diff -u --recursive --new-file v2.3.99-pre5/linux/CREDITS linux/CREDITS --- v2.3.99-pre5/linux/CREDITS Tue Apr 11 15:09:10 2000 +++ linux/CREDITS Mon Apr 24 13:39:33 2000 @@ -268,10 +268,10 @@ D: Original author of the Linux networking code N: Anton Blanchard -E: anton@progsoc.uts.edu.au -W: http://www.progsoc.uts.edu.au/~anton/ +E: anton@linuxcare.com +W: http://linuxcare.com.au/anton/ P: 1024/8462A731 4C 55 86 34 44 59 A7 99 2B 97 88 4A 88 9A 0D 97 -D: sun4 port +D: sun4 port, Sparc hacker S: 47 Robert Street S: Marrickville NSW 2204 S: Australia @@ -941,17 +941,13 @@ D: Selection mechanism N: Andre Hedrick +E: andre@linux-ide.org E: andre@suse.com D: Random SMP kernel hacker... D: Uniform Multi-Platform E-IDE driver -D: AEC6210UF Ultra33 -D: Aladdin 1533/1543(C) chipset -D: Active-Chipset maddness.......... -D: HighPoint HPT343/5 Ultra/33 & HPT366 Ultra/66 chipsets -D: Intel PIIX chipset -D: Promise PDC20246/20247 & PDC20262 chipsets -D: SiS5513 Ultra/66/33 chipsets -D: VIA 82C586/596/686 chipsets +D: Active-ATA-Chipset maddness.......... +D: Ultra DMA 66/33 +D: ATA-Smart Kernel Daemon S: 580 Second Street, Suite 2 S: Oakland, CA S: USA @@ -1148,6 +1144,7 @@ D: 4.4BSD and NeXTstep filesystem support in the old ufs. D: Openstep filesystem and NeXTstep CDROM support in the new ufs. D: Replace CPU==[3-6]86 and __i386__ submodel flags by configuration options. +D: Replace __SMP__ by CONFIG_SMP. D: Danish HOWTO, Linux+FreeBSD mini-HOWTO. S: Dr. Holsts Vej 34, lejl. 164 S: DK-8230 Åbyhøj @@ -1173,6 +1170,7 @@ W: http://linux.powertweak.com D: Moved PCI bridge tuning to userspace (Powertweak). D: Centaur/IDT Winchip/Winchip 2 tweaks. +D: AFFS fixes for 2.3.x D: Misc clean ups and other random hacking. S: 28, Laura Street, S: Treforest, Pontypridd, @@ -1791,6 +1789,13 @@ S: Derbyshire DE4 3RL S: United Kingdom +N: Ian S. Nelson +E: ian.nelson@echostar.com +D: Minor mmap and ide hacks +S: 1370 Atlantis Ave. +S: Lafayette CO, 80026 +S: USA + N: Russell Nelson E: nelson@crynwr.com W: http://www.crynwr.com/~nelson @@ -2262,6 +2267,10 @@ S: Richardson, Texas S: USA +N: Christopher Smith +E: x@xman.org +D: Tulip net driver hacker + N: Miquel van Smoorenburg E: miquels@cistron.nl D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff. @@ -2293,6 +2302,13 @@ S: Warburgring 67 S: 66424 Homburg S: Germany + +N: Andrew Stanley-Jones +E: asj@lanmedia.com +D: LanMedia Corp. Device WAN card device driver +S: #102, 686 W. Maude Ave +S: Sunyvale, CA 94086 +S: USA N: Henrik Storner E: storner@image.dk diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/Changes linux/Documentation/Changes --- v2.3.99-pre5/linux/Documentation/Changes Mon Mar 27 08:08:20 2000 +++ linux/Documentation/Changes Thu Apr 13 22:45:43 2000 @@ -62,7 +62,7 @@ - Bash 1.14.7 ; bash -version - Ncpfs 2.2.0 ; ncpmount -v - Pcmcia-cs 3.1.2 ; cardmgr -V -- PPP 2.3.11 ; pppd --version +- PPP 2.4.0b1 ; pppd --version - Util-linux 2.9i ; chsh -v - isdn4k-utils v3.1beta7 ; isdnctrl 2>&1|grep version @@ -391,22 +391,33 @@ PPP === - Due to changes in the PPP driver and routing code, those of you + The PPP driver has been restructured to support multilink and +to enable it to operate over diverse kinds of media. Those of you using PPP networking will need to upgrade your pppd to at least -version 2.3.11. See ftp://cs.anu.edu.au/pub/software/ppp/ for newest -versions. +version 2.4.0b1. See ftp://linuxcare.com.au/pub/ppp/ for the latest +version. - You must make sure that the special device file /dev/ppp exists. -It can be made by executing this command as root: + If you are not using devfs, you must make sure that the special +device file /dev/ppp exists. It can be made by executing this command +as root: mknod /dev/ppp c 108 0 If you have built ppp support as modules, you should put the lines -below in your /etc/modules.conf file. I assume you want asynchronous -ppp; replace ppp_async by ppp_synctty if you want synchronous ppp. +below in your /etc/modules.conf file. - alias char-major-108 ppp_generic - alias tty-ldisc-3 ppp_async + alias char-major-108 ppp_generic + alias /dev/ppp ppp_generic + alias tty-ldisc-3 ppp_async + alias tty-ldisc-14 ppp_synctty + alias ppp-compress-21 bsd_comp + alias ppp-compress-24 ppp_deflate + alias ppp-compress-26 ppp_deflate + +If you are using devfsd and you have ppp_generic as a module, put the +following line in your /etc/devfsd.conf: + + LOOKUP ppp MODLOAD iBCS ==== @@ -425,12 +436,6 @@ fuser, which comes with psmisc, reads /proc/*/fd/* to do its job. Upgrade psmisc if 2.2 changes to /proc broke the version you're using. -Tunelp -====== - - A new version of tunelp is available which will allow you to enable -"trustirq" mode, improving printing while using IRQ-driven lp ports. - PCI utils ========= @@ -525,6 +530,17 @@ you need to install the LVM tools. More information can be found at the home page of the LVM project at http://linux.msede.com/lvm/. +Inline Documentation +==================== +Many of the functions available for modules to use are now documented +with specially-formatted comments near their definitions. These +comments can be combined with the SGML templates in the +Documentation/DocBook directory to make DocBook files, which can then +be combined with DocBook stylesheets to make PostScript documents, +HTML pages, PDF files, and so on. In order to convert from DocBook +format to a format of your choice, you'll need to install jade, as +well as some stylesheets. + Where to get the files ********************** @@ -718,8 +734,8 @@ PPP === -The 2.3.11 release: -ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.11.tar.gz +The 2.4.0b1 release: +ftp://linuxcare.com.au/pub/ppp/ppp-2.4.0b1.tar.gz IP Chains ========= @@ -775,12 +791,6 @@ http://linux.powertweak.com/files/powertweak-0.1.2.tgz ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/powertweak/powertweak-0.1.2.tgz -Tunelp -====== - -The 0-2.1.131 release: -ftp://e-mind.com/pub/linux/tunelp/tunelp-0-2.1.131.tar.gz - Xosview ======= @@ -817,6 +827,17 @@ The 0.7 release: ftp://linux.msede.com/lvm/v0.7/lvm_0.7.tar.gz + +Jade +==== + +The 1.2.1 release: +ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz + +DSSSL Stylesheets for the DocBook DTD +===================================== + +http://nwalsh.com/docbook/dsssl/ Other Info diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.99-pre5/linux/Documentation/Configure.help Tue Apr 11 15:09:11 2000 +++ linux/Documentation/Configure.help Mon Apr 24 16:15:01 2000 @@ -18,7 +18,7 @@ # - Polish, by Cezar Cichocki (cezar@cs.net.pl), at # http://www.cs.net.pl/~cezar/Kernel # - German, by SuSE, at http://www.suse.de/~ke/kernel . This patch -# includes infrastructure to support different languages as well. +# also includes infrastructure to support different languages. # # To access a document on the WWW, you need to have a direct Internet # connection and a browser program such as netscape or lynx. If you @@ -187,48 +187,44 @@ High Memory support CONFIG_NOHIGHMEM - If you are compiling a kernel which will never run on a machine - with more than 1 Gigabyte total physical RAM, answer "off" - here (default choice). This will result in the old "3GB/1GB" - virtual/physical memory split. 3GB are mapped so as each processus - sees a 3GB virtual memory space. - The remaining part of the 4GB virtual memory space is used by the - kernel to 'permanently map' as much physical memory as possible. - Certain types of applications perform better if there is more - 'permanently mapped' kernel memory. - Certain types of applications (eg. database servers) perform - better if they have as much virtual memory per process as possible. - Linux can use up to 64 Gigabytes of physical memory on x86 systems. - However 32-bit x86 processors have only 4 Gigabytes of virtual memory - space. - - Any potentially remaining part of physical memory is called - 'high memory' that is all the physical RAM that could not be directly - mapped by the kernel - ie. 3GB if there is 4GB RAM in the system, - 7GB if there is 8GB RAM in the system. + However, the address space of 32-bit x86 processors is only 4 + Gigabytes large. That means that, if you have a large amount of + physical memory, not all of it can be "permanently mapped" by the + kernel. The physical memory that's not permanently mapped is called + "high memory". + + If you are compiling a kernel which will never run on a machine with + more than 1 Gigabyte total physical RAM, answer "off" here (default + choice and suitable for most users). This will result in a "3GB/1GB" + split: 3GB are mapped so that each process sees a 3GB virtual memory + space and the remaining part of the 4GB virtual memory space is used + by the kernel to permanently map as much physical memory as + possible. - If 4 Gigabytes physical RAM or less is used then answer "4GB" here. + If the machine has between 1 and 4 Gigabytes physical RAM, then + answer "4GB" here. If more than 4 Gigabytes is used then answer "64GB" here. This selection turns Intel PAE (Physical Address Extension) mode on. PAE implements 3-level paging on IA32 processors. PAE is fully supported by Linux, PAE mode is implemented on all recent Intel - processors (PPro and better). NOTE: The "64GB" kernel will not - boot CPUs that not support PAE! + processors (Pentium Pro and better). NOTE: If you say "64GB" here, + then the kernel will not boot on CPUs that don't support PAE! The actual amount of total physical memory will either be - autodetected or can be forced by using a kernel command line option + auto detected or can be forced by using a kernel command line option such as "mem=256M". (Try "man bootparam" or see the documentation of your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time. The lilo procedure is also explained in the - SCSI-HOWTO, available from http://www.linuxdoc.org/docs.html#howto .) + kernel at boot time.) + + If unsure, say "off". Normal PC floppy disk support CONFIG_BLK_DEV_FD If you want to use the floppy disk drive(s) of your PC under Linux, say Y. Information about this driver, especially important for IBM - Thinkpad users, is contained in drivers/block/README.fd. This file + Thinkpad users, is contained in Documentation/floppy.txt. That file also contains the location of the Floppy driver FAQ as well as location of the fdutils package used to configure additional parameters of the driver at run time. @@ -276,7 +272,9 @@ Saying Y here will allow you to use a regular file as a block device; you can then create a file system on that block device and mount it just as you would mount other block devices such as hard - drive partitions, CDROM drives or floppy drives. + drive partitions, CDROM drives or floppy drives. The loop devices + are block special device files with major number 7 and typically + called /dev/loop0, /dev/loop1 etc. This is useful if you want to check an ISO 9660 file system before burning the CD, or if you want to use floppy images without first @@ -291,17 +289,18 @@ bits of, say, a sound file). This is also safe if the file resides on a remote file server. If you want to do this, you will first have to acquire and install a kernel patch from - ftp://ftp.replay.com/pub/crypto/linux/all or - ftp://verden.pvv.org/pub/linux/kerneli/v2.1/ , and then you need to + ftp://ftp.kerneli.org/pub/kerneli/ , and then you need to say Y to this option. Note that alternative ways to use encrypted file systems are provided by the cfs package, which can be gotten from - ftp://ftp.replay.com/pub/crypto/disk/ , and the newer tcfs package, - available at http://tcfs.dia.unisa.it/ . You do not need to say Y - here if you want to use one of these. However, using cfs requires - saying Y to "NFS file system support" below while using tcfs - requires applying a kernel patch. + ftp://ftp.kerneli.org/pub/kerneli/net-source/ , and the newer tcfs + package, available at http://tcfs.dia.unisa.it/ . You do not need to + say Y here if you want to use one of these. However, using cfs + requires saying Y to "NFS file system support" below while using + tcfs requires applying a kernel patch. An alternative steganography + solution is provided by StegFS, also available from + ftp://ftp.kerneli.org/pub/kerneli/net-source/ . To use the loop device, you need the losetup utility and a recent version of the mount program, both contained in the util-linux @@ -533,8 +532,11 @@ drives, similar to the SCSI protocol. The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by - this driver. (ATAPI PD-CD/CDR drives are not supported by this - driver; support for PD-CD/CDR drives is available if you answer Y to + this driver. For information about jumper settings and the question + of when a ZIP drive uses a partition table, see + http://www.win.tue.nl/~aeb/linux/zip/zip-1.html . + (ATAPI PD-CD/CDR drives are not supported by this driver; support + for PD-CD/CDR drives is available if you answer Y to "SCSI emulation support", below). If you say Y here, the FLOPPY drive will be identified along with @@ -715,21 +717,25 @@ Please read the comments at the top of drivers/scsi/3w-xxxx.c -AEC6210 chipset support -CONFIG_BLK_DEV_AEC6210 +AEC62XX chipset support +CONFIG_BLK_DEV_AEC62XX This driver adds up to 4 more EIDE devices sharing a single interrupt. This add-on card is a bootable PCI UDMA controller. In order to get this card to initialize correctly in some cases, you should say Y here, and preferably also to "Use DMA by default when available". - Please read the comments at the top of drivers/ide/aec6210.c If - you say Y here, then say Y to "Use DMA by default when available" as + The ATP850U/UF is an UltraDMA 33 chipset base. + The ATP860 is an UltraDMA 66 chipset base. + The ATP860M(acintosh) version is an UltraDMA 66 chipset base. + + Please read the comments at the top of drivers/ide/aec62xx.c + If you say Y here, then say Y to "Use DMA by default when available" as well. -AEC6210 Tuning support (WIP) -CONFIG_AEC6210_TUNING - Please read the comments at the top of drivers/ide/aec6210.c +AEC62XX Tuning support (WIP) +CONFIG_AEC62XX_TUNING + Please read the comments at the top of drivers/ide/aec62xx.c If unsure, say N. ALI M15x3 chipset support @@ -969,6 +975,12 @@ If unsure, say N. +VIA82CXXX Tuning support (WIP) +CONFIG_VIA82CXXX_TUNING + Please read the comments at the top of drivers/ide/via82cxxx.c + + If unsure, say N. + Other IDE chipset support CONFIG_IDE_CHIPSETS Say Y here if you want to include enhanced support for various IDE @@ -1417,7 +1429,7 @@ devices named /dev/VolumeGroupName/LogicalVolumeName. For details see Documentation/LVM-HOWTO. You will need supporting - user space software from http://linux.msede.com/lvm . + user space software; location is in Documentation/Changes. If you want to compile this support as a module ( = code which can be inserted in and removed from the running kernel whenever you @@ -1437,12 +1449,12 @@ CONFIG_BLK_DEV_MD This driver lets you combine several hard disk partitions into one logical block device. This can be used to simply append one - partition to another one or to combine several redundant - hard disks to a RAID1/4/5 device so as to provide protection against - hard disk failures. This is called "Software RAID" since the - combining of the partitions is done by the kernel. "Hardware RAID" - means that the combining is done by a dedicated controller; if you - have such a controller, you do not need to say Y here. + partition to another one or to combine several redundant hard disks + into a RAID1/4/5 device so as to provide protection against hard + disk failures. This is called "Software RAID" since the combining of + the partitions is done by the kernel. "Hardware RAID" means that the + combining is done by a dedicated controller; if you have such a + controller, you do not need to say Y here. More information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from @@ -1510,7 +1522,7 @@ RAID-4/RAID-5 mode CONFIG_MD_RAID5 A RAID-5 set of N drives with a capacity of C MB per drive provides - the capacity of C * (N - 1) drives, and protects against a failure + the capacity of C * (N - 1) MB, and protects against a failure of a single drive. For a given sector (row) number, (N - 1) drives contain data sectors, and one drive contains the parity protection. For a RAID-4 set, the parity blocks are present on a single drive, @@ -1619,6 +1631,56 @@ 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM systems. +PCMCIA SCSI adapter support +CONFIG_SCSI_PCMCIA + Say Y here if you intend to attach a PCMCIA or CardBus card to your + computer which acts as a SCSI host adapter. These are credit card + size devices often used with laptops. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions PCMCIA SCSI host adapters. + +Adaptec AHA152X PCMCIA support +CONFIG_PCMCIA_AHA152X + Say Y here if you intend to attach this type of PCMCIA SCSI host + adapter to your computer. + + This driver is also available as a module called aha152x_cs.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Qlogic PCMCIA support +CONFIG_PCMCIA_QLOGIC + Say Y here if you intend to attach this type of PCMCIA SCSI host + adapter to your computer. + + This driver is also available as a module called qlogic_cs.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Future Domain PCMCIA support +CONFIG_PCMCIA_FDOMAIN + Say Y here if you intend to attach this type of PCMCIA SCSI host + adapter to your computer. + + This driver is also available as a module called fdomain_cs.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Adaptec APA1480 CardBus support +CONFIG_PCMCIA_APA1480 + Say Y here if you intend to attach this type of CardBus SCSI host + adapter to your computer. + + This driver is also available as a module called apa1480_cb.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + CPU type CONFIG_CPU_R3000 Please make sure to pick the right CPU type. Linux/MIPS is not @@ -1709,8 +1771,8 @@ Various modules exist for netfilter which replace the previous masquerading (ipmasqadm), packet filtering (ipchains), transparent - proxying, and portforwarding mechanisms. More information is - available from http://netfilter.kernelnotes.org . + proxying, and portforwarding mechanisms. Please see + Documentation/Changes for the location of these packages. Make sure to say N to "Fast switching" below if you intend to say Y here, as Fast switching currently bypasses netfilter. @@ -1746,10 +1808,10 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `Y'. -IP: userspace queueing via NETLINK (EXPERIMENTAL) +IP: user space queueing via NETLINK (EXPERIMENTAL) CONFIG_IP_NF_QUEUE - Netfilter has the ability to queue packets to userspace: the netlink - device can be used to access them using this driver. + Netfilter has the ability to queue packets to user space: the + netlink device can be used to access them using this driver. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. @@ -3808,12 +3870,17 @@ Kernel httpd acceleration (EXPERIMENTAL) CONFIG_KHTTPD - The kernel httpd acceleration daemon (kHTTPd) is a (limited) - web server built into the kernel. It is limited since it can only - serve files from the file system. Saying "M" here builds the - kHTTPd module; this is NOT enough to have a working kHTTPd. - For safety reasons, the module has to be activated by doing a - "echo 1 > /proc/sys/net/khttpd/start" after inserting the module. + The kernel httpd acceleration daemon (kHTTPd) is a (limited) web + server built into the kernel. It is limited since it can only serve + files from the file system and cannot deal with executable content + such as CGI scripts. Serving files is sped up if you use kHTTPd. + If kHTTPd is not able to fulfill a request, it can transparently + pass it through to a user space web server such as apache. + + Saying "M" here builds the kHTTPd module; this is NOT enough to have + a working kHTTPd. For safety reasons, the module has to be activated + by doing a "echo 1 > /proc/sys/net/khttpd/start" after inserting the + module. Before using this, read the README in net/khttpd ! @@ -4841,12 +4908,16 @@ say N here. FORE Systems 200E-series -CONFIG_ATM_FORE200E +CONFIG_ATM_FORE200E_MAYBE This is a driver for the FORE Systems 200E-series ATM adapter cards. It simultaneously supports PCA-200E and SBA-200E models on PCI and SBUS hosts. Say Y (or M to compile as a module named fore_200e.o) here if you have one of these ATM adapters. + Note that the driver will actually be compiled only if you + additionally enable the support for PCA-200E and/or SBA-200E + cards. + See the file Documentation/networking/fore200e.txt for further details. @@ -5026,15 +5097,17 @@ about anything having "SCSI" in its name other than hard disks, CDROMs or tapes, say Y here. These won't be supported by the kernel directly, so you need some additional software which knows how to - talk to these devices using the SCSI protocol. For scanners, look at - SANE (www.mostang.com/sane). For CD writer software look at cdrecord - (www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private - /cdrecord.html) and for burning a "disk at once": cdrdao - (www.ping.de/sites/daneb/cdrdao.html). Cdparanoia is a high quality - digital reader of audio CDs (www.xiph.org/paranoia). - For other devices, it's possible that you'll have to write the driver - software yourself. Please read the file Documentation/scsi-generic.txt - for more information. + talk to these devices using the SCSI protocol: + + For scanners, look at SANE (http://www.mostang.com/sane). For CD + writer software look at cdrecord + (http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html) + and for burning a "disk at once": cdrdao + (http://www.ping.de/sites/daneb/cdrdao.html). Cdparanoia is a high + quality digital reader of audio CDs (http://www.xiph.org/paranoia). + For other devices, it's possible that you'll have to write the + driver software yourself. Please read the file + Documentation/scsi-generic.txt for more information. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -5858,6 +5931,15 @@ The module will be called qlogicfc.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Qlogic QLA 1280 SCSI support +CONFIG_SCSI_QLOGIC_1280 + Say Y if you have a QLogic ISP1x80/1x160 SCSI host adapter. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called qla1280.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + Seagate ST-02 and Future Domain TMC-8xx SCSI support CONFIG_SCSI_SEAGATE These are 8-bit SCSI controllers; the ST-01 is also supported by @@ -6541,6 +6623,17 @@ Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +PPP multilink support (EXPERIMENTAL) +CONFIG_PPP_MULTILINK + PPP multilink is a protocol (defined in RFC 1990) which allows you + to combine several (logical or physical) lines into one logical PPP + connection, so that you can utilize your full bandwidth. + + This has to be supported at the other end as well and you need a + version of the pppd daemon which understands the multilink protocol. + + If unsure, say N. + PPP support for async serial ports CONFIG_PPP_ASYNC Say Y (or M) here if you want to be able to use PPP over standard @@ -6552,6 +6645,8 @@ into and removed from the running kernel). If you want to compile it as a module, say M here and read Documentation/modules.txt. + If unsure, say Y. + PPP support for sync tty ports CONFIG_PPP_SYNC_TTY Say Y (or M) here if you want to be able to use PPP over synchronous @@ -6902,15 +6997,16 @@ as a module, say M here and read Documentation/modules.txt. If unsure, say N. -3Com 3c575 CardBus support -CONFIG_PCMCIA_3C575 - This driver supports the 3Com 3c575 series of CardBus Fast Ethernet - adapters. +IBM PCMCIA Token Ring adapter support +CONFIG_PCMCIA_IBMTR + Say Y here if you intend to attach this type of Token Ring PCMCIA + card to your computer. You then also need to say Y to "Token Ring + driver support". - This driver can only be compiled as a module ( = code which can be + This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will be called 3c575_cb.o. If you want to do that, say M - here and read Documentation/modules.txt. If unsure, say N. + The module will be called ibmtr_cs.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. Xircom Tulip-like CardBus support CONFIG_PCMCIA_XIRTULIP @@ -7216,7 +7312,7 @@ Differentiated Services (diffserv) and Resource Reservation Protocol (RSVP) on your Linux router if you also say Y to "QoS support", "Packet classifier API" and to some classifiers below. Documentation - and software is at http://icawwww1.ipfl.ch/linux/diffserv/ . + and software is at http://icawww1.epfl.ch/linux-diffserv/ . If you say Y here and to "/proc file system" below, you will be able to read status information about packet schedulers from the file @@ -7346,7 +7442,7 @@ Differentiated Services (diffserv) and Resource Reservation Protocol (RSVP) on your Linux router if you also say Y to "Packet classifier API" and to some classifiers below. Documentation and software is at - http://icawwww1.ipfl.ch/linux/diffserv/ . + http://icawww1.epfl.ch/linux-diffserv/ . Note that the answer to this question won't directly affect the kernel: saying N will just cause this configure script to skip all @@ -7369,7 +7465,7 @@ This will enable you to use Differentiated Services (diffserv) and Resource Reservation Protocol (RSVP) on your Linux router. Documentation and software is at - http://icawwww1.ipfl.ch/linux/diffserv/ . + http://icawww1.epfl.ch/linux-diffserv/ . ### Add #tristate ' TC index classifier' CONFIG_NET_CLS_TCINDEX @@ -7492,6 +7588,31 @@ The module will be called cosa.o. For general information about modules read Documentation/modules.txt. +Lan Media sync serial boards support +CONFIG_LANMEDIA + This is a driver for the following Lan Media family of serial boards. + + LMC 1000 board allows you to connect synchronous serial devices (for + example base-band modems, or any other device with the X.21, V.24, + V.35 or V.36 interface) to your Linux box. + + LMC 1200 with on board DSU board allows you to connect your Linux + box dirrectly to a T1 or E1 circuit. + + LMC 5200 board provides a HSSI interface capable of runnig up to + 52 mbits per second. + + LMC 5245 board connects directly to a T3 circuit saving the + additional external hardware. + + To change setting such as syncPPP vs cisco HDLC or clock source you + will need lmcctl. It it available at ftp.lanmedia.com. + + This code is also available as a module called lmc.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + Fibre Channel driver support CONFIG_NET_FC Fibre Channel is a high speed serial protocol mainly used to connect @@ -8163,12 +8284,19 @@ Documentation/networking/net-modules.txt. The module will be called 3c515.o. -3c590 series (592/595/597) "Vortex" support +3c59x/3c90x/3c575_Cardbus series "Vortex/Boomerang/Cyclone" support CONFIG_VORTEX - If you have a 3Com "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) - or "Boomerang" series (EtherLink XL 3c900 or 3c905) network - (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . More specific + This option enables driver support for a large number of 10mbps and + 10/100mbps EISA, PCI and PCMCIA 3Com network cards: + + "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI + "Boomerang" (EtherLink XL 3c900 or 3c905) PCI + "Cyclone" (3c540/3c900/3c905/3c980/3c575/3c656) PCI and Cardbus + "Tornado" (3c905) PCI + "Hurricane" (3c555/3cSOHO) PCI + + If you have such a card, say Y and read the Ethernet-HOWTO, available + from http://www.linuxdoc.org/docs.html#howto . More specific information is in Documentation/networking/vortex.txt and in the comments at the beginning of drivers/net/3c59x.c. @@ -9357,11 +9485,13 @@ modems, and printers support the USB protocol and can be connected to the PC via those ports. - Say Y here if your computer has a USB port and you want to - use USB devices. You then need to say Y to at least one - of "UHCI support" or "OHCI support" below (the type of interface - that the USB hardware in your computer provides) and then choose - from among the drivers for USB peripherals. + Say Y here if your computer has a USB port and you want to use USB + devices. You then need to say Y to at least one of "UHCI support" or + "OHCI support" below (the type of interface that the USB hardware in + your computer provides to the operating system) and then choose from + among the drivers for USB peripherals. You may want to check out the + information provided in Documentation/usb/ and especially the links + given in Documentation/usb/usb-help.txt. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9370,8 +9500,8 @@ USB verbose debug messages CONFIG_USB_DEBUG - Say Y here if you want the USB core drivers to produce a bunch of - debug messages to the system log. Select this if you are having a + Say Y here if you want the USB core & hub drivers to produce a bunch + of debug messages to the system log. Select this if you are having a problem with USB support and want to see more of what is going on. UHCI (intel PIIX4, VIA, ...) support? @@ -9379,56 +9509,54 @@ The Universal Host Controller Interface is a standard by Intel for accessing the USB hardware in the PC (which is also called the USB host controller). If your USB host controller conforms to this - standard, say Y. All recent boards with Intel PCI chipsets (like - intel 430TX, 440FX, 440LX, 440BX, i810, i820) conform to this standard. - Also all VIA PCI chipsets (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo - Pro II or Apollo Pro 133). - If unsure, say Y. + standard, you may want to say Y, but see below. All recent boards + with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX, + i810, i820) conform to this standard. Also all VIA PCI chipsets + (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro + 133). + + Currently there exist two drivers for UHCI host controllers: this + one and the so-called JE driver, which you can get from + "UHCI alternate (JE) support", below. You need only one. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called usb-uhci.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. - -USB-UHCI High Bandwidth support -CONFIG_USB_UHCI_HIGH_BANDWIDTH - This option enables the so-called reclamation loop in usb-uhci, thus - allowing much higher transfer bandwidth for USB-bulk and control - messages; isochronous transfers (audio, video etc.) are not affected. - Due to a very simple design of the UHCI controller, this may cause - a significant PCI congestion under certain conditions. If you are - experiencing a system slowdown, disable this option. - - If unsure, say N. - + UHCI (intel PIIX4, VIA, ...) alternate (JE) support? CONFIG_USB_UHCI_ALT - This is an alternate driver for UHCI support. It has been commonly - been referred to as the "JE driver". - The Universal Host Controller Interface is a standard by Intel for accessing the USB hardware in the PC (which is also called the USB host controller). If your USB host controller conforms to this - standard, say Y. All recent boards with Intel PCI chipsets (like - intel 430TX, 440FX, 440LX, 440BX, i810, i820) conform to this standard. - Also all VIA PCI chipsets (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo - Pro II or Apollo Pro 133). - If unsure, say Y. + standard, you may want to say Y, but see below. All recent boards + with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX, + i810, i820) conform to this standard. Also all VIA PCI chipsets + (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro + 133). If unsure, say Y. + + Currently there exist two drivers for UHCI host controllers: this + so-called JE driver, and the one you get from "UHCI support", above. + You need only one. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called uhci.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. - -OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support? + +UHCI unlink optimizations (EXPERIMENTAL) +CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE + This option currently does nothing. You may say Y or N. + +OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support CONFIG_USB_OHCI The Open Host Controller Interface is a standard by Compaq/Microsoft/National for accessing the USB PC hardware (also - called USB host controller). If your USB host controller conforms - to this standard, say Y. The USB host controllers on most - non-Intel architectures and on several x86 compatibles with non-Intel - chipsets - like SiS (actual 610, 610 and so on) or ALi (ALi IV, ALi V, - Aladdin Pro..) - conform to this standard. + called USB host controller). If your USB host controller conforms to + this standard, say Y. The USB host controllers on most non-Intel + architectures and on several x86 compatibles with non-Intel chipsets + -- like SiS (aktual 610, 610 and so on) or ALi (ALi IV, ALi V, + Aladdin Pro..) -- conform to this standard. You may want to read the file Documentation/usb/ohci.txt. @@ -9439,9 +9567,17 @@ USB Human Interface Device (HID) support CONFIG_USB_HID - Say Y here if you want to connect a keyboard, mouse, joystick, - graphic tablet, UPS or any other HID based devices to your computer - via USB. + Say Y here if you want to connect keyboards, mice, joysticks, + graphic tablets, UPS's or any other HID based devices to your + computer via USB. More information is available: + Documentation/usb/input.txt. + + If unsure, say Y. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called hid.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. USB HIDBP Keyboard support CONFIG_USB_KBD @@ -9515,17 +9651,6 @@ The module will be called mousedev.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -Mix all mice into one device -CONFIG_INPUT_MOUSEDEV_MIX - Say Y here if you want input from all your USB HID mice to be mixed - into one misc device. If you say N, you'll have a separate - device for each USB mouse. - -Support for digitizers -CONFIG_INPUT_MOUSEDEV_DIGITIZER - Say Y here if you have a digitizer that doesn't emulate a mouse - itself, and want to use it as a mouse. - Horizontal screen resolution CONFIG_INPUT_MOUSEDEV_SCREEN_X For the mouse emulation to be correct, the mousedev driver needs to @@ -9578,6 +9703,7 @@ CONFIG_USB_ACM This driver supports USB modems and ISDN adapters which support the Communication Device Class Abstract Control Model interface. + Please read Documentation/usb/acm.txt for details. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9623,26 +9749,35 @@ USB FTDI Single Port Serial Driver CONFIG_USB_SERIAL_FTDI_SIO Say Y here if you want to use a FTDI SIO single port USB to serial - converter device. The implementation I have is called the USC-1000 + converter device. The implementation I have is called the USC-1000. - See http://reality.sgi.com/bryder_wellington/ftdi_sio for more information - on this driver and the device + See http://reality.sgi.com/bryder_wellington/ftdi_sio for more + information on this driver and the device. -USB FTDI Single Port Serial Driver +USB Keyspan PDA Single Port Serial Driver CONFIG_USB_SERIAL_KEYSPAN_PDA - Say Y here if you want to use a Keyspan PDA single port USB to serial - converter device. + Say Y here if you want to use a Keyspan PDA single port USB to + serial converter device. + +USB ZyXEL omni.net LCD Plus Driver +CONFIG_USB_SERIAL_OMNINET + Say Y here if you want to use a ZyXEL omni.net LCD ISDN TA. USB Printer support CONFIG_USB_PRINTER - Say Y here if you want to connect a USB printer to your computer's USB - port. + Say Y here if you want to connect a USB printer to your computer's + USB port. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called printer.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +USB Serial Converter verbose debug +CONFIG_USB_SERIAL_DEBUG + Say Y here if you want verbose debug messages from the USB Serial + Converter. + USB IBM (Xirlink) C-It Camera support CONFIG_USB_IBMCAM Say Y here if you want to connect a IBM "C-It" camera, also known as @@ -9710,13 +9845,12 @@ The module will be called dc2xx.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. - USB Mustek MDC800 Digital Camera Support CONFIG_USB_MDC800 Say Y here if you want to connect this type of still camera to your computer's USB port. This driver can be used with gphoto 0.4.3 - and higher (look at www.gphoto.org). - To use it create a devicenode with mknod /dev/mustek c 180 32 and + and higher (look at http://www.gphoto.org ). + To use it create a device node with "mknod /dev/mustek c 10 171" and configure it in your software. This code is also available as a module ( = code which can be @@ -9771,13 +9905,13 @@ CONFIG_USB_DEVICEFS If you say Y here (and to "/proc file system support" below), you will get a file /proc/usb/devices which lists the devices currently - connected to your USB busses, a file /proc/usb/drivers file which - lists the USB kernel client drivers currently loaded, and for every + connected to your USB busses, a file /proc/usb/drivers which lists + the USB kernel client drivers currently loaded, and for every connected device a file named "/proc/usb/xxx/yyy", where xxx is the bus number and yyy the device number; the latter files can be used - by userspace drivers to talk to the device. These files are - "virtual", meaning they are generated on the fly and not stored on - the hard drive. + by user space programs to talk directly to the device. These files + are "virtual", meaning they are generated on the fly and not stored + on the hard drive. For the format of the /proc/usb/ files, please read Documentation/usb/proc_usb_info.txt. @@ -9939,8 +10073,33 @@ If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be - called cramfs.o. + called cramfs.o. Note that the root file system (the one containing + the directory /) cannot be compiled as a module. + + If unsure, say N. +Simple RAM-based file system support +CONFIG_RAMFS + Ramfs is a file system which keeps all files in RAM. It allows + read and write access. + + In contrast to RAM disks, which get allocated a fixed amount of RAM, + ramfs grows and shrinks to accommodate the files it contains. + + Before you can use this RAM-based file system, it has to be mounted, + meaning it has to be given a location in the directory hierarchy. If + you want to use the location /ramfiles for example, you would have + to create that directory first and then mount the file system by + saying "mount -t ramfs ramfs /ramfiles" or the equivalent line in + /etc/fstab. Everything is "virtual" in the sense that no files will + be created on your hard drive; if you reboot, everything in + /ramfiles will be lost. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ramfs.o. + ISO 9660 CDROM file system support CONFIG_ISO9660_FS This is the standard file system used on CDROMs. It was previously @@ -10124,12 +10283,17 @@ (there is a small number of Interrupt ReQuest lines in your computer that are used by the attached devices to gain the CPU's attention -- often a source of trouble if two devices are mistakenly configured - to use the same IRQ). + to use the same IRQ). The program procinfo to display some + information about your system gathered from the /proc file system. + + Before you can use the /proc file system, it has to be mounted, + meaning it has to be given a location in the directory hierarchy. + That location should be /proc. A command such as "mount -t proc proc + /proc" or the equivalent line in /etc/fstab does the job. The /proc file system is explained in the file Documentation/filesystems/proc.txt and on the proc(5) manpage ("man - 5 proc"). You can also use the program procinfo to display some - information about your system gathered from the /proc file system. + 5 proc"). This option will enlarge your kernel by about 67 KB. Several programs depend on this, so everyone should say Y here. @@ -10142,9 +10306,9 @@ allocations. Device drivers register entries in /dev which then appear automatically, which means that the system administrator does not have to create character and block special device files in the - /dev directory using the mknod command anymore. + /dev directory using the mknod command (or MAKEDEV script) anymore. - This is work in progress. If you want to use this you *must* read + This is work in progress. If you want to use this, you *must* read the material in Documentation/filesystems/devfs/, especially the file README there. @@ -10193,6 +10357,13 @@ If you don't know what all this is about, say N. +Provide NFSv3 client support (EXPERIMENTAL) +CONFIG_NFS_V3 + Say Y here if you want your NFS client to be able to speak the newer + version 3 of the NFS protocol. + + If unsure, say N. + Root file system on NFS CONFIG_ROOT_NFS If you want your Linux box to mount its whole root file system (the @@ -10219,6 +10390,10 @@ locations are given in the file Documentation/Changes in the NFS section. + If you say Y here, you will get support for version 2 of the NFS + protocol (NFSv2). If you also want NFSv3, say Y to the next question + as well. + Please read the NFS-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . @@ -10265,7 +10440,7 @@ If you say Y here, you will (maybe) be able to write to NTFS file systems as well as read from them. The read-write support in NTFS is far from being complete and is not well tested. If you - enable this, back up your NTFS volume first since it may get + say Y here, back up your NTFS volume first since it may get damaged. Also, make sure to run chkdsk from within Microsoft Windows NT after having performed any writes to a NTFS partition from Linux to detect any problems as early as possible. @@ -10361,7 +10536,8 @@ which can be inserted in and removed from the running kernel whenever you want). The module is called romfs.o. If you want to compile it as a module, say M here and read - Documentation/modules.txt. + Documentation/modules.txt. Note that the file system of your root + partition (the one containing the directory /) cannot be a module. If you don't know whether you need it, then you don't need it: answer N. @@ -10393,9 +10569,9 @@ overhead in the already-mounted case; this is unlike the BSD automounter (amd), which is a pure user space daemon. - To use the automounter you need the user-space tools from - ftp://ftp.kernel.org/pub/linux/daemons/autofs ; you also want to - answer Y to "NFS file system support", below. + To use the automounter you need the user-space tools from the autofs + package; you can find the location in Documentation/Changes. You + also want to answer Y to "NFS file system support", below. If you want to use the newer version of the automounter with more features, say N here and say Y to "Kernel automounter v4 support", @@ -10585,7 +10761,8 @@ The GNU C library glibc 2.1 contains the requisite support for this mode of operation; you also need client programs that use the Unix98 - API. + API. Please read Documentation/Changes for more information about + the Unix98 pty devices. Note that the experimental "/dev file system support" (CONFIG_DEVFS_FS) is a more general facility. @@ -12336,14 +12513,30 @@ CONFIG_WDT If you have a WDT500P or WDT501P watchdog board, say Y here, otherwise N. It is not possible to probe for this board, which means - that you have to set the IO port and IRQ it uses in the kernel - source at the top of drivers/char/wdt.c. + that you have to inform the kernel about the IO port and IRQ using + the "wdt=" kernel option (try "man bootparam" or see the + documentation of your boot loader (lilo or loadlin) about how to + pass options to the kernel at boot time). If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called wdt.o. +WDT PCI Watchdog timer +CONFIG_WDTPCI + If you have a PCI WDT500/501 watchdog board, say Y here, + otherwise N. It is not possible to probe for this board, which means + that you have to inform the kernel about the IO port and IRQ using + the "wdt=" kernel option (try "man bootparam" or see the + documentation of your boot loader (lilo or loadlin) about how to + pass options to the kernel at boot time). + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called wdt_pci.o. + WDT501 features CONFIG_WDT_501 Saying Y here and creating a character special file /dev/temperature @@ -12836,9 +13029,9 @@ ProAudioSpectrum 16 support CONFIG_SOUND_PAS Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio - 16 or Logitech SoundMan 16 sound card. Don't answer Y if you have - some other card made by Media Vision or Logitech since they are not - PAS16 compatible. + 16 or Logitech SoundMan 16 sound card. Answer N if you have some + other card made by Media Vision or Logitech since those are not + PAS16 compatible. Please read Documentation/sound/PAS16. If you compile the driver into the kernel, you have to add "pas2=,,,,,,, @@ -12854,12 +13047,12 @@ Please read the file Documentation/sound/Soundblaster. You should also say Y here for cards based on the Avance Logic - ALS-007 chip (read Documentation/sound/ALS) and for cards based - on ESS chips (read Documentation/sound/ESS1868 and + ALS-007 and ALS-1X0 chips (read Documentation/sound/ALS) and for cards + based on ESS chips (read Documentation/sound/ESS1868 and Documentation/sound/ESS). If you have an SB AWE 32 or SB AWE 64, say - Y here and also to "Additional lowlevel drivers" and to "SB32/AWE - support" below and read Documentation/sound/INSTALL.awe. If you have - an IBM Mwave card, say Y here and read Documentation/sound/mwave. + Y here and also to "AWE32 synth" below and read + Documentation/sound/INSTALL.awe. If you have an IBM Mwave card, say + Y here and read Documentation/sound/mwave. If you compile the driver into the kernel and don't want to use isapnp, you have to add "sb=,,," to the kernel @@ -13248,6 +13441,11 @@ driver as a module you have to specify the MPU I/O base address with the parameter 'mpu_base=0xNNN'. +Creative EMU10K1 based PCI sound cards +CONFIG_SOUND_EMU10K1 + Say Y or M if you have a PCI sound card using the EMU10K1 + chipset, such as the Creative SBLive! or SB PCI512. + Ensoniq ES1370 based PCI sound cards CONFIG_SOUND_ES1370 Say Y or M if you have a PCI sound card utilizing the Ensoniq @@ -13494,9 +13692,8 @@ Say Y or N according to the D-channel protocol which your local telephone service company provides. - NOTE: If you say Y here and you have only one ISDN card installed, - you cannot say Y to "HiSax Support for German 1TR6", below. And vice - versa. + The call control protocol E-DSS1 is used in most European countries. + If unsure, say yes. Support for german charge info CONFIG_DE_AOC @@ -13527,9 +13724,9 @@ Say Y or N according to the D-channel protocol which your local telephone service company provides. - NOTE: If you say Y here and you have only one ISDN card installed, - you cannot say Y to "HiSax Support for EURO/DSS1", above. And vice - versa. + 1TR6 is an old call control protocol which was used in Germany + before E-DSS1 was established. Nowadays, all new lines in Germany + use E-DSS1. Teles 16.0/8.0 CONFIG_HISAX_16_0 @@ -14932,6 +15129,35 @@ as a module (c-qcam.o). Read Documentation/video4linux/CQcam.txt for more information. +CPiA Video For Linux +CONFIG_VIDEO_CPIA + This is the video4linux driver for cameras based on Vision's CPiA + (Colour Processor Interface ASIC), such as the Creative Labs Video + Blaster Webcam II. If you have one of these cameras, say Y here + and select parallel port and/or USB lowlevel support below, + otherwise say N. This will not work with the Creative Webcam III. + + Please read Documentation/video4linux/README.cpia for more + information. + + This driver is also available as a module (cpia.o). + +CPiA Parallel Port Lowlevel Support +CONFIG_VIDEO_CPIA_PP + This is the lowlevel parallel port support for cameras based on + Vision's CPiA (Colour Processor Interface ASIC), such as the + Creative Webcam II. If you have the parallel port version of one + of these cameras, say Y here, otherwise say N. It is also available + as a module (cpia_pp.o). + +CPiA USB Lowlevel Support +CONFIG_VIDEO_CPIA_USB + This is the lowlevel USB support for cameras based on Vision's CPiA + (Colour Processor Interface ASIC), such as the Creative Webcam II. + If you have the USB version of one of these cameras, say Y here, + otherwise say N. This will not work with the Creative Webcam III. + It is also available as a module (cpia_usb.o). + Mediavision Pro Movie Studio Video For Linux CONFIG_VIDEO_PMS Say Y if you have such a thing. This driver is also available as a @@ -15410,121 +15636,16 @@ boards from BVM Ltd. Everyone using one of these boards should say Y here. -Support for user-space parallel port device drivers -CONFIG_PPDEV - Saying Y to this adds support for /dev/parport device nodes. This - is needed for programs that want portable access to the parallel - port, for instance deviceid (which displays Plug-and-Play device - IDs). - - This is the parallel port equivalent of SCSI generic support (sg). - It is safe to say N to this -- it is not needed for normal printing - or parallel port CD-ROM/disk support. - - This support is also available as a module. If you want to compile - it as a module, say M here and read Documentation/modules.txt. The - module will be called ppdev.o. - - If unsure, say N. - -Kernel httpd acceleration (EXPERIMENTAL) -CONFIG_KHTTPD - The kernel httpd acceleration daemon (kHTTPd) is a (limited) - web server build into the kernel. It is limited since it can only - serve files from the file system. Saying "M" here builds the - kHTTPd module; this is NOT enough to have a working kHTTPd. - For safety reasons, the module has to be activated by doing a - "echo 1 > /proc/sys/net/khttpd/start" after inserting the module. - - Before using this, read the README in /usr/src/linux/net/khttpd ! - - The kHTTPd is experimental. Be careful when using it on a production - machine. Also note that kHTTPd doesn't support virtual servers yet. - -I2C support -CONFIG_I2C - I2C (pronounce: I-square-C) is a slow bus protocol developed by - Philips. SMBus, or System Management Bus is a sub-protocol of I2C. - - Both I2C and SMBus are supported here. You will need this for - hardware sensors support, and in the future for Video for Linux - support. - - Beside this option, you will also need to select specific drivers - for your bus adapter(s). - -I2C bit-banging interfaces -CONFIG_I2C_ALGOBIT - This allows you to use a range of I2C adapters called bit-banging - adapters. Why they are called so is rather technical and uninteresting; - but you need to select this if you own one of the adapters listed - under it. - -Philips style parallel port adapter -CONFIG_I2C_PHILIPSPAR - This supports parallel-port I2C adapters made by Philips. Unless you - own such an adapter, you do not need to select this. - -ELV adapter -CONFIG_I2C_ELV - This supports parallel-port I2C adapters called ELV. Unless you - own such an adapter, you do not need to select this. - -Velleman K9000 adapter -CONFIG_I2C_VELLEMAN - This supports the Velleman K9000 parallel-port I2C adapter. Unless - you own such an adapter, you do not need to select this. - -I2C PCF 8584 interfaces -CONFIG_I2C_ALGOPCF - This allows you to use a range of I2C adapters called PCF - adapters. Why they are called so is rather technical and uninteresting; - but you need to select this if you own one of the adapters listed - under it. - -Elektor ISA card -CONFIG_I2C_ELEKTOR - This supports the PCF8584 ISA bus I2C adapter. Unless you own such - an adapter, you do not need to select this. - -I2C device interface -CONFIG_I2C_CHARDEV - Here you find the drivers which allow you to use the i2c-* device - files, usually found in the /dev directory on your system. They - make it possible to have user-space programs use the I2C bus. - -CPiA Video For Linux -CONFIG_VIDEO_CPIA - This is the video4linux driver for cameras based on Vision's CPiA - (Colour Processor Interface ASIC), such as the Creative Labs Video - Blaster Webcam II. If you have one of these cameras, say Y here - and select parallel port and/or USB lowlevel support below, - otherwise say N. This will not work with the Creative Webcam III. - It is also available as a module (cpia.o). - -CPiA Parallel Port Lowlevel Support -CONFIG_VIDEO_CPIA_PP - This is the lowlevel parallel port support for cameras based on - Vision's CPiA (Colour Processor Interface ASIC), such as the - Creative Webcam II. If you have the parallel port version of one - of these cameras, say Y here, otherwise say N. It is also available - as a module (cpia_pp.o). - -CPiA USB Lowlevel Support -CONFIG_VIDEO_CPIA_USB - This is the lowlevel USB support for cameras based on Vision's CPiA - (Colour Processor Interface ASIC), such as the Creative Webcam II. - If you have the USB version of one of these cameras, say Y here, - otherwise say N. This will not work with the Creative Webcam III. - It is also available as a module (cpia_usb.o). # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, -# Intel, IRQ, Linux, MSDOS, NetWare, NetWinder, NFS, -# PCI, SCSI, SPARC -# two words: hard drive, hard disk, sound card, home page -# other: it's safe to save; daemon; use --, not - or --- +# Intel, IRQ, ISDN, Linux, MSDOS, NetWare, NetWinder, +# NFS, PCI, SCSI, SPARC +# two words: file system, hard drive, hard disk, home page, +# user space, web site +# other: it's safe to save; daemon; use --, not - or ---; +# use KB for 1024 bytes, not kB or K. # # # This is used by Emacs' spell checker ispell.el: @@ -15655,7 +15776,7 @@ # LocalWords: caldera Preload Preloading slowdowns schoebel uni NBD nbd prog # LocalWords: stuttgart rdist TRANS hostnames mango jukeboxes ESS userland PD # LocalWords: hardlinked NAMETRANS env mtab fstab umount nologin runlevel gid -# LocalWords: filespace adm Nodename hostname uname Kernelname bootp nmi DI OV +# LocalWords: adm Nodename hostname uname Kernelname bootp nmi DI OV StegFS # LocalWords: KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt RX mdafb # LocalWords: dataless kerneltype SYSNAME Comtrol Rocketport palmtop fbset EGS # LocalWords: nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY @@ -15803,7 +15924,7 @@ # LocalWords: Diffserv DSMARK Ingress Qdisc TCINDEX TMSPCI tmspci Ringode JE # LocalWords: MADGEMC madgemc TokenRing SMCTR TokenCard smctr Wacom Graphire # LocalWords: WMFORCE mousedev ConnectTech HandSpring Xirlink IBMCAM ibmcam SN -# LocalWords: DEVICEFS yyy userspace Cymraeg Dwave SIMM JSFLASH JavaStation's +# LocalWords: DEVICEFS yyy Cymraeg Dwave SIMM JSFLASH JavaStation's multilink # LocalWords: nsc ircc DDB Vrc CMN TB PROMs Vino rivafb DDC Matroxes MGA TVO # LocalWords: MAVEN fbdev crtc maven matroxset NTSC PCA SBA AAL SKFP DAS SAS # LocalWords: skfp Intuos ADMtek's pegasus PLUSB plusb pointopoint mp rio Xeon @@ -15828,4 +15949,7 @@ # LocalWords: UltraDMA WDC CRC CONNTRACK IPTABLES iptables nfmark interface's # LocalWords: tdfxfb TNTx HGA hgafb VERBOSEDEBUG SunTrunking SunSoft XIRTULIP # LocalWords: ethercards PNIC Macronix MXIC ASIX xircom Mustek MDC gphoto mdc -# LocalWords: CramFs Cramfs uid cramfs AVM's kernelcapi PCIV +# LocalWords: CramFs Cramfs uid cramfs AVM's kernelcapi PCIV cdrdao Cdparanoia +# LocalWords: DMX Domex dmx wellington ftdi sio Accton Billington Corega FEter +# LocalWords: MELCO LUA PNA Linksys SNC chkdsk AWACS Webcam RAMFS Ramfs ramfs +# LocalWords: ramfiles MAKEDEV pty WDTPCI APA apa diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt --- v2.3.99-pre5/linux/Documentation/DMA-mapping.txt Sun Feb 20 21:12:38 2000 +++ linux/Documentation/DMA-mapping.txt Tue Apr 25 17:52:05 2000 @@ -198,7 +198,7 @@ PCI_DMA_TODEVICE means "from main memory to the PCI device" PCI_DMA_FROMDEVICE means "from the PCI device to main memory" -Cou are _strongly_ encouraged to specify this as precisely +You are _strongly_ encouraged to specify this as precisely as you possibly can. If you absolutely cannot know the direction of the DMA transfer, @@ -284,7 +284,7 @@ To unmap a scatterlist, just call: - pci_unmap_sg(dev, sglist, nents); + pci_unmap_sg(dev, sglist, nents, direction); Again, make sure DMA activity finished. diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.3.99-pre5/linux/Documentation/DocBook/Makefile Tue Apr 11 15:09:11 2000 +++ linux/Documentation/DocBook/Makefile Thu Apr 13 09:25:44 2000 @@ -3,13 +3,22 @@ PS := $(patsubst %.sgml, %.ps, $(BOOKS)) PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) -books: docproc $(BOOKS) +$(BOOKS): $(TOPDIR)/scripts/docproc + +.PHONY: books ps pdf clean mrproper db2ps db2pdf + +books: $(BOOKS) ps: $(PS) pdf: $(PDF) -docproc: +db2ps db2pdf: + @(which $@ > /dev/null 2>&1) || \ + (echo "*** You need to install DocBook stylesheets ***"; \ + exit 1) + +$(TOPDIR)/scripts/docproc: $(MAKE) -C $(TOPDIR)/scripts docproc wanbook.sgml: wanbook.tmpl @@ -64,7 +73,7 @@ mrproper: clean $(RM) $(PS) $(PDF) -%.ps : %.sgml +%.ps : %.sgml db2ps db2ps $< %.pdf : %.sgml diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/arm/Setup linux/Documentation/arm/Setup --- v2.3.99-pre5/linux/Documentation/arm/Setup Fri Oct 22 13:21:43 1999 +++ linux/Documentation/arm/Setup Tue Apr 25 17:38:33 2000 @@ -112,6 +112,14 @@ system 64-bit serial number + mem_fclk_21285 + + The speed of the external oscillator to the 21285 (footbridge), + which control's the speed of the memory bus, timer & serial port. + Depending upon the speed of the cpu its value can be between + 0-66 MHz. If no params are passed or a value of zero is passed, + then a value of 50 Mhz is the default on 21285 architectures. + paths[8][128] These are now obsolete, and should not be used. diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/computone.txt linux/Documentation/computone.txt --- v2.3.99-pre5/linux/Documentation/computone.txt Fri Jan 21 18:19:15 2000 +++ linux/Documentation/computone.txt Tue Apr 25 16:53:13 2000 @@ -6,12 +6,12 @@ These notes are for the drivers which have already been integrated into the kernel and have been tested on Linux kernels 2.0, 2.2, and 2.3. -Version: 1.2.4 -Date: 12/15/99 +Version: 1.2.9 +Date: 04/12/2000 Author: Andrew Manison Testing: larryg@computone.com Support: support@computone.com -Fixes and Updates: Doug McNash +Fixes and Updates: Doug McNash Proc Filesystem and Kernel Integration: Mike Warfield @@ -28,7 +28,7 @@ products previous to the Intelliport II. This driver was developed on the v2.0.x Linux tree and has been tested up -to v2.2.13; it will probably not work with earlier v1.X kernels,. +to v2.2.14; it will probably not work with earlier v1.X kernels,. 2. QUICK INSTALLATION @@ -43,49 +43,48 @@ Note the hardware address from the Computone ISA cards installed into the system. These are required for editing ip2.h or editing - /etc/config.modules, or for specification on the modprobe + /etc/modules.conf, or for specification on the modprobe command line. + Note that the /etc/modules.conf file is named /etc/conf.modules + with older versions of the module utilities. + Software - Module installation: -a) Obtain driver-kernel patch file -b) Copy to the linux source tree root, Run ip2build (if not patch) -c) Determine free irq/address to use if any (configure BIOS if need be) -d) Run "make config" or "make menuconfig" or "make xconfig" +a) Determine free irq/address to use if any (configure BIOS if need be) +b) Run "make config" or "make menuconfig" or "make xconfig" Select (m) module for CONFIG_COMPUTONE under character devices. CONFIG_PCI and CONFIG_MODULES also may need to be set. -e) Set address on ISA cards then: +c) Set address on ISA cards then: edit /usr/src/linux/drivers/char/ip2/ip2.h if needed or edit /etc/modules.conf if needed (module). or both to match this setting. -f) Run "make dep" -g) Run "make modules" -h) Run "make modules_install" -i) Run "/sbin/depmod -a" -j) install driver using `modprobe ip2 ` (options listed below) -k) run ip2mkdev (either the script below or the binary version) +d) Run "make dep" +e) Run "make modules" +f) Run "make modules_install" +g) Run "/sbin/depmod -a" +h) install driver using `modprobe ip2 ` (options listed below) +i) run ip2mkdev (either the script below or the binary version) Kernel installation: -a) Obtain driver-kernel patch file -b) Copy to the linux source tree root, Run ip2build (if not patch) -c) Determine free irq/address to use if any (configure BIOS if need be) -d) Run "make config" or "make menuconfig" or "make xconfig" +a) Determine free irq/address to use if any (configure BIOS if need be) +b) Run "make config" or "make menuconfig" or "make xconfig" Select (y) kernel for CONFIG_COMPUTONE under character devices. CONFIG_PCI may need to be set if you have PCI bus. -e) Set address on ISA cards then: +c) Set address on ISA cards then: edit /usr/src/linux/drivers/char/ip2/ip2.h -f) Run "make dep" -g) Run "make zImage" or whatever target you prefer. -h) mv /usr/src/linux/arch/i386/boot/zImage to /boot. -i) Add new config for this kernel into /etc/lilo.conf, run "lilo" +d) Run "make dep" +e) Run "make zImage" or whatever target you prefer. +f) mv /usr/src/linux/arch/i386/boot/zImage to /boot. +g) Add new config for this kernel into /etc/lilo.conf, run "lilo" or copy to a floppy disk and boot from that floppy disk. -j) Reboot using this kernel -k) run ip2mkdev (either the script below or the binary version) +h) Reboot using this kernel +i) run ip2mkdev (either the script below or the binary version) 3. INSTALLATION @@ -162,6 +161,22 @@ Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and cuf0 - cuf255 for callout devices. +If you are using devfs, existing devices are automatically created within +the devfs name space. Normal devices will be ttf/0 - ttf/255 and callout +devices will be cuf/0 - cuf/255. With devfs installed, ip2mkdev will +create symbolic links in /dev from the old conventional names to the newer +devfs names as follows: + + /dev/ip2ipl[n] -> /dev/ip2/ipl[n] n = 0 - 3 + /dev/ip2stat[n] -> /dev/ip2/stat[n] n = 0 - 3 + /dev/ttyF[n] -> /dev/ttf/[n] n = 0 - 255 + /dev/cuf[n] -> /dev/cuf/[n] n = 0 - 255 + +Only devices for existing ports and boards will be created. + +You do not need to run ip2mkdev if you are using devfs and only want to +use the devfs native device names. + 4. USING THE DRIVERS @@ -195,14 +210,49 @@ use the ip2mkdev script, you must have procfs enabled and the proc file system mounted on /proc. -6. NOTES +You do not need to run ip2mkdev if you are using devfs and only want to +use the devfs native device names. + + +6. DEVFS + +DEVFS is the DEVice File System available as an add on package for the +2.2.x kernels and available as a configuration option in 2.3.46 and higher. +Devfs allows for the automatic creation and management of device names +under control of the device drivers themselves. The Devfs namespace is +hierarchial and reduces the clutter present in the normal flat /dev +namespace. Devfs names and conventional device names may be intermixed. +A userspace daemon, devfsd, exists to allow for automatic creation and +management of symbolic links from the devfs name space to the conventional +names. More details on devfs can be found on the DEVFS home site at + or in the file kernel +documenation files, .../linux/Documenation/filesystems/devfs/REAME. + +If you are using devfs, existing devices are automatically created within +the devfs name space. Normal devices will be ttf/0 - ttf/255 and callout +devices will be cuf/0 - cuf/255. With devfs installed, ip2mkdev will +create symbolic links in /dev from the old conventional names to the newer +devfs names as follows: + + /dev/ip2ipl[n] -> /dev/ip2/ipl[n] n = 0 - 3 + /dev/ip2stat[n] -> /dev/ip2/stat[n] n = 0 - 3 + /dev/ttyF[n] -> /dev/ttf/[n] n = 0 - 255 + /dev/cuf[n] -> /dev/cuf/[n] n = 0 - 255 + +Only devices for existing ports and boards will be created. + +You do not need to run ip2mkdev if you are using devfs and only want to +use the devfs native device names. + + +7. NOTES This is a release version of the driver, but it is impossible to test it in all configurations of Linux. If there is any anomalous behaviour that does not match the standard serial port's behaviour please let us know. -7. ip2mkdev shell script +8. ip2mkdev shell script Previously, this script was simply attached here. It is now attached as a shar archive to make it easier to extract the script from the documentation. @@ -223,15 +273,15 @@ # To extract the files from this archive, save it to some FILE, remove # everything before the `!/bin/sh' line above, then type `sh FILE'. # -# Made on 1999-12-17 16:06 EST by . -# Source directory was `/mnt2/src/linux-2.3.33/Documentation'. +# Made on 2000-03-10 11:55 EST by . +# Source directory was `/mnt1/src/linux-2.3.50c/Documentation'. # # Existing files will *not* be overwritten unless `-c' is specified. # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ -# 3300 -rwxr-xr-x ip2mkdev +# 4061 -rwxr-xr-x ip2mkdev # save_IFS="${IFS}" IFS="${IFS}:" @@ -278,7 +328,7 @@ fi rm -f 1231235999 $$.touch # -if mkdir _sh06360; then +if mkdir _sh17088; then $echo 'x -' 'creating lock directory' else $echo 'failed to create lock directory' @@ -291,7 +341,7 @@ $echo 'x -' extracting 'ip2mkdev' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'ip2mkdev' && #!/bin/sh - -X +# # ip2mkdev # # Make or remove devices as needed for Computone Intelliport drivers @@ -300,16 +350,48 @@ # with it. That prevents us from screwing up open ttys, ownership # and permissions on a running system! # -# This script will NOT remove devices that no longer exist because -# their board or interface box has been removed. If you want to get -# rid of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*" -# before running this script, which will then recreate all the valid -# devices +# This script will NOT remove devices that no longer exist if their +# board or interface box has been removed. If you want to get rid +# of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*" +# before running this script. Running this script will then recreate +# all the valid devices. # # =mhw= # Michael H. Warfield # mhw@wittsend.com # +# Updated 03/09/2000 for devfs support in ip2 drivers. =mhw= +# +X +if test -d /dev/ip2 ; then +# This is devfs mode... We don't do anything except create symlinks +# from the real devices to the old names! +X cd /dev +X echo "Creating symbolic links to devfs devices" +X for i in `ls ip2` ; do +X if test ! -L ip2$i ; then +X # Remove it incase it wasn't a symlink (old device) +X rm -f ip2$i +X ln -s ip2/$i ip2$i +X fi +X done +X for i in `ls ttf` ; do +X if test ! -L ttyF$i ; then +X # Remove it incase it wasn't a symlink (old device) +X rm -f ttyF$i +X ln -s ttyf/$i ttyF$i +X fi +X done +X for i in `ls cuf` ; do +X if test ! -L cuf$i ; then +X # Remove it incase it wasn't a symlink (old device) +X rm -f cuf$i +X ln -s cuf/$i cuf$i +X fi +X done +X exit 0 +fi +X if test ! -f /proc/tty/drivers then X echo "\ @@ -344,8 +426,8 @@ # Ok... So we got the driver loaded and we can locate the procfs files. # Next we need our major numbers. X -TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tty/!d' -e 's/.*tty.[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` -CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu.[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` +TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tt/!d' -e 's/.*tt[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` +CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[ ]*.*/\1/' < /proc/tty/driver/ip2` X echo "\ @@ -426,20 +508,20 @@ X Xexit 0 SHAR_EOF - $shar_touch -am 1217160599 'ip2mkdev' && + $shar_touch -am 03101153100 'ip2mkdev' && chmod 0755 'ip2mkdev' || $echo 'restore of' 'ip2mkdev' 'failed' if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'ip2mkdev:' 'MD5 check failed' -eccd181f4a2005e47a969fc83885df61 ip2mkdev +b0671abeba07b0a9266b70aaf24509b3 ip2mkdev SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ip2mkdev'`" - test 3300 -eq "$shar_count" || - $echo 'ip2mkdev:' 'original size' '3300,' 'current size' "$shar_count!" + test 4061 -eq "$shar_count" || + $echo 'ip2mkdev:' 'original size' '4061,' 'current size' "$shar_count!" fi fi -rm -fr _sh06360 +rm -fr _sh17088 exit 0 diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/fb/tgafb.txt linux/Documentation/fb/tgafb.txt --- v2.3.99-pre5/linux/Documentation/fb/tgafb.txt Thu Jul 1 10:57:36 1999 +++ linux/Documentation/fb/tgafb.txt Wed Apr 12 09:47:30 2000 @@ -1,25 +1,35 @@ -[Also cloned from vesafb.txt, thanks to Gerd] +$Id: tgafb.txt,v 1.1.2.2 2000/04/04 06:50:18 mato Exp $ What is tgafb? =============== This is a driver for DECChip 21030 based graphics framebuffers, a.k.a. TGA -cards, specifically the following models +cards, which are usually found in older Digital Alpha systems. The +following models are supported: -ZLxP-E1 (8bpp, 4 MB VRAM) +ZLxP-E1 (8bpp, 2 MB VRAM) ZLxP-E2 (32bpp, 8 MB VRAM) ZLxP-E3 (32bpp, 16 MB VRAM, Zbuffer) -This version, tgafb-1.12, is almost a complete rewrite of the code written -by Geert Uytterhoeven, which was based on the original TGA console code -written by Jay Estabrook. - -Major new features: - - * Support for multiple resolutions, including setting the resolution at - boot time, allowing the use of a fixed-frequency monitor. - * Complete code rewrite to follow Geert's skeletonfb spec which will allow - future implementation of hardware acceleration and other features. +This version is an almost complete rewrite of the code written by Geert +Uytterhoeven, which was based on the original TGA console code written by +Jay Estabrook. + +Major new features since Linux 2.0.x: + + * Support for multiple resolutions + * Support for fixed-frequency and other oddball monitors + (by allowing the video mode to be set at boot time) + +User-visible changes since Linux 2.2.x: + + * Sync-on-green is now handled properly + * More useful information is printed on bootup + (this helps if people run into problems) + +This driver does not (yet) support the TGA2 family of framebuffers, so the +PowerStorm 3D30/4D20 (also known as PBXGB) cards are not supported. These +can however be used with the standard VGA Text Console driver. Configuration @@ -32,19 +42,27 @@ font:X - default font to use. All fonts are supported, including the SUN12x22 font which is very nice at high resolutions. -mode:X - default video mode. See drivers/video/tgafb.c for a list. - -X11 -=== - -XF68_FBDev should work just fine, but I haven't tested it. Running -the XF86_TGA server (reasonably recent versions of which support all TGA -cards) works fine for me. - -One minor problem with XF86_TGA is when running tgafb in resolutions higher -than 640x480, on switching VCs from tgafb to X, the entire screen is not -re-drawn and must be manually refreshed. This is an X server problem, not a -tgafb problem. + +mode:X - default video mode. The following video modes are supported: + 640x480-60, 800x600-56, 640x480-72, 800x600-60, 800x600-72, + 1024x768-60, 1152x864-60, 1024x768-70, 1024x768-76, + 1152x864-70, 1280x1024-61, 1024x768-85, 1280x1024-70, + 1152x864-84, 1280x1024-76, 1280x1024-85 + + +Known Issues +============ + +The XFree86 FBDev server has been reported not to work, since tgafb doesn't do +mmap(). Running the standard XF86_TGA server from XFree86 3.3.x works fine for +me, however this server does not do acceleration, which make certain operations +quite slow. Support for acceleration is being progressively integrated in +XFree86 4.x. + +When running tgafb in resolutions higher than 640x480, on switching VCs from +tgafb to XF86_TGA 3.3.x, the entire screen is not re-drawn and must be manually +refreshed. This is an X server problem, not a tgafb problem, and is fixed in +XFree86 4.0. Enjoy! diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog --- v2.3.99-pre5/linux/Documentation/filesystems/devfs/ChangeLog Tue Mar 7 14:32:25 2000 +++ linux/Documentation/filesystems/devfs/ChangeLog Fri Apr 21 16:11:05 2000 @@ -1480,3 +1480,19 @@ - Only set auto-ownership for /dev/pty/s* +=============================================================================== +Changes for patch v162 + +Work sponsored by SGI + +- Set inode->i_size to correct size for symlinks + Thanks to Jeremy Fitzhardinge + +- Only give lookup() method to directories to comply with new VFS + assumptions + +- Remove unnecessary tests in symlink methods + +- Don't kill existing block ops in + +- Restore auto-ownership for /dev/pty/m* diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/filesystems/devfs/modules.conf linux/Documentation/filesystems/devfs/modules.conf --- v2.3.99-pre5/linux/Documentation/filesystems/devfs/modules.conf Wed Feb 16 17:03:51 2000 +++ linux/Documentation/filesystems/devfs/modules.conf Fri Apr 21 16:11:05 2000 @@ -38,7 +38,7 @@ # SCSI tapes probeall /dev/st scsi-hosts st -alias /dev/st* /dev/sr +alias /dev/st* /dev/st alias /dev/nst* /dev/st # SCSI generic diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/ia64/efirtc.txt linux/Documentation/ia64/efirtc.txt --- v2.3.99-pre5/linux/Documentation/ia64/efirtc.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/ia64/efirtc.txt Fri Apr 21 15:21:23 2000 @@ -0,0 +1,128 @@ +EFI Real Time Clock driver +------------------------------- +S. Eranian +March 2000 + +I/ Introduction + +This document describes the efirtc.c driver has provided for +the IA-64 platform. + +The purpose of this driver is to supply an API for kernel and user applications +to get access to the Time Service offered by EFI version 0.92. + +EFI provides 4 calls one can make once the OS is booted: GetTime(), +SetTime(), GetWakeupTime(), SetWakeupTime() which are all supported by this driver. +We describes those calls as well the the design of the driver in the following +sections. + +II/ Design Decisions + +The original ideas was to provide a very simple driver to get access to, +at first, the time of day service. This is required in order to access, in a +portable way, the CMOS clock. A program like /sbin/hwclock uses such a clock +to initialize the system view of the time during boot. + +Because we wanted to minimize the impact on existing user-level apps using +the CMOS clock, we decided to expose an API that was very similar to the one +used today with the legacy RTC driver (driver/char/rtc.c). However, because +EFI provides a simpler services, not all all ioctl() are available. Also +new ioctl()s have been introduced for things that EFI provides but not the +legacy. + +EFI uses a slightly different way of representing the time, noticeably +the reference date is different. Year is the using the full 4-digit format. +The Epoch is January 1st 1998. For backward compatibility reasons we don't +expose this new way of representing time. Instead we use something very +similar to the struct tm, i.e. struct rtc_time, as used by hwclock. +One of the reasons for doing it this way is to allow for EFI to still evolve +without necessarily impatcing any of the user applications. The decoupling +enables flexibility and permits writing wrapper code is ncase things change. + +The driver exposes two interfaces, one via the device file and a set of ioctl()s. +The other is read-only via the /proc filesystem. + +As of today we don't offer a /proc/sys interface. + +To allow for a uniform interface between the legacy RTC and EFI time service, +we have created the include/linux/rtc.h header file to contain only the +"public" API of the two drivers. The specifics of the legacy RTC are still +in include/linux/mc146818rtc.h. + + +III/ Time of day service + +The part of the driver gives access to the time of day service of EFI. +Two ioctl()s, compatible with the legacy RTC calls: + + Read the CMOS clock: ioctl(d, RTC_RD_TIME, &rtc); + + Write the CMOS clock: ioctl(d, RTC_SET_TIME, &rtc); + +The rtc is a pointer to a data structure defined in rtc.h which is close +to a struct tm: + +struct rtc_time { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +The driver takes care of converting back an forth between the EFI time and +this format. + +Those two ioctl()s can be exercised with the hwclock command: + +For reading: +# /sbin/hwclock --show +Mon Mar 6 15:32:32 2000 -0.910248 seconds + +For setting: +# /sbin/hwclock --systohc + +Root privileges are required to be able to set the time of day. + +IV/ Wakeup Alarm service + +EFI provides an API by which one can program when a machine should wakeup, +i.e. reboot. This is very different from the alarm provided by the legacy +RTC which is some kind of interval timer alarm. For this reason we don't use +the same ioctl()s to get access to the service. Instead we have +introduced 2 news ioctl()s to the interface of an RTC. + +We have added 2 new ioctl()s that are specific to the EFI driver: + + Read the current state of the alarm + ioctl(d, RTC_WKLAM_RD, &wkt) + + Set the alarm or change its status + ioctl(d, RTC_WKALM_SET, &wkt) + +The wkt structure encapsulates a struct rtc_time + 2 extra fields to get +status information: + +struct rtc_wkalrm { + + unsigned char enabled; /* =1 if alarm is enabled */ + unsigned char pending; /* =1 if alarm is pending */ + + struct rtc_time time; +} + +As of today, none of the existing user-level apps supports this feature. +However writing such a program should be hard by simply using those two +ioctl(). + +Root privileges are required to be able to set the alarm. + +V/ References. + +Checkout the following Web site for more information on EFI: + +http://developer.intel.com/technology/efi/ diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.3.99-pre5/linux/Documentation/ioctl-number.txt Sat Feb 26 22:31:37 2000 +++ linux/Documentation/ioctl-number.txt Thu Apr 13 09:00:51 2000 @@ -28,8 +28,9 @@ I'll register one for you. The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number -to distinguish ioctls from each other. The third argument is the size -of the structure going into the kernel or coming out of the kernel. +to distinguish ioctls from each other. The third argument to _IOW, +_IOR, or _IOWR is the type of the data going into the kernel or coming +out of the kernel (e.g. 'int' or 'struct foo'). Some devices use their major number as the identifier; this is OK, as long as it is unique. Some devices are irregular and don't follow any diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/kernel-docs.txt linux/Documentation/kernel-docs.txt --- v2.3.99-pre5/linux/Documentation/kernel-docs.txt Fri Jan 21 18:19:15 2000 +++ linux/Documentation/kernel-docs.txt Tue Apr 25 16:53:13 2000 @@ -164,6 +164,18 @@ different situations. We also investigate the complex topic of DMA". + * Title: "Device Drivers Concluded" + Author: Georg v. Zezschwitz. + URL: http://www2.linuxjournal.com/lj-issues/issue28/1287.html + Keywords: address spaces, pages, pagination, page management, + demand loading, swapping, memory protection, memory mapping, mmap, + virtual memory areas (VMAs), vremap, PCI. + Description: Finally, the above turned out into a five articles + series. This latest one's introduction reads: "This is the last of + five articles about character device drivers. In this final + section, Georg deals with memory mapping devices, beginning with + an overall description of the Linux memory management concepts". + * Title: "Network Buffers And Memory Management" Author: Alan Cox. URL: http://www.ssc.com/lj/issue30/kk30.html @@ -234,11 +246,26 @@ Description: 68 pages paper on writing character drivers. A little bit old (1.993, 1.994) although still useful. + * Title: "Design and Implementation of the Second Extended + Filesystem" + Author: Rémy Card, Theodore Ts'o, Stephen Tweedie. + URL: http://web.mit.edu/tytso/www/linux/ext2intro.html + Keywords: ext2, linux fs history, inode, directory, link, devices, + VFS, physical structure, performance, benchmarks, ext2fs library, + ext2fs tools, e2fsck. + Description: Paper written by three of the top ext2 hackers. + Covers Linux filesystems history, ext2 motivation, ext2 features, + design, physical structure on disk, performance, benchmarks, + e2fsck's passes description... A must read! + Notes: This paper was first published in the Proceedings of the + First Dutch International Symposium on Linux, ISBN 90-367-0385-9. + * Title: "The Second Extended Filesystem" Author: Matthew Wilcox. URL: http://pocket.fluff.org/~mrw/linux/ext2.txt Keywords: ext2, filesystem. - Description: Description of ext2's blocks, directories, inodes ... + Description: Description of ext2's blocks, directories, inodes... + Notes: Seems to be DOWN. Anyone knows another link for it? * Title: "Analysis of the Ext2fs structure" Author: Louis-Dominique Dubeau. @@ -247,6 +274,15 @@ Description: Description of ext2's blocks, directories, inodes, bitmaps, invariants ... + * Title: "Journaling the Linux ext2fs Filesystem" + Author: Stephen C. Tweedie. + URL: + ftp://ftp.uk.linux.org:/pub/linux/sct/fs/jfs/journal-design.ps.gz + Keywords: ext3, journalist. + Description: Excellent 8-pages paper explaining the journaling + capabilities added to ext2 by the author, showing different + problems faced and the alternatives chosen. + * Title: "Kernel API changes from 2.0 to 2.2" Author: Richard Gooch. URL: @@ -258,7 +294,7 @@ * Title: "Kernel API changes from 2.2 to 2.3" Author: Richard Gooch. URL: - http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.2.html + http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.3.html Keywords: 2.3, changes. Description: Kernel functions/structures/variables which changed from 2.2.x to 2.3.x. @@ -295,6 +331,81 @@ want a mechanism that is scalable. This means a large number of inactive FDs cost very little in memory and CPU time to manage". + * Title: "The Kernel Hacking HOWTO" + Author: Various Talented People, and Rusty. + URL: http://www.samba.org/~netfilter/kernel-hacking-HOWTO.html + Keywords: HOWTO, kernel contexts, deadlock, locking, modules, + symbols, return conventions. + Description: From the Introduction: "Please understand that I + never wanted to write this document, being grossly underqualified, + but I always wanted to read it, and this was the only way. I + simply explain some best practices, and give reading entry-points + into the kernel sources. I avoid implementation details: that's + what the code is for, and I ignore whole tracts of useful + routines. This document assumes familiarity with C, and an + understanding of what the kernel is, and how it is used. It was + originally written for the 2.3 kernels, but nearly all of it + applies to 2.2 too; 2.0 is slightly different. ". + + * Title: "ALSA 0.5.0 Developer documentation" + Author: Stephan 'Jumpy' Bartels . + URL: http://www.math.TU-Berlin.de/~sbartels/alsa/ + Keywords: ALSA, sound, soundcard, driver, lowlevel, hardware. + Description: Advanced Linux Sound Architecture for developers, + both at kernel and user-level sides. Work in progress. ALSA is + supposed to be Linux's next generation sound architecture. + + * Title: "Programming Guide for Linux USB Device Drivers" + Author: Detlef Fliegl. + URL: http://usb.in.tum.de/usbdoc/ + Keywords: USB, universal serial bus. + Description: A must-read. From the Preface: "This document should + give detailed information about the current state of the USB + subsystem and its API for USB device drivers. The first section + will deal with the basics of USB devices. You will learn about + different types of devices and their properties. Going into detail + you will see how USB devices communicate on the bus. The second + section gives an overview of the Linux USB subsystem [2] and the + device driver framework. Then the API and its data structures will + be explained step by step. The last section of this document + contains a reference of all API calls and their return codes". + Notes: Beware: the main page states: "This document may not be + published, printed or used in excerpts without explicit permission + of the author". Fortunately, it may still be read... + + * Title: "Tour Of the Linux Kernel Source" + Author: Vijo Cherian. + URL: http://www.geocities.com/vijoc/tolks/tolks.html + Keywords: . + Description: A classic of this page! Was lost for a while and is + back again. Thanks Vijo! TOLKS: the name says it all. A tour of + the sources, describing directories, files, variables, data + structures... It covers general stuff, device drivers, + filesystems, IPC and Networking Code. + + * Title: "Linux Kernel Mailing List Glossary" + Author: John Levon. + URL: http://www.movement.uklinux.net/glossary.html + Keywords: glossary, terms, linux-kernel. + Description: From the introduction: "This glossary is intended as + a brief description of some of the acronyms and terms you may hear + during discussion of the Linux kernel". + + * Title: "Linux Kernel Locking HOWTO" + Author: Various Talented People, and Rusty. + URL: + http://netfilter.kernelnotes.org/unreliable-guides/kernel-locking- + HOWTO.html + Keywords: locks, locking, spinlock, semaphore, atomic, race + condition, bottom halves, tasklets, softirqs. + Description: The title says it all: document describing the + locking system in the Linux Kernel either in uniprocessor or SMP + systems. + Notes: "It was originally written for the later (>2.3.47) 2.3 + kernels, but most of it applies to 2.2 too; 2.0 is slightly + different". Freely redistributable under the conditions of the GNU + General Public License. + BOOKS: (Not on-line) * Title: "Linux Device Drivers" @@ -366,15 +477,33 @@ * Title: "Linux Core Kernel Commentary. Guide to Insider's Knowledge on the Core Kernel od the Linux Code" Author: Scott Maxwell. - Publisher: ???. + Publisher: Coriolis. Date: 1999. Pages: 592. ISBN: 1-57610-469-9 - Notes: CD-ROM included. + Notes: CD-ROM included. Line by line commentary of the kernel + code. + + * Title: "Linux IP Stacks Commentary" + Author: Stephen Satchell and HBJ Clifford. + Publisher: Coriolis. + Date: 2000. + Pages: ???. + ISBN: 1-57610-470-2 + Notes: Line by line source code commentary book. + + * Title: "Programming for the real world - POSIX.4" + Author: Bill O. Gallmeister. + Publisher: O'Reilly & Associates, Inc.. + Date: 1995. + Pages: ???. + ISBN: I-56592-074-0 + Notes: Though not being directly about Linux, Linux aims to be + POSIX. Good reference. MISCELLANEOUS: - * Name: Linux Source Driver. + * Name: "Linux Source Driver" URL: http://lsd.linux.cz Keywords: Browsing source code. Description: "Linux Source Driver (LSD) is an application, which @@ -385,27 +514,27 @@ and variables) and LSD can generate patches for you on the fly (files, directories or kernel)". - * Name: Cross-Referencing Linux. + * Name: "Cross-Referencing Linux" URL: http://lxr.linux.no/source/ Keywords: Browsing source code. Description: Another web-based Linux kernel source code browser. Lots of cross references to variables and functions. You can see where they are defined and where they are used. - * Name: Linux Weekly News. + * Name: "Linux Weekly News" URL: http://lwn.net Keywords: latest kernel news. Description: The title says it all. There's a fixed kernel section summarizing developers' work, bug fixes, new features and versions produced during the week. Published every Thursday. - * Name: Kernel Traffic. + * Name: "Kernel Traffic" URL: http://kt.linuxcare.com Keywords: linux-kernel mailing list, weekly kernel news. Description: Weekly newsletter covering the most relevant discussions of the linux-kernel mailing list. - * Name: CuTTiNG.eDGe.LiNuX. + * Name: "CuTTiNG.eDGe.LiNuX" URL: http://edge.kernelnotes.org Keywords: changelist. Description: Site which provides the changelist for every kernel @@ -413,7 +542,7 @@ the patches and describes them. Pointers to the patches are there, too. - * Name: New linux-kernel Mailing List FAQ. + * Name: "New linux-kernel Mailing List FAQ" URL: Original site: http://www.altern.org/andrebalsa/doc/lkml-faq.html URL: U.S. mirror site: @@ -433,6 +562,45 @@ Description: Set of slides, presumably from a presentation on the Linux VFS layer. Covers version 2.1.x, with dentries and the dcache. + + * Name: "Gary's Enciclopedia - The Linux Kernel" + Author: Gary (I suppose...). + URL: http://members.aa.net/~swear/pedia/kernel.html + Keywords: links, not found here?. + Description: Gary's Enciclopedia exists to allow the rapid finding + of documentation and other information of interest to GNU/Linux + users. It has about 4000 links to external pages in 150 major + categories. This link is for kernel-specific links, documents, + sites... Look there if you could not find here whar you were + looking for. + + * Name: "The home page of Linux-MM" + Author: The Linux-MM team. + URL: http://www.linux.eu.org/Linux-MM/ + Keywords: memory management, Linux-MM, mm patches, TODO, docs, + mailing list. + Description: Site devoted to Linux Memory Mangement development. + Memory related patches, HOWTOs, links, mm developers... Don't miss + it if you are interested in memory management development! + + * Name: "Kernel Newbies IRC Channel" + URL: http://www.surriel.com/kernelnewbies.shtml + Keywords: IRC, newbies, channel, asking doubts. + Description: #kernelnewbies on irc.openprojects.net. From the web + page: "#kernelnewbies is an IRC network dedicated to the 'newbie' + kernel hacker. The audience mostly consists of people who are + learning about the kernel, working on kernel projects or + professional kernel hackers that want to help less seasoned kernel + people. [...] #kernelnewbies is on the Open Projects IRC Network, + try irc.openprojects.net or irc..openprojects.net as your + server and then /join #kernelnewbies". + + * Name: "linux-kernel mailing list archives and search engines" + URL: http://www.uwsg.indiana.edu/hypermail/linux/kernel/index.html + URL: http://www.kernelnotes.org/lnxlists/linux-kernel/ + Keywords: linux-kernel, archives, search. + Description: Some of the linux-kernel mailing list archivers. If + you have a better/another one, please let me know. _________________________________________________________________ - Document last updated on Tue Nov 30 11:20:00 CET 1999 + Document last updated on Mon Apr 17 18:07:07 CEST 2000 diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/networking/dmfe.txt linux/Documentation/networking/dmfe.txt --- v2.3.99-pre5/linux/Documentation/networking/dmfe.txt Tue Mar 14 19:10:38 2000 +++ linux/Documentation/networking/dmfe.txt Mon Apr 24 13:39:33 2000 @@ -16,17 +16,13 @@ A. Compiler command: - A-1: For normal single processor kernel + A-1: For normal single or multiple processor kernel "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c dmfe.c" - A-2: For single processor and enable kernel module version function + A-2: For single or multiple processor with kernel module version function "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c dmfe.c" - - A-3: For multiple processors(SMP) and enable the module version function - "gcc -D__SMP__ -DMODULE -DMODVERSIONS -D__KERNEL__ -I/usr/src/linux - /net/inet -Wall -Wstrict-prototypes -O6 -c dmfe.c" B. The following steps teach you how to active DM9102 board: diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/networking/fore200e.txt linux/Documentation/networking/fore200e.txt --- v2.3.99-pre5/linux/Documentation/networking/fore200e.txt Sat Feb 26 22:31:37 2000 +++ linux/Documentation/networking/fore200e.txt Fri Apr 14 09:37:10 2000 @@ -1,6 +1,26 @@ -Fore PCA-200E/SBA-200E ATM NIC Firmware Copyright Notice --------------------------------------------------------- +FORE Systems PCA-200E/SBA-200E ATM NIC driver +--------------------------------------------- + +This driver adds support for the FORE Systems 200E-series ATM adapters +to the Linux operating system. It is based on the earlier PCA-200E driver +written by Uwe Dannowski. + +The driver simultaneously supports PCA-200E and SBA-200E adapters on +i386, alpha (untested), powerpc, sparc and sparc64 archs. + +The intent is to enable the use of different models of FORE adapters at the +same time, by hosts that have several bus interfaces (such as PCI+SBUS, +PCI+MCA or PCI+EISA). + +Only PCI and SBUS devices are currently supported by the driver, but support +for other bus interfaces such as EISA should not be too hard to add (this may +be more tricky for the MCA bus, though, as FORE made some MCA-specific +modifications to the adapter's AALI interface). + + +Firmware Copyright Notice +------------------------- Please read the fore200e_firmware_copyright file present in the linux/drivers/atm directory for details and restrictions. @@ -13,26 +33,22 @@ uploaded to the ATM adapters at system boot time or at module loading time. The supplied firmware images should work with all adapters. -However, if you encounter problems (firmware doesn't start or the driver -is unable to read PROM data), you may consider trying another firmware +However, if you encounter problems (the firmware doesn't start or the driver +is unable to read the PROM data), you may consider trying another firmware version. Alternative binary firmware images can be found somewhere on the -ForeThough CD-ROM supplied with your adapter by FORE Systems. +ForeThought CD-ROM supplied with your adapter by FORE Systems. You can also get the latest firmware images from FORE Systems at http://www.fore.com. Register TACTics Online and go to the 'software updates' pages. The firmware binaries are part of -the various ForeThough software distributions. +the various ForeThought software distributions. Notice that different versions of the PCA-200E firmware exist, depending on the endianess of the host architecture. The driver is shipped with both little and big endian PCA firmware images. Name and location of the new firmware images can be set at kernel -configuration time. - - -Driver Rebuilding ------------------ +configuration time: 1. Copy the new firmware binary files (with .bin, .bin1 or .bin2 suffix) to some directory, such as linux/drivers/atm. @@ -40,11 +56,7 @@ 2. Reconfigure your kernel to set the new firmware name and location. Expected pathnames are absolute or relative to the drivers/atm directory. -3. Delete the files drivers/atm/fore200e_pca_fw.[co] and/or fore200e_sba_fw.[co] - to ensure that the new firmware will be used when rebuilding the kernel or - the module. - -4. Rebuild and re-install your kernel or your module. +3. Rebuild and re-install your kernel or your module. Feedback @@ -52,4 +64,3 @@ Feedback is welcome. Please send success stories/bug reports/ patches/improvement/comments/flames to . - diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/networking/tulip.txt linux/Documentation/networking/tulip.txt --- v2.3.99-pre5/linux/Documentation/networking/tulip.txt Mon Mar 27 08:08:20 2000 +++ linux/Documentation/networking/tulip.txt Fri Apr 14 10:09:00 2000 @@ -142,6 +142,10 @@ Version history =============== +0.9.4.3 (April 14, 2000): +* mod_timer fix (Hal Murray) +* PNIC2 resusitation (Chris Smith) + 0.9.4.2 (March 21, 2000): * Fix 21041 CSR7, CSR13/14/15 handling * Merge some PCI ids from tulip 0.91x diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt --- v2.3.99-pre5/linux/Documentation/networking/vortex.txt Mon Jan 22 12:52:34 1996 +++ linux/Documentation/networking/vortex.txt Mon Apr 24 15:17:06 2000 @@ -1,8 +1,46 @@ This document describes the usage and errata of the 3Com "Vortex" device driver for Linux. +The driver was written by Donald Becker + +Don is no longer the prime maintener of this version of the driver. +Please report problems to one or more of: + + Andrew Morton + Netdev mailing list + + This driver supports the following hardware: - 3c590, 3c592, 3c595, 3c597 + + 3c590 Vortex 10Mbps + 3c592 EISA 10mbps Demon/Vortex + 3c597 EISA Fast Demon/Vortex + 3c595 Vortex 100baseTx + 3c595 Vortex 100baseT4 + 3c595 Vortex 100base-MII + 3Com Vortex + 3c900 Boomerang 10baseT + 3c900 Boomerang 10Mbps Combo + 3c900 Cyclone 10Mbps TPO + 3c900 Cyclone 10Mbps Combo + 3c900 Cyclone 10Mbps TPC + 3c900B-FL Cyclone 10base-FL + 3c905 Boomerang 100baseTx + 3c905 Boomerang 100baseT4 + 3c905B Cyclone 100baseTx + 3c905B Cyclone 10/100/BNC + 3c905B-FX Cyclone 100baseFx + 3c905C Tornado + 3c980 Cyclone + 3cSOHO100-TX Hurricane + 3c555 Laptop Hurricane + 3c575 Boomerang CardBus + 3CCFE575 Cyclone CardBus + 3CCFE575CT Cyclone CardBus + 3CCFE656 Cyclone CardBus + 3CCFEM656 Cyclone CardBus + 3c450 Cyclone/unknown + 3Com Boomerang (unknown version) When loaded as a module the following variables may be set: name type description @@ -33,3 +71,46 @@ 16 Bus-master enable bit (experimental use only!) Details of the device driver implementation are at the top of the source file. + +Additional documentation is available at Don Becker's Linux Drivers site: + + http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html + + +Additional resources +-------------------- + +Donald Becker's driver development site: + + http://cesdis.gsfc.nasa.gov/linux/ + +Don's vortex-diag program is useful for inspecting the NIC's state: + + http://cesdis.gsfc.nasa.gov/linux/diag/vortex-diag.c + +Don's mii-diag program may be used for inspecting and manipulating the +NIC's Media Independent Interface subsystem: + + http://cesdis.gsfc.nasa.gov/linux/diag/#mii-diag + +3Com's documentation for many NICs, including the ones supported by +this driver is available at + + http://support.3com.com/partners/developer/developer_form.html + +A detailed changelog for the modifications which were made for 2.3 +series kernel is available at + + http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 + + + +Cisco interoperability note from Walter Wong : + + On a side note, adding HAS_NWAY seems to share a problem with the + Cisco 6509 switch. Specifically, you need to change the spanning + tree parameter for the port the machine is plugged into to 'portfast' + mode. Otherwise, the negotiation fails. This has been an issue + we've noticed for a while but haven't had the time to track down. + + diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sound/ALS linux/Documentation/sound/ALS --- v2.3.99-pre5/linux/Documentation/sound/ALS Tue Mar 14 19:10:38 2000 +++ linux/Documentation/sound/ALS Tue Apr 11 19:13:15 2000 @@ -13,9 +13,12 @@ sound configuration section of the kernel config: - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support - FM synthesizer (YM3812/OPL-3) support -Since the ALS-007/100/200 is a PnP card, the sound driver probably should be -compiled as a module, with the isapnptools used to wake up the sound card. -Set the "I/O base for SB", "Sound Blaster IRQ" and "Sound Blaster DMA" (8 bit - +Since the ALS-007/100/200 are PnP cards, ISAPnP support should probably be +compiled in. + +Alternatively, if you decide not to use kernel level ISAPnP, you can use the +user mode isapnptools to wake up the sound card, as in 2.2.X. Set the "I/O +base for SB", "Sound Blaster IRQ" and "Sound Blaster DMA" (8 bit - either 0, 1 or 3) to the values used in your particular installation (they should match the values used to configure the card using isapnp). The ALS-007 does NOT implement 16 bit DMA, so the "Sound Blaster 16 bit DMA" @@ -41,3 +44,4 @@ 30 March 1998 Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200 +Modified 2000-04-10 by Paul Laufer, pelaufer@csupomona.edu to add ISAPnP info. diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sound/AWE32 linux/Documentation/sound/AWE32 --- v2.3.99-pre5/linux/Documentation/sound/AWE32 Sun Nov 7 16:37:33 1999 +++ linux/Documentation/sound/AWE32 Tue Apr 11 19:13:15 2000 @@ -9,9 +9,10 @@ 2) If your card is NOT "Plug-n-Play" then go to 5th step now. In the other case proceed to step 3. -3) You should obtain isapnptools. I looked through other PnP packages -for Linux, but all they are either in deep unstable beta/alpha releases or -they are much worse than isapnptools. In my case isapnptools were included in +3) You should compile in kernel ISAPnP support or you should obtain isapnptools. +If you choose kernel level ISAPnP skip to step 5. I looked through other PnP +packages for Linux, but all they are either in deep unstable beta/alpha releases +or they are much worse than isapnptools. In my case isapnptools were included in a Linux distribution (Red Hat 5.x). If you also already have them then go to step 4. @@ -67,11 +68,7 @@ In "make (x,menu)config" select in "Sound": select "OSS sound modules" as (module) - -In "Additional low level sound drivers": -"Additional low level sound drivers", "AWE32 synth" as (module). -Select "Additional low level sound drivers" as [y] (or [*] (yes)) (If it is not -available as [y], select it as (module)) +select "AWE32 Synth" as (module) Now recompile the kernel (make dep; make (b)zImage, b(z)lilo, etc...; make modules; make modules_install), update your boot loader (if required) and @@ -87,9 +84,7 @@ alias midi awe_wave post-install awe_wave /usr/bin/sfxload /usr/synthfm.sbk -options sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330 -(on io=0xaaa irq=b.... you should use your own settings) That will enable the Sound Blaster and AWE wave synthesis. To play midi files you should get one of these programs: @@ -107,4 +102,4 @@ Yaroslav Rosomakho (alons55@dialup.ptt.ru) http://www.yar.opennet.ru -Last Updated: 3Jan99 +Last Updated: 10Apr2000 diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sound/README.awe linux/Documentation/sound/README.awe --- v2.3.99-pre5/linux/Documentation/sound/README.awe Thu Apr 29 11:53:41 1999 +++ linux/Documentation/sound/README.awe Tue Apr 11 19:13:15 2000 @@ -23,11 +23,10 @@ * NOTE TO LINUX USERS -To enable this driver on linux-2.[01].x kernels, you need turn on both -"lowlevel drivers support" and "AWE32 synth support" options in sound -menu when configure your linux kernel and modules. The precise -installation procedure is described in the AWE64-Mini-HOWTO and -linux-kernel/Documetation/sound/AWE32. +To enable this driver on linux-2.[01].x kernels, you need turn on +"AWE32 synth" options in sound menu when configure your linux kernel +and modules. The precise installation procedure is described in the +AWE64-Mini-HOWTO and linux-kernel/Documetation/sound/AWE32. If you're using PnP cards, the card must be initialized before loading the sound driver. There're several options to do this: diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sound/README.modules linux/Documentation/sound/README.modules --- v2.3.99-pre5/linux/Documentation/sound/README.modules Sun Nov 7 16:37:33 1999 +++ linux/Documentation/sound/README.modules Tue Apr 11 19:13:15 2000 @@ -33,6 +33,12 @@ options sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330 options adlib_card io=0x388 # FM synthesizer + Alternatively, if you have compiled in kernel level ISAPnP support: + +alias char-major-14 sb +post-install sb /sbin/modprobe "-k" "adlib_card" +options adlib_card io=0x388 + The effect of this is that the sound driver and all necessary bits and pieces autoload on demand, assuming you use kerneld (a sound choice) and autoclean when not in use. Also, options for the device drivers are diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sound/Soundblaster linux/Documentation/sound/Soundblaster --- v2.3.99-pre5/linux/Documentation/sound/Soundblaster Wed Aug 19 14:38:12 1998 +++ linux/Documentation/sound/Soundblaster Tue Apr 11 19:13:15 2000 @@ -13,12 +13,19 @@ dma16 16-bit DMA channel for SB16 and equivalent cards (5,6,7) mpu_io I/O for MPU chip if present (0x300,0x330) -mad16=1 Set when loading this as part of the MAD16 setup only -trix=1 Set when loading this as part of the Audiotrix setup only -pas2=1 Set when loading this as part of the Pas2 setup only sm_games=1 Set if you have a Logitech soundman games acer=1 Set this to detect cards in some ACER notebooks mwave_bug=1 Set if you are trying to use this driver with mwave (see on) +type Use this to specify a specific card type + +The following arguments are taken if ISAPnP support is compiled in + +isapnp=0 Set this to disable ISAPnP detection (use io=0xXXX etc. above) +multiple=1 Set to enable detection of multiple Soundblaster cards. +reverse=1 Reverses the order of the search in the PnP table. +uart401=1 Set to enable detection of mpu devices on some clones. +isapnpjump Jumps to a specific slot in the driver's PnP table. Use the + source, Luke. You may well want to load the opl3 driver for synth music on most SB and clone SB devices diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/sx.txt linux/Documentation/sx.txt --- v2.3.99-pre5/linux/Documentation/sx.txt Thu Aug 5 14:47:44 1999 +++ linux/Documentation/sx.txt Mon Apr 24 13:39:33 2000 @@ -175,8 +175,13 @@ works). sx_irqmask: The mask of allowable IRQs to use. I suggest you set - this to 0 (disable IRQs all together) and use polling if - the assignment of IRQs becomes problematic. + this to 0 (disable IRQs all together) and use polling if + the assignment of IRQs becomes problematic. This is defined + as the sum of (1 << irq) 's that you want to allow. So + sx_irqmask of 8 (1 << 3) specifies that only irq 3 may + be used by the SX driver. If you want to specify to the + driver: "Either irq 11 or 12 is ok for you to use", then + specify (1 << 11) | (1 << 12) = 0x1800 . sx_debug: You can enable different sorts of debug traces with this. At "-1" all debugging traces are active. You'll get several diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/usb/dc2xx.txt linux/Documentation/usb/dc2xx.txt --- v2.3.99-pre5/linux/Documentation/usb/dc2xx.txt Fri Jan 21 18:19:15 2000 +++ linux/Documentation/usb/dc2xx.txt Fri Apr 21 14:03:00 2000 @@ -1,4 +1,4 @@ -19 January 2000 +14 April 2000 david-b@pacbell.net This is an overview of how to use the "dc2xx" USB driver with certain @@ -17,30 +17,22 @@ In addition the DC-220, DC-260, DC-265, and DC-290 are also recognized. However, like other cameras using the "Digita OS" (from www.flashpoint.com) -there is no gPhoto support for this camera. At this writing the best -known support for these cameras is a Python script that supports image -downloading from those cameras. (See archives of the linux-usb mailing -list.) When it becomes available, the HP PhotoSmart C500 should also -work ... it's another Digita OS camera with USB support. - -It's likely that other digital still cameras can also use this USB driver, -even if they're not from Kodak and don't use Digita. The reason is that -most currently known USB still camera protocols treat USB like a faster -packet-carrying connection than a serial line, which is exactly how this -driver looks to an application. +there is no gPhoto support for this camera. There is a python script +for accessing these cameras (see archives of the linux-usb mailing list) +and a "Digita Services" library that can also use this driver. + +The HP PhotoSmart C500 should also work, since it's another Digita camera +with USB support. USB HARDWARE -This has been shown to work on x86 OHCI and UHCI (Intel) chipsets. OHCI has -been trouble free; not so with UHCI, which was first seen to be happy with -2.3.24 kernels, and has not been as fast as OHCI. Users on the PowerMac -platform have had success, although the stock kernel doesn't yet support -that platform. +Recent kernels have had no particular problems using this driver with +either OHCI or UHCI chipsets, and have worked on the PowerMac platform. Note that in some cases changes in BIOS settings may be needed before your USB works. At least one user has reported a need for SMP-related -settings as well. +settings as well, and some old hardware may not handle USB correctly. SETUP @@ -50,15 +42,18 @@ Create at least one device, perhaps like this (both read and write): - # mknod -m 0666 /dev/kodak00 c 180 80 - # mknod -m 0666 /dev/kodak01 c 180 81 + # mknod -m 0660 /dev/usb/dc2xx0 c 180 80 + # mknod -m 0660 /dev/usb/dc2xx1 c 180 81 ... +NOTE: you would normally configure PAM so that the user logged in at +the console is granted ownership of these devices. console.perms(5) +explains how to do this. + The driver supports multiple device nodes. The USB framework supports -a maximum of sixteen device nodes (up to minor device number 96), though -by default fewer devices are available. +a maximum of sixteen device nodes (up to minor device number 96). -When you plug in one camera, it will use the first device node (kodak00 +When you plug in one camera, it will use the first device node (dc2xx0 in the example above). A second camera will use the second device node, and so on. @@ -69,18 +64,22 @@ itself up correctly. - You should see an entry in /proc/bus/usb/drivers for "dc2xx", - if you enabled USB /proc support. + if you enabled USB /proc support and correctly mounted the + usbdevfs on /proc/bus/usb. Second: when you connect your camera to the computer, does it get recognized by the driver? (Make sure the camera is powered on!) - if you've got /proc/bus/usb/devices, you should see an entry something like this. The "ProdID" may be different if you didn't - plug in a DC-240, but the "Driver=dc2xx" had better be there. + plug in a DC-240, as may the strings presented, but "Driver=dc2xx" + had better be there. T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 MxCh= 0 D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Vendor=040a ProdID=0120 Rev= 1.08 + S: Manufacturer=Eastman Kodak Company + S: Product=KODAK DC240 Zoom Digital Camera C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms @@ -90,13 +89,12 @@ Manufacturer: Eastman Kodak Company Product: KODAK DC240 Zoom Digital Camera - Serial Number: ? dc2xx.c: USB Camera #0 connected Third: (optional) can you use gPhoto to talk to the camera? - - When you configure your camera, tell it to use "/dev/kodak00" (or - whatever name you used). Right now, gPhoto emits a diagnostic + - When you configure your camera, tell it to use "/dev/usb/dc2xx0" + (or whatever name you used). Right now, gPhoto emits a diagnostic message (non-GUI) saying that it since it didn't act like a TTY, it's assuming it's got a USB connection. diff -u --recursive --new-file v2.3.99-pre5/linux/Documentation/video4linux/README.cpia linux/Documentation/video4linux/README.cpia --- v2.3.99-pre5/linux/Documentation/video4linux/README.cpia Tue Apr 11 15:09:11 2000 +++ linux/Documentation/video4linux/README.cpia Thu Apr 13 09:25:44 2000 @@ -51,12 +51,12 @@ CONFIG_VIDEO_CPIA=m CONFIG_VIDEO_CPIA_PP=m -For autoloading of all those modules you need to tell kerneld some -stuff. Add the following line to your kerneld config-file +For autoloading of all those modules you need to tell modutils some +stuff. Add the following line to your modutils config-file (e.g. /etc/modules.conf or wherever your distribution does store that stuff): -options parport_pc dma=3 irq=7 +options parport_pc io=0x378 irq=7 dma=3 alias char-major-81 cpia_pp The first line tells the dma/irq channels to use. Those _must_ match diff -u --recursive --new-file v2.3.99-pre5/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.99-pre5/linux/MAINTAINERS Tue Apr 11 15:09:11 2000 +++ linux/MAINTAINERS Tue Apr 25 17:38:33 2000 @@ -50,7 +50,7 @@ Maintainers List (try to look for most precise areas first) Note: For the hard of thinking, this list is meant to remain in alphabetical -order. If you could add yourselves to it in alphabetical order that would +order. If you could add yourselves to it in alphabetical order that would be so much easier [Ed] P: Person @@ -147,7 +147,7 @@ ARM PORT P: Russell King M: linux@arm.linux.org.uk -L: linux-arm@vger.rutgers.edu +L: linux-arm-kernel@lists.arm.linux.org.uk W: http://www.arm.linux.org.uk/ S: Maintained @@ -205,7 +205,7 @@ COMPUTONE INTELLIPORT MULTIPORT CARD P: Doug McNash P: Michael H. Warfield -M: Doug McNash +M: Doug McNash M: Michael H. Warfield W: http://www.computone.com/ W: http://www.wittsend.com/computone.html @@ -340,6 +340,13 @@ M: saw@saw.sw.com.sg S: Maintained +EMU10K1 SOUND DRIVER +P: Rui Sousa +M: rsousa@grad.physics.sunysb.edu +L: emu10k1-devel@opensource.creative.com +W: http://opensource.creative.com/ +S: Maintained + ETHEREXPRESS-16 NETWORK DRIVER P: Philip Blundell M: Philip.Blundell@pobox.com @@ -474,9 +481,11 @@ IDE DRIVER [GENERAL] P: Andre Hedrick +M: andre@linux-ide.org M: andre@suse.com L: linux-kernel@vger.rutgers.edu -W: http://linux.kernel.org/pub/linux/kernel/people/hedrick/ +W: http://www.kernel.org/pub/linux/kernel/people/hedrick/ +W: http://www.linux-ide.org/ S: Supported IDE/ATAPI CDROM DRIVER @@ -590,6 +599,12 @@ W: http://csua.berkeley.edu/~gam3/knfsd S: Maintained +LANMEDIA WAN CARD DRIVER +P: Andrew Stanley-Jones +M: asj@lanmedia.com +W: http://www.lanmedia.com/ +S: Supported + LAPB module P: Henner Eisen M: eis@baty.hanse.de @@ -611,9 +626,8 @@ MAESTRO PCI SOUND DRIVER P: Zach Brown -M: zab@redhat.com -W: http://people.redhat.com/zab/maestro/ -S: Supported +M: zab@zabbo.net +S: Odd Fixes M68K P: Jes Sorensen @@ -969,7 +983,7 @@ P: Jakub Jelinek M: jj@sunsite.ms.mff.cuni.cz P: Anton Blanchard -M: anton@progsoc.uts.edu.au +M: anton@linuxcare.com L: sparclinux@vger.rutgers.edu L: ultralinux@vger.rutgers.edu W: http://ultra.linux.cz diff -u --recursive --new-file v2.3.99-pre5/linux/Makefile linux/Makefile --- v2.3.99-pre5/linux/Makefile Wed Apr 12 10:02:34 2000 +++ linux/Makefile Mon Apr 24 15:17:07 2000 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 3 SUBLEVEL = 99 -EXTRAVERSION = -pre5 +EXTRAVERSION = -pre6 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -33,7 +33,6 @@ STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump -MAKE = make MAKEFILES = $(TOPDIR)/.config GENKSYMS = /sbin/genksyms MODFLAGS = -DMODULE @@ -342,6 +341,10 @@ if [ -f PCMCIA_SCSI_MODULES ]; then inst_mod PCMCIA_SCSI_MODULES pcmcia; fi; \ \ ls -1 -U *.o | sort > $$MODLIB/.allmods; \ + if [ -f $$MODLIB/net/3c59x.o ]; then \ + mkdir -p $$MODLIB/pcmcia; \ + ln -nfs ../net/3c59x.o $$MODLIB/pcmcia/3c575_cb.o; \ + MODULES="$$MODULES 3c575_cb.o"; fi; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \ if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \ rm -f $$MODLIB/.misc $$MODLIB/.allmods; \ @@ -370,6 +373,7 @@ rm -f drivers/char/conmakehash rm -f drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist rm -f drivers/sound/bin2hex drivers/sound/hex2hex + rm -f drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2} rm -f net/khttpd/make_times_h rm -f net/khttpd/times.h rm -f submenu* @@ -388,6 +392,7 @@ rm -f drivers/sound/msndperm.c rm -f drivers/sound/pndsperm.c rm -f drivers/sound/pndspini.c + rm -f drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw rm -f .version .config* config.in config.old rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog @@ -410,14 +415,15 @@ sync sgmldocs: + chmod 755 $(TOPDIR)/scripts/docgen + chmod 755 $(TOPDIR)/scripts/gen-all-syms + chmod 755 $(TOPDIR)/scripts/kernel-doc $(MAKE) -C $(TOPDIR)/Documentation/DocBook books psdocs: sgmldocs - $(MAKE) -C scripts docproc $(MAKE) -C Documentation/DocBook ps pdfdocs: sgmldocs - $(MAKE) -C scripts docproc $(MAKE) -C Documentation/DocBook pdf sums: diff -u --recursive --new-file v2.3.99-pre5/linux/REPORTING-BUGS linux/REPORTING-BUGS --- v2.3.99-pre5/linux/REPORTING-BUGS Thu Apr 29 11:53:41 1999 +++ linux/REPORTING-BUGS Wed Apr 12 09:16:31 2000 @@ -46,8 +46,10 @@ [7.1.] Software (add the output of the ver_linux script here) [7.2.] Processor information (from /proc/cpuinfo): [7.3.] Module information (from /proc/modules): -[7.4.] SCSI information (from /proc/scsi/scsi) -[7.5.] Other information that might be relevant to the problem +[7.4.] Loaded driver and hardware information (/proc/ioports, /proc/iomem) +[7.5.] PCI information ('lspci -vvv' as root) +[7.6.] SCSI information (from /proc/scsi/scsi) +[7.7.] Other information that might be relevant to the problem (please look in /proc and include all information that you think to be relevant): [X.] Other notes, patches, fixes, workarounds: diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.3.99-pre5/linux/arch/alpha/kernel/alpha_ksyms.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/alpha_ksyms.c Mon Apr 24 13:39:34 2000 @@ -174,7 +174,7 @@ * SMP-specific symbols. */ -#ifdef __SMP__ +#ifdef CONFIG_SMP EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(flush_tlb_all); @@ -199,10 +199,10 @@ EXPORT_SYMBOL(write_lock); EXPORT_SYMBOL(read_lock); #endif -#else /* __SMP__ */ +#else /* CONFIG_SMP */ EXPORT_SYMBOL(__local_bh_count); EXPORT_SYMBOL(__local_irq_count); -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ EXPORT_SYMBOL(rtc_lock); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.3.99-pre5/linux/arch/alpha/kernel/entry.S Mon Mar 27 08:08:21 2000 +++ linux/arch/alpha/kernel/entry.S Mon Apr 24 13:39:34 2000 @@ -4,6 +4,7 @@ * kernel entry-points */ +#include #include #define SIGCHLD 20 @@ -706,7 +707,7 @@ br restore_all .end entSys -#ifdef __SMP__ +#ifdef CONFIG_SMP .globl ret_from_smp_fork .align 3 .ent ret_from_smp_fork @@ -715,7 +716,7 @@ mov $17,$16 jsr $31,schedule_tail .end ret_from_smp_fork -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ .align 3 .ent reschedule diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S --- v2.3.99-pre5/linux/arch/alpha/kernel/head.S Wed Dec 15 10:43:16 1999 +++ linux/arch/alpha/kernel/head.S Mon Apr 24 13:39:34 2000 @@ -7,6 +7,7 @@ * the kernel global pointer and jump to the kernel entry-point. */ +#include #include .globl swapper_pg_dir @@ -30,7 +31,7 @@ call_pal PAL_halt .end __start -#ifdef __SMP__ +#ifdef CONFIG_SMP .align 3 .globl __smp_callin .ent __smp_callin @@ -52,7 +53,7 @@ jsr $26,smp_callin call_pal PAL_halt .end __smp_callin -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ # # The following two functions are needed for supporting SRM PALcode diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.3.99-pre5/linux/arch/alpha/kernel/irq.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/irq.c Thu Apr 13 17:06:00 2000 @@ -373,7 +373,7 @@ #ifdef CONFIG_SMP /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); entry->nlink = 1; entry->data = (void *)(long)irq; @@ -397,7 +397,7 @@ #ifdef CONFIG_SMP /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir); + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); entry->nlink = 1; entry->data = (void *)&prof_cpu_mask; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c --- v2.3.99-pre5/linux/arch/alpha/kernel/pci.c Mon Mar 27 08:08:21 2000 +++ linux/arch/alpha/kernel/pci.c Tue Apr 25 17:56:06 2000 @@ -110,10 +110,15 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size) { struct pci_dev *dev = data; + struct pci_controler *hose = dev->sysdata; unsigned long alignto; unsigned long start = res->start; if (res->flags & IORESOURCE_IO) { + /* Make sure we start at our min on all hoses */ + if (start - hose->io_space->start < PCIBIOS_MIN_IO) + start = PCIBIOS_MIN_IO + hose->io_space->start; + /* * Aligning to 0x800 rather than the minimum base of * 0x400 is an attempt to avoid having devices in @@ -121,11 +126,18 @@ * probes for EISA cards. * * Adaptecs, especially, resent such intrusions. + * + * The de4x5 driver has the eisa probe conditionalized + * out for Alpha, so lower the minimum base back to 0x400. */ - alignto = MAX(0x800, size); + alignto = MAX(0x400, size); start = ALIGN(start, alignto); } else if (res->flags & IORESOURCE_MEM) { + /* Make sure we start at our min on all hoses */ + if (start - hose->mem_space->start < PCIBIOS_MIN_MEM) + start = PCIBIOS_MIN_MEM + hose->io_space->start; + /* * The following holds at least for the Low Cost * Alpha implementation of the PCI interface: @@ -230,7 +242,7 @@ pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus) { /* Update device resources. */ - + struct pci_controler *hose = (struct pci_controler *)bus->sysdata; int i; for (i = 0; i < PCI_NUM_RESOURCES; i++) { @@ -238,10 +250,10 @@ continue; if (dev->resource[i].flags & IORESOURCE_IO) pcibios_fixup_resource(&dev->resource[i], - bus->resource[0]); + hose->io_space); else if (dev->resource[i].flags & IORESOURCE_MEM) pcibios_fixup_resource(&dev->resource[i], - bus->resource[1]); + hose->mem_space); } pcibios_assign_special(dev); } @@ -257,6 +269,12 @@ bus->resource[0] = hose->io_space; bus->resource[1] = hose->mem_space; + /* If this is a bridge, get the current bases */ + if (bus->self) { + pci_read_bridge_bases(bus); + pcibios_fixup_device_resources(bus->self, bus->parent); + } + for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { struct pci_dev *dev = pci_dev_b(ln); if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) @@ -268,10 +286,25 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *res, int resource) { + struct pci_controler *hose = dev->sysdata; int where; u32 reg; + if (resource < PCI_ROM_RESOURCE) where = PCI_BASE_ADDRESS_0 + (resource * 4); + else if (resource == PCI_ROM_RESOURCE) + where = dev->rom_base_reg; + else { + /* Don't update non-standard resources here */ + return; + } + + /* Point root at the hose root */ + if (res->flags & IORESOURCE_IO) + root = hose->io_space; + if (res->flags & IORESOURCE_MEM) + root = hose->mem_space; + reg = (res->start - root->start) | (res->flags & 0xf); pci_write_config_dword(dev, where, reg); if ((res->flags & (PCI_BASE_ADDRESS_SPACE @@ -319,10 +352,12 @@ pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) { - ranges->io_start -= bus->resource[0]->start; - ranges->io_end -= bus->resource[0]->start; - ranges->mem_start -= bus->resource[1]->start; - ranges->mem_end -= bus->resource[1]->start; + struct pci_controler *hose = (struct pci_controler *)bus->sysdata; + + ranges->io_start -= hose->io_space->start; + ranges->io_end -= hose->io_space->start; + ranges->mem_start -= hose->mem_space->start; + ranges->mem_end -= hose->mem_space->start; } int @@ -332,6 +367,94 @@ return 0; } +#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +static void __init +pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer) +{ + struct pbus_set_ranges_data inner; + struct pci_dev *dev; + struct pci_dev *bridge = bus->self; + struct pci_controler *hose = bus->sysdata; + struct list_head *ln; + + if (!bridge) + return; /* host bridge, nothing to do */ + + /* set reasonable default locations for pcibios_align_resource */ + inner.io_start = hose->io_space->start + PCIBIOS_MIN_IO; + inner.mem_start = hose->mem_space->start + PCIBIOS_MIN_MEM; + inner.io_end = inner.io_start; + inner.mem_end = inner.mem_start; + + /* Collect information about how our direct children are layed out. */ + for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { + int i; + dev = pci_dev_b(ln); + + /* Skip bridges for now */ + if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) + continue; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource res; + unsigned long size; + + memcpy(&res, &dev->resource[i], sizeof(res)); + size = res.end - res.start + 1; + + if (res.flags & IORESOURCE_IO) { + res.start = inner.io_end; + pcibios_align_resource(dev, &res, size); + inner.io_end = res.start + size; + } else if (res.flags & IORESOURCE_MEM) { + res.start = inner.mem_end; + pcibios_align_resource(dev, &res, size); + inner.mem_end = res.start + size; + } + } + } + + /* And for all of the subordinate busses. */ + for (ln=bus->children.next; ln != &bus->children; ln=ln->next) + pcibios_size_bridge(pci_bus_b(ln), &inner); + + /* turn the ending locations into sizes (subtract start) */ + inner.io_end -= inner.io_start; + inner.mem_end -= inner.mem_start; + + /* Align the sizes up by bridge rules */ + inner.io_end = ROUND_UP(inner.io_end, 4*1024); + inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024); + + /* Adjust the bridge's allocation requirements */ + bridge->resource[0].end = bridge->resource[0].start + inner.io_end; + bridge->resource[1].end = bridge->resource[1].start + inner.mem_end; + + /* adjust parent's resource requirements */ + if (outer) { + outer->io_end = ROUND_UP(outer->io_end, 4*1024); + outer->io_end += inner.io_end; + + outer->mem_end = ROUND_UP(outer->mem_end, 1*1024*1024); + outer->mem_end += inner.mem_end; + } +} + +#undef ROUND_UP + +static void __init +pcibios_size_bridges(void) +{ + struct list_head *ln1, *ln2; + + for(ln1=pci_root_buses.next; ln1 != &pci_root_buses; ln1=ln1->next) + for(ln2 = pci_bus_b(ln1)->children.next; + ln2 != &pci_bus_b(ln1)->children; + ln2 = ln2->next) + pcibios_size_bridge(pci_bus_b(ln2), NULL); +} + void __init common_init_pci(void) { @@ -349,6 +472,7 @@ next_busno += 1; } + pcibios_size_bridges(); pci_assign_unassigned_resources(); pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq); pci_set_bus_ranges(); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.3.99-pre5/linux/arch/alpha/kernel/process.c Mon Mar 27 08:08:21 2000 +++ linux/arch/alpha/kernel/process.c Mon Apr 24 13:39:34 2000 @@ -116,7 +116,7 @@ /* Clear reason to "default"; clear "bootstrap in progress". */ flags &= ~0x00ff0001UL; -#ifdef __SMP__ +#ifdef CONFIG_SMP /* Secondaries halt here. */ if (cpuid != boot_cpuid) { flags |= 0x00040000UL; /* "remain halted" */ @@ -145,7 +145,7 @@ } *pflags = flags; -#ifdef __SMP__ +#ifdef CONFIG_SMP /* Wait for the secondaries to halt. */ clear_bit(boot_cpuid, &cpu_present_mask); while (cpu_present_mask) @@ -184,7 +184,7 @@ struct halt_info args; args.mode = mode; args.restart_cmd = restart_cmd; -#ifdef __SMP__ +#ifdef CONFIG_SMP smp_call_function(common_shutdown_1, &args, 1, 0); #endif common_shutdown_1(&args); @@ -321,7 +321,7 @@ stack = ((struct switch_stack *) regs) - 1; childstack = ((struct switch_stack *) childregs) - 1; *childstack = *stack; -#ifdef __SMP__ +#ifdef CONFIG_SMP childstack->r26 = (unsigned long) ret_from_smp_fork; #else childstack->r26 = (unsigned long) ret_from_sys_call; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h --- v2.3.99-pre5/linux/arch/alpha/kernel/proto.h Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/proto.h Mon Apr 24 13:39:34 2000 @@ -1,3 +1,4 @@ +#include /* Prototypes of functions used across modules here in this directory. */ #define vucp volatile unsigned char * @@ -132,7 +133,7 @@ /* irq.c */ -#ifdef __SMP__ +#ifdef CONFIG_SMP #define mcheck_expected(cpu) (cpu_data[cpu].mcheck_expected) #define mcheck_taken(cpu) (cpu_data[cpu].mcheck_taken) #define mcheck_extra(cpu) (cpu_data[cpu].mcheck_extra) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.3.99-pre5/linux/arch/alpha/kernel/setup.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/setup.c Mon Apr 24 13:39:34 2000 @@ -484,7 +484,7 @@ * Identify the flock of penguins. */ -#ifdef __SMP__ +#ifdef CONFIG_SMP setup_smp(); #endif paging_init(); @@ -930,7 +930,7 @@ unaligned[1].count, unaligned[1].pc, unaligned[1].va, platform_string(), nr_processors); -#ifdef __SMP__ +#ifdef CONFIG_SMP len += smp_info(buffer+len); #endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.3.99-pre5/linux/arch/alpha/kernel/time.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/time.c Mon Apr 24 13:39:34 2000 @@ -22,6 +22,7 @@ * fixed algorithm in do_gettimeofday() for calculating the precise time * from processor cycle counter (now taking lost_ticks into account) */ +#include #include #include #include @@ -90,7 +91,7 @@ __u32 now; long nticks; -#ifndef __SMP__ +#ifndef CONFIG_SMP /* Not SMP, do kernel PC profiling here. */ if (!user_mode(regs)) alpha_do_profile(regs->pc); @@ -315,7 +316,7 @@ read_unlock_irqrestore(&xtime_lock, flags); -#ifdef __SMP__ +#ifdef CONFIG_SMP /* Until and unless we figure out how to get cpu cycle counters in sync and keep them there, we can't use the rpcc tricks. */ delta_usec = lost * (1000000 / HZ); @@ -361,7 +362,7 @@ must be subtracted out here to keep a coherent view of the time. Without this, a full-tick error is possible. */ -#ifdef __SMP__ +#ifdef CONFIG_SMP delta_usec = lost_ticks * (1000000 / HZ); #else delta_usec = rpcc() - state.last_time; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.3.99-pre5/linux/arch/alpha/kernel/traps.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/traps.c Mon Apr 24 13:39:34 2000 @@ -95,7 +95,7 @@ { if (regs->ps & 8) return; -#ifdef __SMP__ +#ifdef CONFIG_SMP printk("CPU %d ", hard_smp_processor_id()); #endif printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c --- v2.3.99-pre5/linux/arch/alpha/mm/fault.c Thu Mar 2 14:36:22 2000 +++ linux/arch/alpha/mm/fault.c Mon Apr 24 15:49:21 2000 @@ -4,6 +4,7 @@ * Copyright (C) 1995 Linus Torvalds */ +#include #include #include #include @@ -34,7 +35,7 @@ * Force a new ASN for a task. */ -#ifndef __SMP__ +#ifndef CONFIG_SMP unsigned long last_asn = ASN_FIRST_VERSION; #endif @@ -139,7 +140,7 @@ * make sure we exit gracefully rather than endlessly redo * the fault. */ - fault = handle_mm_fault(current, vma, address, cause > 0); + fault = handle_mm_fault(mm, vma, address, cause > 0); up(&mm->mmap_sem); if (fault < 0) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.3.99-pre5/linux/arch/alpha/mm/init.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/mm/init.c Mon Apr 24 13:39:34 2000 @@ -37,7 +37,7 @@ struct thread_struct original_pcb; -#ifndef __SMP__ +#ifndef CONFIG_SMP struct pgtable_cache_struct quicklists; #endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S --- v2.3.99-pre5/linux/arch/arm/boot/compressed/head.S Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/boot/compressed/head.S Tue Apr 25 16:54:38 2000 @@ -6,6 +6,66 @@ #include .section ".start", #alloc, #execinstr + +/* + * Debugging stuff + */ + .macro kputc,val + mov r0, \val + bl putc + .endm + + .macro kphex,val,len + mov r0, \val + mov r1, #\len + bl phex + .endm + + .macro debug_reloc_start +#ifdef DEBUG + kputc #'\n' + kphex r6, 8 + kputc #':' + kphex r5, 8 + kputc #'-' + kphex r8, 8 + kputc #'>' + kphex r4, 8 + kputc #'\n' +#endif + .endm + + .macro debug_reloc_end +#ifdef DEBUG + mov r8, r0 + kphex r5, 8 + kputc #'-' + kphex r8, 8 + kputc #'\n' + mov r0, r4 + bl memdump +#endif + .endm + +#if 0 + .macro loadsp, rb + mov \rb, #0x7c000000 + .endm + + .macro writeb, rb + strb \rb, [r3, #0x3f8] + .endm +#else + .macro loadsp, rb + mov \rb, #0x03000000 + orr \rb, \rb, #0x00010000 + .endm + + .macro writeb, rb + strb \rb, [r3, #0x3f8 << 2] + .endm +#endif + /* * sort out different calling conventions */ @@ -42,6 +102,8 @@ cmp r2, r3 blt 1b + bl cache_on + mov r1, sp @ malloc space above stack add r2, sp, #0x10000 @ 64k max @@ -77,15 +139,87 @@ cmp r2, r3 blt 1b - eor r1, r6, #0x44 << 24 @ SA-110 or SA-1100? - eor r1, r1, #0x01 << 16 - eor r1, r1, #0xa1 << 8 - movs r1, r1, lsr #5 - mcreq p15, 0, r1, c7, c7, 0 @ flush I & D-cache - mcreq p15, 0, r1, c7, c10, 4 @ drain WB + bl cache_clean_flush add pc, r5, r0 @ call relocation code /* + * Page table physical address list + */ + .align 5 + .type pgtable,#object +pgtable: .word 0x00004000 @ 0x00 + .word 0x10004000 @ 0x01 + .word 0x00000000 @ 0x02 + .word 0x40004000 @ 0x03 + .word 0x00004000 @ 0x04 + .word 0x00004000 @ 0x05 + .word 0x00004000 @ 0x06 + .word 0x80004000 @ 0x07 + .word 0x00004000 @ 0x08 + .word 0x00000000 @ 0x09 + .word 0x00000000 @ 0x0a + .word 0x00000000 @ 0x0b + .word 0x00000000 @ 0x0c + .word 0x00000000 @ 0x0d + .word 0x10004000 @ 0x0e + .word 0x08004000 @ 0x0f + .word 0xc0004000 @ 0x10 + .size pgtable,. - pgtable +1: + + .type LC0, #object +LC0: .word __bss_start + .word _end + .word _load_addr + .word _start + .word user_stack+4096 + .size LC0, . - LC0 + + .align 5 +cache_on: ldr r1, proc_sa110_type + eor r1, r1, r6 + movs r1, r1, lsr #5 + movne pc, lr + cmp r7, #(1b - pgtable) >> 2 + movge pc, lr + adr r3, pgtable + ldr r3, [r3, r7, lsl #2] + teq r3, #0 + moveq pc, lr +/* + * Initialise the page tables + */ + mov r0, r3 + mov r8, r0, lsr #18 + mov r8, r8, lsl #18 @ start of RAM + add r9, r8, #0x20000000 @ the maximum RAM size + mov r1, #0x12 + orr r1, r1, #3 << 10 + add r2, r3, #16384 +1: cmp r1, r8 @ if virt > start of RAM + orrge r1, r1, #0x0c @ set cacheable, bufferable + cmp r1, r9 @ if virt > end of RAM + bicge r1, r1, #0x0c @ clear cacheable, bufferable + str r1, [r0], #4 @ 1:1 mapping + add r1, r1, #1048576 + teq r0, r2 + bne 1b + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c8, c7 @ flush I,D TLBs + mcr p15, 0, r3, c2, c0 @ load page table pointer + mov r0, #-1 + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 + orr r0, r0, #0x1000 @ I-cache enable +#ifndef DEBUG + orr r0, r0, #0x003d @ Write buffer, mmu +#endif + mcr p15, 0, r0, c1, c0 + mov pc, lr + +/* * r0 = decompressed kernel length * r1-r3 = unused * r4 = kernel execution address @@ -94,87 +228,68 @@ * r7 = architecture ID * r8-r14 = unused */ + .align 5 reloc_start: add r8, r5, r0 -#if 0 - mov r0, #'\n' - bl putc - mov r0, r6 - mov r1, #8 - bl phex - mov r0, #':' - bl putc - mov r0, r5 - mov r1, #8 - bl phex - mov r0, #'-' - bl putc - mov r0, r8 - mov r1, #8 - bl phex - mov r0, #'>' - bl putc - mov r0, r4 - mov r1, #8 - bl phex - mov r0, #'\n' - bl putc -#endif - mov r0, r8 + debug_reloc_start mov r1, r4 1: .rept 4 - ldmia r5!, {r2, r3, r8 - r13} @ relocate kernel - stmia r1!, {r2, r3, r8 - r13} + ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel + stmia r1!, {r0, r2, r3, r9 - r13} .endr - cmp r5, r0 + cmp r5, r8 blt 1b -#if 0 - mov r8, r0 - mov r0, r5 - mov r1, #8 - bl phex - mov r0, #'-' - bl putc - mov r0, r8 - mov r1, #8 - bl phex - mov r0, #'\n' - bl putc - mov r0, r4 - bl memdump -#endif - eor r0, r6, #0x44 << 24 @ SA-110 or SA-1100? - eor r0, r0, #0x01 << 16 - eor r0, r0, #0xa1 << 8 - movs r0, r0, lsr #5 - mcreq p15, 0, r0, c7, c7, 0 @ flush I cache - mcreq p15, 0, r1, c7, c10, 4 @ drain WB + debug_reloc_end -call_kernel: mov r0, #0 +call_kernel: bl cache_clean_flush + bl cache_off + mov r0, #0 mov r1, r7 @ restore architecture number mov pc, r4 @ call kernel -phexbuf: .space 12 + .type proc_sa110_type,#object +proc_sa110_type: + .word 0x4401a100 + .size proc_sa110_type, . - proc_sa110_type -#if 0 - .macro loadsp, rb - mov \rb, #0x7c000000 - .endm +/* + * Turn off StrongARM cache and MMU + */ + .align 5 +cache_off: ldr r1, proc_sa110_type + eor r1, r1, r6 + movs r1, r1, lsr #5 + movne pc, lr + mrc p15, 0, r0, c1, c0 + bic r0, r0, #0x000d + mcr p15, 0, r0, c1, c0 + mov pc, lr - .macro writeb, rb - strb \rb, [r3, #0x3f8] - .endm -#else - .macro loadsp, rb - mov \rb, #0x03000000 - orr \rb, \rb, #0x00010000 - .endm +/* + * Clean and flush the cache to maintain consistency. + */ + .align 5 +cache_clean_flush: + ldr r1, proc_sa110_type @ SA-110 or SA-1100? + eor r1, r1, r6 + movs r1, r1, lsr #5 + movne pc, lr - .macro writeb, rb - strb \rb, [r3, #0x3f8 << 2] - .endm -#endif + bic r1, pc, #31 + add r2, r1, #32768 +1: ldr r12, [r1], #32 + teq r1, r2 + bne 1b + + mcr p15, 0, r1, c7, c7, 0 @ flush I cache + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +#ifdef DEBUG + .type phexbuf,#object +phexbuf: .space 12 + .size phexbuf, . - phexbuf phex: adr r3, phexbuf mov r2, #0 @@ -240,14 +355,10 @@ cmp r11, #64 blt 2b mov pc, r10 +#endif + reloc_end: -LC0: .word __bss_start - .word _end - .word _load_addr - .word _start - .word user_stack+4096 .align - .section ".stack" user_stack: .space 4096 diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.3.99-pre5/linux/arch/arm/config.in Tue Apr 11 15:09:11 2000 +++ linux/arch/arm/config.in Tue Apr 25 16:54:38 2000 @@ -137,9 +137,6 @@ define_bool CONFIG_ISA_DMA n fi -define_bool CONFIG_SBUS n -define_bool CONFIG_PCMCIA n - if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then bool 'Kernel-mode alignment trap handler' CONFIG_ALIGNMENT_TRAP fi @@ -221,7 +218,6 @@ fi fi fi - #source drivers/misc/Config.in diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/def-configs/ebsa110 linux/arch/arm/def-configs/ebsa110 --- v2.3.99-pre5/linux/arch/arm/def-configs/ebsa110 Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/def-configs/ebsa110 Tue Apr 25 16:54:38 2000 @@ -2,6 +2,12 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +CONFIG_UID16=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y # # System and processor type @@ -12,20 +18,13 @@ CONFIG_ARCH_EBSA110=y # CONFIG_FOOTBRIDGE is not set # CONFIG_ARCH_ACORN is not set -# CONFIG_ISA_DMA is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set -# CONFIG_CPU_ARM2 is not set -# CONFIG_CPU_ARM3 is not set -# CONFIG_CPU_ARM6 is not set -# CONFIG_CPU_ARM7 is not set +CONFIG_CPU_32v4=y CONFIG_CPU_SA110=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -# CONFIG_TEXT_SECTIONS is not set +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set # # Loadable module support @@ -42,29 +41,52 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_NWFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y -CONFIG_BINFMT_ELF=m +CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Parallel port support +# CONFIG_PARPORT=y CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_SUPERIO=y +# CONFIG_PARPORT_ARC is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y CONFIG_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8" CONFIG_LEDS=y # -# Plug and Play support +# I2O device support # -# CONFIG_PNP is not set +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set # -# Block devices +# Plug and Play configuration # -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_IDE is not set +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # -# Please see Documentation/ide.txt for help/info on IDE drives +# Block devices # -# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set # # Additional Block Devices @@ -74,10 +96,6 @@ # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y # CONFIG_BLK_DEV_INITRD is not set -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_HD is not set # # Character devices @@ -94,29 +112,39 @@ # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_UNIX98_PTYS is not set CONFIG_PRINTER=m -CONFIG_PRINTER_READBACK=y -CONFIG_MOUSE=y +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +# CONFIG_I2C is not set # # Mice # -# CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_BUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set +CONFIG_MOUSE=y # CONFIG_PSMOUSE is not set # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set -CONFIG_WATCHDOG=y # # Watchdog Cards # +CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set # CONFIG_WDT is not set CONFIG_SOFT_WATCHDOG=y # CONFIG_PCWATCHDOG is not set # CONFIG_ACQUIRE_WDT is not set +# CONFIG_MIXCOMWD is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set @@ -124,64 +152,92 @@ # Video For Linux # # CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK 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_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set # # Networking options # CONFIG_PACKET=m -# CONFIG_NETLINK is not set -CONFIG_FIREWALL=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_TOS is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_ROUTE_LARGE_TABLES is not set CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -CONFIG_IP_FIREWALL=y -CONFIG_IP_ALWAYS_DEFRAG=y -# CONFIG_IP_TRANSPARENT_PROXY is not set -CONFIG_IP_MASQUERADE=y - -# -# Protocol-specific masquerading support will be built as modules. -# -CONFIG_IP_MASQUERADE_ICMP=y - -# -# Protocol-specific masquerading support will be built as modules. -# -# CONFIG_IP_MASQUERADE_MOD is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +# CONFIG_ARPD is not set CONFIG_SYN_COOKIES=y # # (it is safe to leave these untouched) # -# CONFIG_INET_RARP is not set # CONFIG_SKB_LARGE is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=y +CONFIG_IP_NF_FTP=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_LIMIT=y +# CONFIG_IP_NF_MATCH_MAC is not set +CONFIG_IP_NF_MATCH_MARK=y +CONFIG_IP_NF_MATCH_MULTIPORT=y +CONFIG_IP_NF_MATCH_TOS=y +CONFIG_IP_NF_MATCH_STATE=y +# CONFIG_IP_NF_MATCH_UNCLEAN is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_MIRROR is not set +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_TARGET_TOS=y +CONFIG_IP_NF_TARGET_MARK=y +CONFIG_IP_NF_TARGET_LOG=y # CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set # # # # CONFIG_IPX is not set # CONFIG_ATALK is not set +# CONFIG_DECNET is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set @@ -190,7 +246,6 @@ # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set # # QoS and/or fair queueing @@ -203,7 +258,7 @@ # CONFIG_HAMRADIO is not set # -# IrDA subsystem support +# IrDA (infrared) support # # CONFIG_IRDA is not set @@ -211,37 +266,72 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set +CONFIG_DUMMY=m +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y CONFIG_ARM_AM79C961A=y # 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_RTL8139 is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set +# CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set # CONFIG_PLIP is not set CONFIG_PPP=y +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_SLIP is not set # -# CCP compressors for PPP are only built as modules. +# Wireless LAN (non-hamradio) # -# CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# # CONFIG_TR is not set -# CONFIG_SHAPER is not set -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA 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 + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set # # SCSI support @@ -249,27 +339,35 @@ # CONFIG_SCSI is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set -CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_BFS_FS 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_CRAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set CONFIG_MINIX_FS=y # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set # CONFIG_EXT2_FS is not set # CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set # @@ -287,22 +385,28 @@ # # 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_SGI_PARTITION is not set # CONFIG_SUN_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ACORN_PARTITION is not set # CONFIG_NLS is not set # +# USB support +# +# CONFIG_USB is not set + +# # Kernel hacking # -CONFIG_FRAME_POINTER=y +# CONFIG_FRAME_POINTER is not set CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set # CONFIG_MAGIC_SYSRQ is not set -# CONFIG_ARTHUR is not set # CONFIG_DEBUG_LL is not set diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/defconfig linux/arch/arm/defconfig --- v2.3.99-pre5/linux/arch/arm/defconfig Tue Apr 11 15:09:12 2000 +++ linux/arch/arm/defconfig Thu Apr 13 22:54:26 2000 @@ -536,8 +536,8 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC6210 is not set -# CONFIG_AEC6210_TUNING 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_AMD7409 is not set diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/arch.c linux/arch/arm/kernel/arch.c --- v2.3.99-pre5/linux/arch/arm/kernel/arch.c Tue Apr 11 15:09:12 2000 +++ linux/arch/arm/kernel/arch.c Tue Apr 25 16:54:38 2000 @@ -1,45 +1,39 @@ /* * linux/arch/arm/kernel/arch.c * - * Architecture specifics + * Architecture specific fixups. This is where any + * parameters in the params struct are fixed up, or + * any additional architecture specific information + * is pulled from the params struct. */ #include #include #include +#include #include #include #include #include "arch.h" -extern unsigned int system_rev; -extern unsigned int system_serial_low; -extern unsigned int system_serial_high; - unsigned int vram_size; -#ifdef CONFIG_ARCH_ACORN -unsigned int memc_ctrl_reg; -unsigned int number_mfm_drives; -#endif extern void setup_initrd(unsigned int start, unsigned int size); extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); -/* - * Architecture specific fixups. This is where any - * parameters in the params struct are fixed up, or - * any additional architecture specific information - * is pulled from the params struct. - */ +#ifdef CONFIG_ARCH_ACORN + +unsigned int memc_ctrl_reg; +unsigned int number_mfm_drives; + static void __init fixup_acorn(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi) { -#ifdef CONFIG_ARCH_ACORN - int i; - if (machine_is_riscpc()) { + int i; + /* * RiscPC can't handle half-word loads and stores */ @@ -69,9 +63,36 @@ } memc_ctrl_reg = params->u1.s.memc_control_reg; number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3; -#endif } +#ifdef CONFIG_ARCH_RPC +MACHINE_START(RISCPC, "Acorn-RiscPC") + MAINTAINER("Russell King") + BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) + BOOT_PARAMS(0x10000100) + DISABLE_PARPORT(0) + DISABLE_PARPORT(1) + FIXUP(fixup_acorn) +MACHINE_END +#endif +#ifdef CONFIG_ARCH_ARC +MACHINE_START(ARCHIMEDES, "Acorn-Archimedes") + MAINTAINER("Dave Gilbert") + BOOT_PARAMS(0x0207c000) + FIXUP(fixup_acorn) +MACHINE_END +#endif +#ifdef CONFIG_ARCH_A5K +MACHINE_START(A5K, "Acorn-A5000") + MAINTAINER("Russell King") + BOOT_PARAMS(0x0207c000) + FIXUP(fixup_acorn) +MACHINE_END +#endif +#endif + +#ifdef CONFIG_ARCH_EBSA285 + static void __init fixup_ebsa285(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi) @@ -82,6 +103,16 @@ ORIG_VIDEO_LINES = params->u1.s.video_num_rows; } +MACHINE_START(EBSA285, "EBSA285") + MAINTAINER("Russell King") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + BOOT_PARAMS(0x00000100) + VIDEO(0x000a0000, 0x000bffff) + FIXUP(fixup_ebsa285) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_NETWINDER /* * Older NeTTroms either do not provide a parameters * page, or they don't supply correct information in @@ -105,6 +136,18 @@ } } +MACHINE_START(NETWINDER, "Rebel-NetWinder") + MAINTAINER("Russell King/Rebel.com") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + BOOT_PARAMS(0x00000100) + VIDEO(0x000a0000, 0x000bffff) + DISABLE_PARPORT(0) + DISABLE_PARPORT(2) + FIXUP(fixup_netwinder) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_CATS /* * CATS uses soft-reboot by default, since * hard reboots fail on early boards. @@ -118,11 +161,20 @@ ORIG_Y = 24; } +MACHINE_START(CATS, "Chalice-CATS") + MAINTAINER("Philip Blundell") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + SOFT_REBOOT + FIXUP(fixup_cats) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_CO285 + static void __init fixup_coebsa285(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi) { -#if 0 extern unsigned long boot_memory_end; extern char boot_command_line[]; @@ -131,242 +183,228 @@ mi->bank[0].size = boot_memory_end; *cmdline = boot_command_line; -#endif } +MACHINE_START(CO285, "co-EBSA285") + MAINTAINER("Mark van Doesburg") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000) + FIXUP(fixup_coebsa285) +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_SA1100 + +extern void select_sa1100_io_desc(void); +#define SET_BANK(__nr,__start,__size) \ + mi->bank[__nr].start = (__start), \ + mi->bank[__nr].size = (__size) static void __init fixup_sa1100(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi) { -#ifdef CONFIG_ARCH_SA1100 - int i; - extern struct mem_desc { - unsigned long phys_start; - unsigned long length; - } mem_desc[]; - extern unsigned int mem_desc_size; - - for( i = 0; i < mem_desc_size; i++ ) { - if( i >= NR_BANKS ) { - printk( __FUNCTION__ - ": mem_desc too large for meminfo structure\n"); - break; - } - mi->bank[i].start = mem_desc[i].phys_start; - mi->bank[i].size = mem_desc[i].length; + select_sa1100_io_desc(); + + if (machine_is_assabet()) { + SET_BANK( 0, 0xc0000000, 32*1024*1024 ); + mi->nr_banks = 1; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( 0xc0800000, 3*1024*1024 ); + } + + else if (machine_is_brutus()) { + SET_BANK( 0, 0xc0000000, 4*1024*1024 ); + SET_BANK( 1, 0xc8000000, 4*1024*1024 ); + SET_BANK( 2, 0xd0000000, 4*1024*1024 ); + SET_BANK( 3, 0xd8000000, 4*1024*1024 ); + mi->nr_banks = 4; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 ); + } + + else if (machine_is_empeg()) { + SET_BANK( 0, 0xc0000000, 4*1024*1024 ); + SET_BANK( 1, 0xc8000000, 4*1024*1024 ); + mi->nr_banks = 2; + + ROOT_DEV = MKDEV( 3, 1 ); /* /dev/hda1 */ + setup_ramdisk( 1, 0, 0, 4096 ); + setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) ); + } + + else if (machine_is_lart()) { + /* + * Note that LART is a special case - it doesn't use physical + * address line A23 on the DRAM, so we effectively have 4 * 8MB + * in two SA1100 banks. + */ + SET_BANK( 0, 0xc0000000, 8*1024*1024 ); + SET_BANK( 1, 0xc1000000, 8*1024*1024 ); + SET_BANK( 2, 0xc8000000, 8*1024*1024 ); + SET_BANK( 3, 0xc9000000, 8*1024*1024 ); + mi->nr_banks = 4; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk(1, 0, 0, 8192); + setup_initrd(0xc0400000, 4*1024*1024); + } + + else if (machine_is_thinclient()) { + SET_BANK( 0, 0xc0000000, 16*1024*1024 ); + mi->nr_banks = 1; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); + } + + else if (machine_is_tifon()) { + SET_BANK( 0, 0xc0000000, 16*1024*1024 ); + SET_BANK( 1, 0xc8000000, 16*1024*1024 ); + mi->nr_banks = 2; + + ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0); + setup_ramdisk(1, 0, 0, 4096); + setup_initrd( 0xd0000000 + 0x1100004, 0x140000 ); + } + + else if (machine_is_victor()) { + SET_BANK( 0, 0xc0000000, 4*1024*1024 ); + mi->nr_banks = 1; + + ROOT_DEV = MKDEV( 60, 2 ); + + /* Get command line parameters passed from the loader (if any) */ + if( *((char*)0xc0000000) ) + strcpy( *cmdline, ((char *)0xc0000000) ); + + /* power off if any problem */ + strcat( *cmdline, " panic=1" ); } - mi->nr_banks = i; -#if defined(CONFIG_SA1100_BRUTUS) - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk( 1, 0, 0, 8192 ); - setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 ); -#elif defined(CONFIG_SA1100_EMPEG) - ROOT_DEV = MKDEV( 3, 1 ); /* /dev/hda1 */ - setup_ramdisk( 1, 0, 0, 4096 ); - setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) ); -#elif defined(CONFIG_SA1100_THINCLIENT) - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk( 1, 0, 0, 8192 ); - setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); -#elif defined(CONFIG_SA1100_TIFON) - ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0); - setup_ramdisk(1, 0, 0, 4096); - setup_initrd( 0xd0000000 + 0x1100004, 0x140000 ); -#elif defined(CONFIG_SA1100_VICTOR) - ROOT_DEV = MKDEV( 60, 2 ); - - /* Get command line parameters passed from the loader (if any) */ - if( *((char*)0xc0000000) ) - strcpy( default_command_line, ((char *)0xc0000000) ); - - /* power off if any problem */ - strcat( default_command_line, " panic=1" ); -#elif defined(CONFIG_SA1100_LART) - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk(1, 0, 0, 8192); - setup_initrd(0xc0400000, 0x00400000); -#endif -#endif } -#define NO_PARAMS 0 -#define NO_VIDEO 0, 0 +#ifdef CONFIG_SA1100_ASSABET +MACHINE_START(ASSABET, "Intel-Assabet") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_BITSY +MACHINE_START(BITSY, "Compaq Bitsy") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_BRUTUS +MACHINE_START(BRUTUS, "Intel Brutus (SA1100 eval board)") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_EMPEG +MACHINE_START(EMPEG, "empeg MP3 Car Audio Player") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_ITSY +MACHINE_START(ITSY, "Compaq Itsy") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100 + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_LART +MACHINE_START(LART, "LART") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_PLEB +MACHINE_START(PLEB, "PLEB") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_THINCLIENT +MACHINE_START(THINCLIENT, "ADS ThinClient") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_TIFON +MACHINE_START(TIFON, "Tifon") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_VICTOR +MACHINE_START(VICTOR, "VisuAide Victor") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#endif -/* - * This is the list of all architectures supported by - * this kernel. This should be integrated with the list - * in head-armv.S. - */ -static struct machine_desc machine_desc[] __attribute__ ((__section__ (".arch.info"))) = { #ifdef CONFIG_ARCH_EBSA110 - { - MACH_TYPE_EBSA110, - "EBSA110", /* RMK */ - 0x00000400, - NO_VIDEO, - 1, 0, 1, 0, 1, - NULL - }, -#endif -#ifdef CONFIG_ARCH_RPC - { - MACH_TYPE_RISCPC, - "Acorn-RiscPC", /* RMK */ - 0x10000100, - NO_VIDEO, - 1, 1, 0, 0, 0, - fixup_acorn - }, +MACHINE_START(EBSA110, "EBSA110") + MAINTAINER("Russell King") + BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000) + BOOT_PARAMS(0x00000400) + DISABLE_PARPORT(0) + DISABLE_PARPORT(2) + SOFT_REBOOT +MACHINE_END #endif #ifdef CONFIG_ARCH_NEXUSPCI - { - MACH_TYPE_NEXUSPCI, - "FTV/PCI", /* Philip Blundell */ - NO_PARAMS, - NO_VIDEO, - 0, 0, 0, 0, 0, - NULL - }, -#endif -#ifdef CONFIG_ARCH_EBSA285 - { - MACH_TYPE_EBSA285, - "EBSA285", /* RMK */ - 0x00000100, - 0x000a0000, 0x000bffff, - 0, 0, 0, 0, 0, - fixup_ebsa285 - }, -#endif -#ifdef CONFIG_ARCH_NETWINDER - { - MACH_TYPE_NETWINDER, - "Rebel-NetWinder", /* RMK */ - 0x00000100, - 0x000a0000, 0x000bffff, - 1, 0, 1, 0, 0, - fixup_netwinder - }, -#endif -#ifdef CONFIG_ARCH_CATS - { - MACH_TYPE_CATS, - "Chalice-CATS", /* Philip Blundell */ - NO_PARAMS, - 0x000a0000, 0x000bffff, - 0, 0, 0, 0, 1, - fixup_cats - }, +MACHINE_START(NEXUSPCI, "FTV/PCI") + MAINTAINER("Philip Blundell") + BOOT_MEM(0x40000000, 0x10000000, 0xe0000000) +MACHINE_END #endif #ifdef CONFIG_ARCH_TBOX - { - MACH_TYPE_TBOX, - "unknown-TBOX", /* Philip Blundell */ - NO_PARAMS, - NO_VIDEO, - 0, 0, 0, 0, 0, - NULL - }, -#endif -#ifdef CONFIG_ARCH_CO285 - { - MACH_TYPE_CO285, - "co-EBSA285", /* Mark van Doesburg */ - NO_PARAMS, - NO_VIDEO, - 0, 0, 0, 0, 0, - fixup_coebsa285 - }, +MACHINE_START(TBOX, "unknown-TBOX") + MAINTAINER("Philip Blundell") + BOOT_MEM(0x80000000, 0x00400000, 0xe0000000) +MACHINE_END #endif #ifdef CONFIG_ARCH_CLPS7110 - { - MACH_TYPE_CLPS7110, - "CL-PS7110", /* Werner Almesberger */ - NO_PARAMS, - NO_VIDEO, - 0, 0, 0, 0, 0, - NULL - }, -#endif -#ifdef CONFIG_ARCH_ARC - { - MACH_TYPE_ARCHIMEDES, - "Acorn-Archimedes",/* RMK/DAG */ - 0x0207c000, - NO_VIDEO, - 0, 0, 0, 0, 0, - fixup_acorn - }, -#endif -#ifdef CONFIG_ARCH_A5K - { - MACH_TYPE_A5K, - "Acorn-A5000", /* RMK/PB */ - 0x0207c000, - NO_VIDEO, - 0, 0, 0, 0, 0, - fixup_acorn - }, +MACHINE_START(CLPS7110, "CL-PS7110") + MAINTAINER("Werner Almesberger") +MACHINE_END #endif #ifdef CONFIG_ARCH_ETOILE - { - MACH_TYPE_ETOILE, - "Etoile", /* Alex de Vries */ - NO_PARAMS, - NO_VIDEO, - 0, 0, 0, 0, 0, - NULL - }, +MACHINE_START(ETOILE, "Etoile") + MAINTAINER("Alex de Vries") +MACHINE_END #endif #ifdef CONFIG_ARCH_LACIE_NAS - { - MACH_TYPE_LACIE_NAS, - "LaCie_NAS", /* Benjamin Herrenschmidt */ - NO_PARAMS, - NO_VIDEO, - 0, 0, 0, 0, 0, - NULL - }, +MACHINE_START(LACIE_NAS, "LaCie_NAS") + MAINTAINER("Benjamin Herrenschmidt") +MACHINE_END #endif #ifdef CONFIG_ARCH_CLPS7500 - { - MACH_TYPE_CLPS7500, - "CL-PS7500", /* Philip Blundell */ - NO_PARAMS, - NO_VIDEO, - 0, 0, 0, 0, 0, - NULL - }, +MACHINE_START(CLPS7500, "CL-PS7500") + MAINTAINER("Philip Blundell") + BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) +MACHINE_END #endif #ifdef CONFIG_ARCH_SHARK - { - MACH_TYPE_SHARK, - "Shark", /* Alexander Schulz */ - NO_PARAMS, - 0x06000000, 0x06000000+0x001fffff, - 0, 0, 0, 0, 0, - NULL - }, -#endif -#ifdef CONFIG_ARCH_SA1100 - { - MACH_TYPE_SA1100, - "SA1100-based", /* Nicolas Pitre */ - NO_PARAMS, - NO_VIDEO, - 0, 0, 0, 0, 0, - fixup_sa1100 - }, +MACHINE_START(SHARK, "Shark") + MAINTAINER("Alexander Schulz") + BOOT_MEM(0x08000000, 0x40000000, 0xe0000000) + VIDEO(0x06000000, 0x061fffff) +MACHINE_END #endif #ifdef CONFIG_ARCH_PERSONAL_SERVER - { - MACH_TYPE_PERSONAL_SERVER, - "Compaq Personal Server", - NO_PARAMS, - NO_VIDEO, - 0, 0, 0, 0, 0, - NULL - } +MACHINE_START(PERSONAL_SERVER, "Compaq Personal Server") + MAINTAINER("Jamey Hicks / George France") + BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) + BOOT_PARAMS(0x00000100) +MACHINE_END #endif -}; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/arch.h linux/arch/arm/kernel/arch.h --- v2.3.99-pre5/linux/arch/arm/kernel/arch.h Tue Mar 14 19:10:38 2000 +++ linux/arch/arm/kernel/arch.h Tue Apr 25 16:54:38 2000 @@ -1,9 +1,27 @@ +/* + * The size of struct machine_desc + * (for assembler code) + */ +#define SIZEOF_MACHINE_DESC 40 + +#ifndef __ASSEMBLY__ + struct machine_desc { + /* + * Note! The first four elements are used + * by assembler code in head-armv.S + */ unsigned int nr; /* architecture number */ + unsigned int phys_ram; /* start of physical ram */ + unsigned int phys_io; /* start of physical io */ + unsigned int virt_io; /* start of virtual io */ + const char *name; /* architecture name */ unsigned int param_offset; /* parameter page */ + unsigned int video_start; /* start of video RAM */ unsigned int video_end; /* end of video RAM */ + unsigned int reserve_lp0 :1; /* never has lp0 */ unsigned int reserve_lp1 :1; /* never has lp1 */ unsigned int reserve_lp2 :1; /* never has lp2 */ @@ -13,3 +31,43 @@ struct param_struct *, char **, struct meminfo *); }; + +/* + * Set of macros to define architecture features + */ +#define MACHINE_START(_type,_name) \ +const struct machine_desc __mach_desc_##_type \ + __attribute__((__section__(".arch.info"))) = { \ + nr: MACH_TYPE_##_type##, \ + name: _name, + +#define MAINTAINER(n) + +#define BOOT_MEM(_pram,_pio,_vio) \ + phys_ram: _pram, \ + phys_io: _pio, \ + virt_io: _vio, + +#define BOOT_PARAMS(_params) \ + param_offset: _params, + +#define VIDEO(_start,_end) \ + video_start: _start, \ + video_end: _end, + +#define DISABLE_PARPORT(_n) \ + reserve_lp##_n##: 1, + +#define BROKEN_HLT \ + broken_hlt: 1, + +#define SOFT_REBOOT \ + soft_reboot: 1, + +#define FIXUP(_func) \ + fixup: _func, + +#define MACHINE_END \ +}; + +#endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.3.99-pre5/linux/arch/arm/kernel/armksyms.c Tue Apr 11 15:09:12 2000 +++ linux/arch/arm/kernel/armksyms.c Tue Apr 25 16:54:38 2000 @@ -101,6 +101,7 @@ EXPORT_SYMBOL(system_rev); EXPORT_SYMBOL(system_serial_low); EXPORT_SYMBOL(system_serial_high); +EXPORT_SYMBOL(mem_fclk_21285); EXPORT_SYMBOL(__bug); EXPORT_SYMBOL(__readwrite_bug); EXPORT_SYMBOL(enable_irq); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/arthur.c linux/arch/arm/kernel/arthur.c --- v2.3.99-pre5/linux/arch/arm/kernel/arthur.c Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/kernel/arthur.c Thu Apr 13 08:11:48 2000 @@ -59,11 +59,7 @@ PER_RISCOS, PER_RISCOS, arthur_to_linux_signals, linux_to_arthur_signals, -#ifdef MODULE - &__this_module, /* No usage counter. */ -#else - NULL, -#endif + THIS_MODULE, NULL /* Nothing after this in the list. */ }; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.3.99-pre5/linux/arch/arm/kernel/bios32.c Tue Apr 11 15:09:12 2000 +++ linux/arch/arm/kernel/bios32.c Tue Apr 25 16:54:38 2000 @@ -21,7 +21,7 @@ extern void hw_init(void); -void pcibios_report_device_errors(void) +void pcibios_report_device_errors(int warn) { struct pci_dev *dev; @@ -34,8 +34,11 @@ continue; pci_write_config_word(dev, PCI_STATUS, status & 0xf900); - printk(KERN_DEBUG "PCI: %02X:%02X: status %04X on %s\n", - dev->bus->number, dev->devfn, status, dev->name); + + if (warn) + printk(KERN_DEBUG "PCI: %02X:%02X: status %04X " + "on %s\n", dev->bus->number, dev->devfn, + status, dev->name); } } @@ -48,10 +51,6 @@ * - (0x48) enable all memory requests from ISA to be channeled to PCI * - (0x42) disable ping-pong (as per errata) * - (0x40) enable PCI packet retry - * - (0x44) Route INTA to IRQ11 - * - (0x83) don't use CPU park enable, park on last master, disable GAT bit - * - (0x80) default rotating priorities - * - (0x81) rotate bank 4 */ static void __init pci_fixup_83c553(struct pci_dev *dev) { @@ -64,10 +63,26 @@ pci_write_config_byte(dev, 0x48, 0xff); pci_write_config_byte(dev, 0x42, 0x00); pci_write_config_byte(dev, 0x40, 0x22); - pci_write_config_word(dev, 0x44, 0xb000); - pci_write_config_byte(dev, 0x83, 0x02); + + /* + * We used to set the arbiter to "park on last master" + * (bit 1 set), but unfortunately the CyberPro does not + * park the bus. We must therefore park on CPU. + */ + pci_write_config_byte(dev, 0x83, 0x00); + + /* + * Rotate priorities of each PCI request + */ pci_write_config_byte(dev, 0x80, 0xe0); pci_write_config_byte(dev, 0x81, 0x01); + + /* + * Route INTA input to IRQ 11, and set + * IRQ11 to be level sensitive. + */ + pci_write_config_word(dev, 0x44, 0xb000); + outb(0x08, 0x4d1); } static void __init pci_fixup_unassign(struct pci_dev *dev) @@ -77,6 +92,23 @@ } /* + * Prevent the PCI layer from seeing the resources + * allocated to this device. These resources are + * of no consequence to the PCI layer (they are + * handled elsewhere). + */ +static void __init pci_fixup_disable(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } +} + +/* * PCI IDE controllers use non-standard I/O port * decoding, respect it. */ @@ -100,6 +132,10 @@ struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, + PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, + pci_fixup_disable + }, { + PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, pci_fixup_83c553 }, { @@ -339,6 +375,7 @@ case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000): case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010): + case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000): return IRQ_NETWINDER_VGA; default: diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/debug-armv.S linux/arch/arm/kernel/debug-armv.S --- v2.3.99-pre5/linux/arch/arm/kernel/debug-armv.S Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/kernel/debug-armv.S Tue Apr 25 16:54:38 2000 @@ -68,7 +68,10 @@ #ifndef CONFIG_DEBUG_DC21285_PORT /* For NetWinder debugging */ .macro addruart,rx - mov \rx, #0xff000000 + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x7c000000 @ physical + movne \rx, #0xff000000 @ virtual orr \rx, \rx, #0x000003f8 .endm @@ -133,7 +136,10 @@ #elif defined(CONFIG_ARCH_SA1100) .macro addruart,rx - mov \rx, #0xf8000000 + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x80000000 @ physical base address + movne \rx, #0xf8000000 @ virtual address add \rx, \rx, #0x00050000 @ Ser3 @add \rx, \rx, #0x00010000 @ Ser1 .endm @@ -171,7 +177,7 @@ ENTRY(printhex2) mov r1, #2 -printhex: ldr r2, =hexbuf +printhex: adr r2, hexbuf add r3, r2, r1 mov r1, #0 strb r1, [r3] @@ -209,5 +215,4 @@ mov r0, #0 b 1b - .bss hexbuf: .space 16 diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.3.99-pre5/linux/arch/arm/kernel/dec21285.c Sun Mar 19 18:35:30 2000 +++ linux/arch/arm/kernel/dec21285.c Tue Apr 25 16:54:38 2000 @@ -23,18 +23,28 @@ #define MAX_SLOTS 21 extern int setup_arm_irq(int, struct irqaction *); -extern void pcibios_report_device_errors(void); +extern void pcibios_report_device_errors(int warn); static unsigned long -dc21285_base_address(struct pci_dev *dev, int where) +dc21285_base_address(struct pci_dev *dev) { unsigned long addr = 0; unsigned int devfn = dev->devfn; - if (dev->bus->number != 0) + if (dev->bus->number == 0) { + if (PCI_SLOT(devfn) == 0) + /* + * For devfn 0, point at the 21285 + */ + addr = ARMCSR_BASE; + else { + devfn -= 1 << 3; + + if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) + addr = PCICFG0_BASE | 0xc00000 | (devfn << 8); + } + } else addr = PCICFG1_BASE | (dev->bus->number << 16) | (devfn << 8); - else if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) - addr = PCICFG0_BASE | 0xc00000 | (devfn << 8); return addr; } @@ -42,7 +52,7 @@ static int dc21285_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - unsigned long addr = dc21285_base_address(dev, where); + unsigned long addr = dc21285_base_address(dev); u8 v; if (addr) @@ -59,7 +69,7 @@ static int dc21285_read_config_word(struct pci_dev *dev, int where, u16 *value) { - unsigned long addr = dc21285_base_address(dev, where); + unsigned long addr = dc21285_base_address(dev); u16 v; if (addr) @@ -76,7 +86,7 @@ static int dc21285_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - unsigned long addr = dc21285_base_address(dev, where); + unsigned long addr = dc21285_base_address(dev); u32 v; if (addr) @@ -93,7 +103,7 @@ static int dc21285_write_config_byte(struct pci_dev *dev, int where, u8 value) { - unsigned long addr = dc21285_base_address(dev, where); + unsigned long addr = dc21285_base_address(dev); if (addr) asm("str%?b %0, [%1, %2]" @@ -105,7 +115,7 @@ static int dc21285_write_config_word(struct pci_dev *dev, int where, u16 value) { - unsigned long addr = dc21285_base_address(dev, where); + unsigned long addr = dc21285_base_address(dev); if (addr) asm("str%?h %0, [%1, %2]" @@ -117,7 +127,7 @@ static int dc21285_write_config_dword(struct pci_dev *dev, int where, u32 value) { - unsigned long addr = dc21285_base_address(dev, where); + unsigned long addr = dc21285_base_address(dev); if (addr) asm("str%? %0, [%1, %2]" @@ -147,6 +157,9 @@ unsigned long irqstatus = *CSR_IRQ_RAWSTATUS; int warn = time_after_eq(jiffies, next_warn); + if (machine_is_netwinder()) + warn = 0; + ctrl |= SA110_CNTL_DISCARDTIMER; if (warn) { @@ -193,7 +206,7 @@ if (warn) printk("pc=[<%08lX>]\n", instruction_pointer(regs)); - pcibios_report_device_errors(); + pcibios_report_device_errors(warn); *CSR_PCICMD = cmd; *CSR_SA110_CNTL = ctrl; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.3.99-pre5/linux/arch/arm/kernel/entry-common.S Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/kernel/entry-common.S Tue Apr 25 16:54:38 2000 @@ -6,7 +6,7 @@ #define S_OFF 8 .macro get_softirq, rd -#ifdef __SMP__ +#ifdef CONFIG_SMP #error SMP not supported #else ldr \rd, __softirq_state diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S --- v2.3.99-pre5/linux/arch/arm/kernel/head-armv.S Tue Mar 14 19:10:38 2000 +++ linux/arch/arm/kernel/head-armv.S Tue Apr 25 16:54:38 2000 @@ -12,6 +12,8 @@ #include #include +#include "arch.h" + #if (TEXTADDR & 0xffff) != 0x8000 #error TEXTADDR must start at 0xXXXX8000 #endif @@ -231,6 +233,13 @@ * Generally, only serious errors cause this. */ __error: +#ifdef CONFIG_DEBUG_LL + mov r8, r0 @ preserve r0 + adr r0, err_str + bl printascii + mov r0, r8 + bl printch +#endif #ifdef CONFIG_ARCH_RPC /* * Turn the screen red on a error - RiscPC only. @@ -247,7 +256,10 @@ 1: mov r0, r0 b 1b - +#ifdef CONFIG_DEBUG_LL +err_str: .asciz "\nError: " + .align +#endif /* * Read processor ID register (CP#15, CR0), and determine @@ -262,9 +274,9 @@ __lookup_processor_type: adr r5, 2f ldmia r5, {r7, r9, r10} - sub r5, r5, r9 + sub r5, r5, r10 add r7, r7, r5 - add r10, r10, r5 + add r10, r9, r5 mrc p15, 0, r9, c0, c0 @ get processor id 1: ldmia r10, {r5, r6, r8} @ value, mask, mmuflags eor r5, r5, r9 @@ -277,8 +289,10 @@ mov pc, lr 2: .long __proc_info_end - .long 2b .long __proc_info_begin + .long 2b + .long __arch_info_begin + .long __arch_info_end /* * Lookup machine architecture @@ -290,135 +304,18 @@ * r7 = byte offset into page tables for IO */ __lookup_architecture_type: - cmp r1, #(__arch_types_end - __arch_types_start) / 16 - bge 1f - adr r4, __arch_types_start - add r4, r4, r1, lsl #4 - ldmia r4, {r4, r5, r6, r7} - mov r7, r7, lsr #18 + adr r4, 2b + ldmia r4, {r2, r3, r5, r6, r7} @ throw away r2, r3 + sub r5, r4, r5 + add r4, r6, r5 + add r7, r7, r5 +1: ldr r5, [r4] + teq r5, r1 + beq 2f + add r4, r4, #SIZEOF_MACHINE_DESC + cmp r4, r7 + blt 1b + mov r7, #0 mov pc, lr -1: mov r7, #0 +2: ldmib r4, {r5, r6, r7} mov pc, lr - -/* - * Machine parameters. Each machine requires 4 words, which are: - * - * word0: unused - * word1: physical start address of RAM - * word2: physical start address of IO - * word3: virtual start address of IO - * - * The IO mappings entered here are used to set up mappings - * required for debugging information to be shown to the user. - * paging_init() does the real page table initialisation. - */ - .type __arch_types_start, #object - @ 0x00 - DEC EBSA110 -__arch_types_start: - .long 0 - .long 0 - .long 0xe0000000 - .long 0xe0000000 - - @ 0x01 - Acorn RiscPC - .long 0 - .long 0x10000000 - .long 0x03000000 - .long 0xe0000000 - - @ 0x02 - Unused - .long 0 - .long 0 - .long 0xe0000000 - .long 0xe0000000 - - @ 0x03 - NexusPCI - .long 0 - .long 0x40000000 - .long 0x10000000 - .long 0xe0000000 - - @ 0x04 - DEC EBSA285 - .long 0 - .long 0 - .long DC21285_ARMCSR_BASE - .long 0xfe000000 - - @ 0x05 - Rebel.com NetWinder - .long 0 - .long 0 - .long DC21285_ARMCSR_BASE - .long 0xfe000000 - - @ 0x06 - CATS - .long 0 - .long 0 - .long DC21285_ARMCSR_BASE - .long 0xfe000000 - - @ 0x07 - tbox - .long 0 - .long 0x80000000 - .long 0x00400000 @ Uart - .long 0xe0000000 - - @ 0x08 - DEC EBSA285 as co-processor - .long 0 - .long 0 - .long DC21285_ARMCSR_BASE @ Physical I/O base address - .long 0x7cf00000 @ Virtual I/O base address - - @ 0x09 - CL-PS7110 - .long 0 - .long 0 - .long 0 - .long 0 - - @ 0x0a - Acorn Archimedes - .long 0 - .long 0 - .long 0 - .long 0 - - @ 0x0b - Acorn A5000 - .long 0 - .long 0 - .long 0 - .long 0 - - @ 0x0c - Etoile - .long 0 - .long 0 - .long 0 - .long 0 - - @ 0x0d - LaCie_NAS - .long 0 - .long 0 - .long 0 - .long 0 - - @ 0x0e - CL-PS7500 - .long 0 - .long 0x10000000 - .long 0x03000000 - .long 0xe0000000 - - @ 0x0f - Digital Shark (DNARD) - .long 0 - .long 0x08000000 - .long 0x40000000 - .long 0xe0000000 - - @ 0x10 - SA1100 - .long 0 - .long 0xc0000000 - .long 0x80000000 - .long 0xf8000000 - - /* - * Don't add anything here unless you have an - * architecture number allocated - see - * Documentation/arm/README - */ -__arch_types_end: diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.3.99-pre5/linux/arch/arm/kernel/irq.c Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/kernel/irq.c Tue Apr 25 16:54:38 2000 @@ -118,10 +118,8 @@ cliIF(); irq_desc[irq].probing = 0; irq_desc[irq].triggered = 0; - if (!irq_desc[irq].noautoenable) { - irq_desc[irq].enabled = 1; - irq_desc[irq].unmask(irq); - } + irq_desc[irq].enabled = 1; + irq_desc[irq].unmask(irq); spin_unlock_irqrestore(&irq_controller_lock, flags); } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.3.99-pre5/linux/arch/arm/kernel/setup.c Tue Apr 11 15:09:12 2000 +++ linux/arch/arm/kernel/setup.c Tue Apr 25 16:54:39 2000 @@ -5,15 +5,14 @@ */ #include #include -#include #include #include #include #include #include #include -#include #include +#include #include #include @@ -33,6 +32,7 @@ #endif extern void paging_init(struct meminfo *); +extern void bootmem_init(struct meminfo *); extern void reboot_setup(char *str); extern void disable_hlt(void); extern int root_mountflags; @@ -43,6 +43,7 @@ unsigned int system_rev; unsigned int system_serial_low; unsigned int system_serial_high; +unsigned int mem_fclk_21285 = 50000000; unsigned int elf_hwcap; #ifdef MULTI_CPU @@ -199,7 +200,8 @@ if (to != command_line) to -= 1; - /* If the user specifies memory size, we + /* + * If the user specifies memory size, we * blow away any automatically generated * size. */ @@ -256,137 +258,6 @@ #endif } -#define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define V_PFN_DOWN(x) O_PFN_DOWN(__pa(x)) - -#define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT) -#define V_PFN_UP(x) O_PFN_UP(__pa(x)) - -#define PFN_SIZE(x) ((x) >> PAGE_SHIFT) -#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \ - (((unsigned long)(s)) & PAGE_MASK)) - -/* - * FIXME: These can be removed when Ingo's cleanup patch goes in - */ -#define free_bootmem(s,sz) free_bootmem((s)< mi->end) { - printk ("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx) - disabling initrd\n", - __pa(initrd_end), mi->end); - initrd_start = 0; - initrd_end = 0; - } - } -#endif - - for (bank = 0; bank < mi->nr_banks; bank ++) { - unsigned int start, end; - - if (mi->bank[bank].size == 0) - continue; - - start = O_PFN_UP(mi->bank[bank].start); - end = O_PFN_DOWN(mi->bank[bank].size + - mi->bank[bank].start); - - if (end < start_pfn) - continue; - - if (start < start_pfn) - start = start_pfn; - - if (end <= start) - continue; - - if (end - start >= bootmap_pages) { - bootmap_pfn = start; - break; - } - } - - if (bootmap_pfn == 0) - BUG(); - - return bootmap_pfn; -} - -/* - * Initialise the bootmem allocator. - */ -static void __init setup_bootmem(struct meminfo *mi) -{ - unsigned int end_pfn, start_pfn, bootmap_pages, bootmap_pfn; - unsigned int i; - - /* - * Calculate the physical address of the top of memory. - */ - mi->end = 0; - for (i = 0; i < mi->nr_banks; i++) { - unsigned long end; - - if (mi->bank[i].size != 0) { - end = mi->bank[i].start + mi->bank[i].size; - if (mi->end < end) - mi->end = end; - } - } - - start_pfn = O_PFN_UP(PHYS_OFFSET); - end_pfn = O_PFN_DOWN(mi->end); - bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn); - bootmap_pfn = find_bootmap_pfn(mi, bootmap_pages); - - /* - * Initialise the boot-time allocator - */ - init_bootmem_start(bootmap_pfn, start_pfn, end_pfn); - - /* - * Register all available RAM with the bootmem allocator. - */ - for (i = 0; i < mi->nr_banks; i++) - if (mi->bank[i].size) - free_bootmem(O_PFN_UP(mi->bank[i].start), - PFN_SIZE(mi->bank[i].size)); - - /* - * Register the reserved regions with bootmem - */ - reserve_bootmem(bootmap_pfn, bootmap_pages); - reserve_bootmem(V_PFN_DOWN(&_stext), PFN_RANGE(&_stext, &_end)); - -#ifdef CONFIG_CPU_32 - /* - * Reserve the page tables. These are already in use. - */ - reserve_bootmem(V_PFN_DOWN(swapper_pg_dir), - PFN_SIZE(PTRS_PER_PGD * sizeof(void *))); -#endif -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - reserve_bootmem(V_PFN_DOWN(initrd_start), - PFN_RANGE(initrd_start, initrd_end)); -#endif -} - static void __init request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc) { @@ -487,6 +358,9 @@ system_serial_low = params->u1.s.system_serial_low; system_serial_high = params->u1.s.system_serial_high; + if (params->u1.s.mem_fclk_21285 > 0) + mem_fclk_21285 = params->u1.s.mem_fclk_21285; + setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0, (params->u1.s.flags & FLAG_RDPROMPT) == 0, params->u1.s.rd_start, @@ -518,9 +392,8 @@ memcpy(saved_command_line, from, COMMAND_LINE_SIZE); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; parse_cmdline(&meminfo, cmdline_p, from); - setup_bootmem(&meminfo); + bootmem_init(&meminfo); request_standard_resources(&meminfo, mdesc); - paging_init(&meminfo); #ifdef CONFIG_VT diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c --- v2.3.99-pre5/linux/arch/arm/kernel/time.c Thu Feb 10 17:11:03 2000 +++ linux/arch/arm/kernel/time.c Tue Apr 25 16:54:39 2000 @@ -30,6 +30,7 @@ extern int setup_arm_irq(int, struct irqaction *); extern void setup_timer(void); +extern rwlock_t xtime_lock; extern volatile unsigned long lost_ticks; /* change this if you have some constant time drift */ @@ -59,7 +60,8 @@ } /* - * hook for getting the time offset + * hook for getting the time offset. Note that it is + * always called with interrupts disabled. */ unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset; @@ -175,29 +177,33 @@ void do_gettimeofday(struct timeval *tv) { unsigned long flags; + unsigned long usec, sec; - save_flags_cli (flags); - *tv = xtime; - tv->tv_usec += gettimeoffset(); - - /* - * xtime is atomically updated in timer_bh. lost_ticks is - * nonzero if the timer bottom half hasnt executed yet. - */ - if (lost_ticks) - tv->tv_usec += USECS_PER_JIFFY; + read_lock_irqsave(&xtime_lock, flags); + usec = gettimeoffset(); + { + unsigned long lost = lost_ticks; - restore_flags(flags); + if (lost) + usec += lost * USECS_PER_JIFFY; + } + sec = xtime.tv_sec; + usec += xtime.tv_usec; + read_unlock_irqrestore(&xtime_lock, flags); - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; + /* usec may have gone up a lot: be safe */ + while (usec >= 1000000) { + usec -= 1000000; + sec++; } + + tv->tv_sec = sec; + tv->tv_usec = usec; } void do_settimeofday(struct timeval *tv) { - cli (); + write_lock_irq(&xtime_lock); /* This is revolting. We need to set the xtime.tv_usec * correctly. However, the value in this location is * is value at the last tick. @@ -205,8 +211,9 @@ * would have done, and then undo it! */ tv->tv_usec -= gettimeoffset(); + tv->tv_usec -= lost_ticks * USECS_PER_JIFFY; - if (tv->tv_usec < 0) { + while (tv->tv_usec < 0) { tv->tv_usec += 1000000; tv->tv_sec--; } @@ -216,7 +223,7 @@ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti(); + write_unlock_irq(&xtime_lock); } static struct irqaction timer_irq = { diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/lib/csumpartialcopy.S linux/arch/arm/lib/csumpartialcopy.S --- v2.3.99-pre5/linux/arch/arm/lib/csumpartialcopy.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/csumpartialcopy.S Tue Apr 25 16:54:39 2000 @@ -12,16 +12,46 @@ * Params : r0 = src, r1 = dst, r2 = len, r3 = checksum * Returns : r0 = new checksum */ + + .macro save_regs + stmfd sp!, {r4 - r8, fp, ip, lr, pc} + .endm + + .macro load_regs,flags + LOADREGS(\flags,fp,{r4 - r8, fp, sp, pc}) + .endm + + .macro load1b, reg1 + ldrb \reg1, [r0], #1 + .endm + + .macro load2b, reg1, reg2 + ldrb \reg1, [r0], #1 + ldrb \reg2, [r0], #1 + .endm + + .macro load1l, reg1 + ldr \reg1, [r0], #4 + .endm + + .macro load2l, reg1, reg2 + ldr \reg1, [r0], #4 + ldr \reg2, [r0], #4 + .endm + + .macro load4l, reg1, reg2, reg3, reg4 + ldmia r0!, {\reg1, \reg2, \reg3, \reg4} + .endm + ENTRY(csum_partial_copy_nocheck) mov ip, sp - stmfd sp!, {r4 - r8, fp, ip, lr, pc} + save_regs sub fp, ip, #4 cmp r2, #4 - blt Ltoo_small + blt .too_small tst r1, #2 @ Test destination alignment - beq Ldst_aligned - ldrb ip, [r0], #1 - ldrb r8, [r0], #1 + beq .dst_aligned + load2b ip, r8 subs r2, r2, #2 @ We do not know if SRC is aligned... orr ip, ip, r8, lsl #8 adds r3, r3, ip @@ -29,12 +59,12 @@ strb ip, [r1], #1 mov ip, ip, lsr #8 strb ip, [r1], #1 @ Destination now aligned -Ldst_aligned: tst r0, #3 - bne Lsrc_not_aligned +.dst_aligned: tst r0, #3 + bne .src_not_aligned adds r3, r3, #0 bics ip, r2, #15 @ Routine for src & dst aligned - beq 3f -1: ldmia r0!, {r4, r5, r6, r7} + beq 2f +1: load4l r4, r5, r6, r7 stmia r1!, {r4, r5, r6, r7} adcs r3, r3, r4 adcs r3, r3, r5 @@ -43,65 +73,69 @@ sub ip, ip, #16 teq ip, #0 bne 1b -3: ands ip, r2, #12 - beq 5f - tst ip, #8 +2: ands ip, r2, #12 beq 4f - ldmia r0!, {r4, r5} + tst ip, #8 + beq 3f + load2l r4, r5 stmia r1!, {r4, r5} adcs r3, r3, r4 adcs r3, r3, r5 tst ip, #4 - beq 5f -4: ldr r4, [r0], #4 + beq 4f +3: load1l r4 str r4, [r1], #4 adcs r3, r3, r4 -5: ands r2, r2, #3 +4: ands r2, r2, #3 adceq r0, r3, #0 - LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) - ldr r4, [r0], #4 + load_regs eqea + load1l r4 tst r2, #2 - beq Lexit_r4 + beq .exit adcs r3, r3, r4, lsl #16 strb r4, [r1], #1 mov r4, r4, lsr #8 strb r4, [r1], #1 mov r4, r4, lsr #8 - b Lexit_r4 +.exit: tst r2, #1 + strneb r4, [r1], #1 + andne r4, r4, #255 + adcnes r3, r3, r4 + adcs r0, r3, #0 + load_regs ea -Ltoo_small: teq r2, #0 - LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) +.too_small: teq r2, #0 + load_regs eqea cmp r2, #2 - blt Ltoo_small1 - ldrb ip, [r0], #1 - ldrb r8, [r0], #1 + blt .too_small1 + load2b ip, r8 orr ip, ip, r8, lsl #8 adds r3, r3, ip strb ip, [r1], #1 strb r8, [r1], #1 tst r2, #1 -Ltoo_small1: ldrneb r4, [r0], #1 -Lexit_r4: tst r2, #1 - strneb r4, [r1], #1 - andne r4, r4, #255 - adcnes r3, r3, r4 - adcs r0, r3, #0 - LOADREGS(ea,fp,{r4 - r8, fp, sp, pc}) +.too_small1: @ C = 0 + beq .csum_exit + load1b ip + strb ip, [r1], #1 + adcs r3, r3, ip +.csum_exit: adc r0, r3, #0 + load_regs ea -Lsrc_not_aligned: +.src_not_aligned: cmp r2, #4 - blt Ltoo_small + blt .too_small and ip, r0, #3 bic r0, r0, #3 - ldr r4, [r0], #4 + load1l r4 cmp ip, #2 - beq Lsrc2_aligned - bhi Lsrc3_aligned + beq .src2_aligned + bhi .src3_aligned mov r4, r4, lsr #8 adds r3, r3, #0 bics ip, r2, #15 beq 2f -1: ldmia r0!, {r5, r6, r7, r8} +1: load4l r5, r6, r7, r8 orr r4, r4, r5, lsl #24 mov r5, r5, lsr #8 orr r5, r5, r6, lsl #24 @@ -122,7 +156,7 @@ beq 4f tst ip, #8 beq 3f - ldmia r0!, {r5, r6} + load2l r5, r6 orr r4, r4, r5, lsl #24 mov r5, r5, lsr #8 orr r5, r5, r6, lsl #24 @@ -132,28 +166,28 @@ mov r4, r6, lsr #8 tst ip, #4 beq 4f -3: ldr r5, [r0], #4 +3: load1l r5 orr r4, r4, r5, lsl #24 str r4, [r1], #4 adcs r3, r3, r4 mov r4, r5, lsr #8 4: ands r2, r2, #3 adceq r0, r3, #0 - LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + load_regs eqea tst r2, #2 - beq Lexit_r4 + beq .exit adcs r3, r3, r4, lsl #16 strb r4, [r1], #1 mov r4, r4, lsr #8 strb r4, [r1], #1 mov r4, r4, lsr #8 - b Lexit_r4 + b .exit -Lsrc2_aligned: mov r4, r4, lsr #16 +.src2_aligned: mov r4, r4, lsr #16 adds r3, r3, #0 bics ip, r2, #15 beq 2f -1: ldmia r0!, {r5, r6, r7, r8} +1: load4l r5, r6, r7, r8 orr r4, r4, r5, lsl #16 mov r5, r5, lsr #16 orr r5, r5, r6, lsl #16 @@ -174,7 +208,7 @@ beq 4f tst ip, #8 beq 3f - ldmia r0!, {r5, r6} + load2l r5, r6 orr r4, r4, r5, lsl #16 mov r5, r5, lsr #16 orr r5, r5, r6, lsl #16 @@ -184,28 +218,31 @@ mov r4, r6, lsr #16 tst ip, #4 beq 4f -3: ldr r5, [r0], #4 +3: load1l r5 orr r4, r4, r5, lsl #16 str r4, [r1], #4 adcs r3, r3, r4 mov r4, r5, lsr #16 4: ands r2, r2, #3 adceq r0, r3, #0 - LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + load_regs eqea tst r2, #2 - beq Lexit_r4 + beq .exit adcs r3, r3, r4, lsl #16 strb r4, [r1], #1 mov r4, r4, lsr #8 strb r4, [r1], #1 - ldrb r4, [r0], #1 - b Lexit_r4 + tst r2, #1 + adceq r0, r3, #0 + load_regs eqea + load1b r4 + b .exit -Lsrc3_aligned: mov r4, r4, lsr #24 +.src3_aligned: mov r4, r4, lsr #24 adds r3, r3, #0 bics ip, r2, #15 beq 2f -1: ldmia r0!, {r5, r6, r7, r8} +1: load4l r5, r6, r7, r8 orr r4, r4, r5, lsl #8 mov r5, r5, lsr #24 orr r5, r5, r6, lsl #8 @@ -226,7 +263,7 @@ beq 4f tst ip, #8 beq 3f - ldmia r0!, {r5, r6} + load2l r5, r6 orr r4, r4, r5, lsl #8 mov r5, r5, lsr #24 orr r5, r5, r6, lsl #8 @@ -236,22 +273,20 @@ mov r4, r6, lsr #24 tst ip, #4 beq 4f -3: ldr r5, [r0], #4 +3: load1l r5 orr r4, r4, r5, lsl #8 str r4, [r1], #4 adcs r3, r3, r4 mov r4, r5, lsr #24 4: ands r2, r2, #3 adceq r0, r3, #0 - LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + load_regs eqea tst r2, #2 - beq Lexit_r4 + beq .exit adcs r3, r3, r4, lsl #16 strb r4, [r1], #1 - ldr r4, [r0], #4 + load1l r4 strb r4, [r1], #1 adcs r3, r3, r4, lsl #24 mov r4, r4, lsr #8 - b Lexit_r4 - - + b .exit diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/lib/csumpartialcopyuser.S linux/arch/arm/lib/csumpartialcopyuser.S --- v2.3.99-pre5/linux/arch/arm/lib/csumpartialcopyuser.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/lib/csumpartialcopyuser.S Tue Apr 25 16:54:39 2000 @@ -153,9 +153,9 @@ save_regs sub fp, ip, #4 cmp r2, #4 - blt .too_small_user + blt .too_small tst r1, #2 @ Test destination alignment - beq .dst_aligned_user + beq .dst_aligned load2b ip, r8 subs r2, r2, #2 @ We do not know if SRC is aligned... orr ip, ip, r8, lsl #8 @@ -164,9 +164,8 @@ strb ip, [r1], #1 mov ip, ip, lsr #8 strb ip, [r1], #1 @ Destination now aligned -.dst_aligned_user: - tst r0, #3 - bne .src_not_aligned_user +.dst_aligned: tst r0, #3 + bne .src_not_aligned adds r3, r3, #0 bics ip, r2, #15 @ Routine for src & dst aligned beq 2f @@ -210,18 +209,17 @@ adcs r0, r3, #0 load_regs ea -.too_small_user: - teq r2, #0 +.too_small: teq r2, #0 load_regs eqea cmp r2, #2 - blt .too_small_user1 + blt .too_small1 load2b ip, r8 orr ip, ip, r8, lsl #8 adds r3, r3, ip strb ip, [r1], #1 strb r8, [r1], #1 tst r2, #1 -.too_small_user1: @ C = 0 +.too_small1: @ C = 0 beq .csum_exit load1b ip strb ip, [r1], #1 @@ -229,15 +227,15 @@ .csum_exit: adc r0, r3, #0 load_regs ea -.src_not_aligned_user: +.src_not_aligned: cmp r2, #4 - blt .too_small_user + blt .too_small and ip, r0, #3 bic r0, r0, #3 load1l r4 cmp ip, #2 - beq .src2_aligned_user - bhi .src3_aligned_user + beq .src2_aligned + bhi .src3_aligned mov r4, r4, lsr #8 adds r3, r3, #0 bics ip, r2, #15 @@ -290,8 +288,7 @@ mov r4, r4, lsr #8 b .exit -.src2_aligned_user: - mov r4, r4, lsr #16 +.src2_aligned: mov r4, r4, lsr #16 adds r3, r3, #0 bics ip, r2, #15 beq 2f @@ -346,8 +343,7 @@ load1b r4 b .exit -.src3_aligned_user: - mov r4, r4, lsr #24 +.src3_aligned: mov r4, r4, lsr #24 adds r3, r3, #0 bics ip, r2, #15 beq 2f diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c --- v2.3.99-pre5/linux/arch/arm/mm/consistent.c Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/mm/consistent.c Tue Apr 25 16:54:39 2000 @@ -29,20 +29,29 @@ if (in_interrupt()) BUG(); + size = PAGE_ALIGN(size); order = get_order(size); page = __get_free_pages(gfp, order); if (!page) goto no_page; - memset((void *)page, 0, PAGE_SIZE << order); - clean_cache_area(page, PAGE_SIZE << order); + memset((void *)page, 0, size); + clean_cache_area(page, size); *dma_handle = virt_to_bus((void *)page); - ret = __ioremap(virt_to_phys((void *)page), PAGE_SIZE << order, 0); - if (ret) + ret = __ioremap(virt_to_phys((void *)page), size, 0); + if (ret) { + /* free wasted pages */ + unsigned long end = page + (PAGE_SIZE << order); + page += size; + while (page < end) { + free_page(page); + page += PAGE_SIZE; + } return ret; + } free_pages(page, order); no_page: @@ -81,18 +90,18 @@ /* * make an area consistent. */ -void consistent_sync(void *vaddr, size_t size, int rw) +void consistent_sync(void *vaddr, size_t size, int direction) { - switch (rw) { - case 0: + switch (direction) { + case PCI_DMA_NONE: BUG(); - case 1: /* invalidate only */ + case PCI_DMA_FROMDEVICE: /* invalidate only */ dma_cache_inv(vaddr, size); break; - case 2: /* writeback only */ + case PCI_DMA_TODEVICE: /* writeback only */ dma_cache_wback(vaddr, size); break; - case 3: /* writeback and invalidate */ + case PCI_DMA_BIDIRECTIONAL: /* writeback and invalidate */ dma_cache_wback_inv(vaddr, size); break; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c --- v2.3.99-pre5/linux/arch/arm/mm/fault-common.c Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/mm/fault-common.c Mon Apr 24 15:51:52 2000 @@ -123,7 +123,7 @@ * make sure we exit gracefully rather than endlessly redo * the fault. */ - if (!handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode))) + if (!handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(mode))) goto do_sigbus; up(&mm->mmap_sem); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.3.99-pre5/linux/arch/arm/mm/init.c Tue Mar 14 19:10:39 2000 +++ linux/arch/arm/mm/init.c Tue Apr 25 16:54:39 2000 @@ -1,9 +1,8 @@ /* * linux/arch/arm/mm/init.c * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-2000 Russell King */ - #include #include #include @@ -32,9 +31,22 @@ #include "map.h" +#ifdef CONFIG_CPU_32 +#define TABLE_OFFSET (PTRS_PER_PTE) +#else +#define TABLE_OFFSET 0 +#endif +#define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *)) + static unsigned long totalram_pages; -struct meminfo meminfo; pgd_t swapper_pg_dir[PTRS_PER_PGD]; +extern int _stext, _text, _etext, _edata, _end; + +/* + * The sole use of this is to pass memory configuration + * data from paging_init to mem_init. + */ +static struct meminfo __initdata meminfo; /* * empty_bad_page is the page that is used for page faults when @@ -119,33 +131,36 @@ void show_mem(void) { int free = 0, total = 0, reserved = 0; - int shared = 0, cached = 0; - struct page *page, *end; + int shared = 0, cached = 0, node; printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - page = mem_map; - end = mem_map + max_mapnr; + for (node = 0; node < numnodes; node++) { + struct page *page, *end; - do { - if (PageSkip(page)) { - page = page->next_hash; - if (page == NULL) - break; - } - total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (!page_count(page)) - free++; - else - shared += atomic_read(&page->count) - 1; - page++; - } while (page < end); + page = NODE_MEM_MAP(node); + end = page + NODE_DATA(node)->node_size; + + do { + if (PageSkip(page)) { + page = page->next_hash; + if (page == NULL) + break; + } + total++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (!page_count(page)) + free++; + else + shared += atomic_read(&page->count) - 1; + page++; + } while (page < end); + } printk("%d pages of RAM\n", total); printk("%d free pages\n", free); @@ -158,24 +173,173 @@ show_buffers(); } +#define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define V_PFN_DOWN(x) O_PFN_DOWN(__pa(x)) + +#define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT) +#define V_PFN_UP(x) O_PFN_UP(__pa(x)) + +#define PFN_SIZE(x) ((x) >> PAGE_SHIFT) +#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \ + (((unsigned long)(s)) & PAGE_MASK)) + +static unsigned int __init +find_bootmap_pfn(struct meminfo *mi, unsigned int bootmap_pages) +{ + unsigned int start_pfn, bank, bootmap_pfn; + + start_pfn = V_PFN_UP(&_end); + bootmap_pfn = 0; + + /* + * FIXME: We really want to avoid allocating the bootmap + * over the top of the initrd. + */ +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) { + if (__pa(initrd_end) > mi->end) { + printk ("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx) - disabling initrd\n", + __pa(initrd_end), mi->end); + initrd_start = 0; + initrd_end = 0; + } + } +#endif + + for (bank = 0; bank < mi->nr_banks; bank ++) { + unsigned int start, end; + + if (mi->bank[bank].size == 0) + continue; + + start = O_PFN_UP(mi->bank[bank].start); + end = O_PFN_DOWN(mi->bank[bank].size + + mi->bank[bank].start); + + if (end < start_pfn) + continue; + + if (start < start_pfn) + start = start_pfn; + + if (end <= start) + continue; + + if (end - start >= bootmap_pages) { + bootmap_pfn = start; + break; + } + } + + if (bootmap_pfn == 0) + BUG(); + + return bootmap_pfn; +} + +/* + * Initialise one node of the bootmem allocator. For now, we + * only initialise node 0. Notice that we have a bootmem + * bitmap per node. + */ +static void __init setup_bootmem_node(int node, struct meminfo *mi) +{ + unsigned int end_pfn, start_pfn, bootmap_pages, bootmap_pfn; + unsigned int i; + + if (node != 0) /* only initialise node 0 for now */ + return; + + start_pfn = O_PFN_UP(PHYS_OFFSET); + end_pfn = O_PFN_DOWN(mi->end); + bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn); + bootmap_pfn = find_bootmap_pfn(mi, bootmap_pages); + + /* + * Initialise the boot-time allocator + */ + init_bootmem_node(node, bootmap_pfn, start_pfn, end_pfn); + + /* + * Register all available RAM with the bootmem allocator. + */ + for (i = 0; i < mi->nr_banks; i++) + if (mi->bank[i].size) + free_bootmem_node(node, mi->bank[i].start, + PFN_SIZE(mi->bank[i].size) << PAGE_SHIFT); + + reserve_bootmem_node(node, bootmap_pfn << PAGE_SHIFT, + bootmap_pages << PAGE_SHIFT); +} + +/* + * Initialise the bootmem allocator. + */ +void __init bootmem_init(struct meminfo *mi) +{ + unsigned int i, node; + + /* + * Calculate the physical address of the top of memory. + * Note that there are no guarantees assumed about the + * ordering of the bank information. + */ + mi->end = 0; + for (i = 0; i < mi->nr_banks; i++) { + unsigned long end; + + if (mi->bank[i].size != 0) { + end = mi->bank[i].start + mi->bank[i].size; + if (mi->end < end) + mi->end = end; + } + } + + max_low_pfn = O_PFN_DOWN(mi->end - PHYS_OFFSET); + + /* + * Setup each node + */ + for (node = 0; node < numnodes; node++) + setup_bootmem_node(node, mi); + + /* + * Register the kernel text and data with bootmem. + * Note that this can only be in node 0. + */ + reserve_bootmem_node(0, V_PFN_DOWN(&_stext) << PAGE_SHIFT, + PFN_RANGE(&_stext, &_end) << PAGE_SHIFT); + +#ifdef CONFIG_CPU_32 + /* + * Reserve the page tables. These are already in use, + * and can only be in node 0. + */ + reserve_bootmem_node(0, V_PFN_DOWN(swapper_pg_dir) << PAGE_SHIFT, + PFN_SIZE(PTRS_PER_PGD * sizeof(void *)) << PAGE_SHIFT); +#endif +#ifdef CONFIG_BLK_DEV_INITRD + /* + * This may be in any bank. Currently, we assume that + * it is in bank 0. + */ + if (initrd_start) + reserve_bootmem_node(0, V_PFN_DOWN(initrd_start) << PAGE_SHIFT, + PFN_RANGE(initrd_start, initrd_end) << PAGE_SHIFT); +#endif +} + /* * paging_init() sets up the page tables... */ void __init paging_init(struct meminfo *mi) { void *zero_page, *bad_page, *bad_table; - unsigned long zone_size[MAX_NR_ZONES]; - int i; + int node; memcpy(&meminfo, mi, sizeof(meminfo)); -#ifdef CONFIG_CPU_32 -#define TABLE_OFFSET (PTRS_PER_PTE) -#else -#define TABLE_OFFSET 0 -#endif -#define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *)) - /* * allocate what we need for the bad pages */ @@ -186,31 +350,42 @@ /* * initialise the page tables */ - pagetable_init(); + pagetable_init(mi); flush_tlb_all(); /* - * Initialise the zones and mem_map + * initialise the zones within each node */ - for (i = 0; i < MAX_NR_ZONES; i++) - zone_size[i] = 0; + for (node = 0; node < numnodes; node++) { + unsigned long zone_size[MAX_NR_ZONES]; + unsigned long zhole_size[MAX_NR_ZONES]; + struct bootmem_data *bdata; + pg_data_t *pgdat; + int i; + + /* + * Initialise the zone size information. + */ + for (i = 0; i < MAX_NR_ZONES; i++) { + zone_size[i] = 0; + zhole_size[i] = 0; + } - /* - * Calculate the size of the zones. On ARM, we don't have - * any problems with DMA or highmem, so all memory is - * allocated to the DMA zone. - */ - for (i = 0; i < mi->nr_banks; i++) { - if (mi->bank[i].size) { - unsigned int end; + pgdat = NODE_DATA(node); + bdata = pgdat->bdata; - end = (mi->bank[i].start - PHYS_OFFSET + - mi->bank[i].size) >> PAGE_SHIFT; - if (zone_size[0] < end) - zone_size[0] = end; - } + /* + * The size of this node has already been determined. + * If we need to do anything fancy with the allocation + * of this memory to the zones, now is the time to do + * it. For now, we don't touch zhole_size. + */ + zone_size[0] = bdata->node_low_pfn - + (bdata->node_boot_start >> PAGE_SHIFT); + + free_area_init_node(node, pgdat, zone_size, + bdata->node_boot_start, zhole_size); } - free_area_init(zone_size); /* * finish off the bad pages once @@ -256,32 +431,33 @@ */ void __init mem_init(void) { - extern char __init_begin, __init_end, _text, _etext, _end; + extern char __init_begin, __init_end; unsigned int codepages, datapages, initpages; - int i; + int i, node; codepages = &_etext - &_text; datapages = &_end - &_etext; initpages = &__init_end - &__init_begin; - max_mapnr = max_low_pfn; - high_memory = (void *)__va(PHYS_OFFSET + max_low_pfn * PAGE_SIZE); + high_memory = (void *)__va(meminfo.end); + max_mapnr = MAP_NR(high_memory); /* * We may have non-contiguous memory. Setup the PageSkip stuff, * and mark the areas of mem_map which can be freed */ if (meminfo.nr_banks != 1) - create_memmap_holes(); + create_memmap_holes(&meminfo); /* this will put all unused low memory onto the freelists */ - totalram_pages += free_all_bootmem(); + for (node = 0; node < numnodes; node++) + totalram_pages += free_all_bootmem_node(node); /* * Since our memory may not be contiguous, calculate the * real number of pages we have in this system */ - printk("Memory:"); + printk(KERN_INFO "Memory:"); num_physpages = 0; for (i = 0; i < meminfo.nr_banks; i++) { @@ -290,7 +466,8 @@ } printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); - printk("Memory: %luKB available (%dK code, %dK data, %dK init)\n", + printk(KERN_NOTICE "Memory: %luKB available (%dK code, " + "%dK data, %dK init)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), codepages >> 10, datapages >> 10, initpages >> 10); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/map.h linux/arch/arm/mm/map.h --- v2.3.99-pre5/linux/arch/arm/mm/map.h Tue Nov 23 22:42:20 1999 +++ linux/arch/arm/mm/map.h Tue Apr 25 16:54:39 2000 @@ -19,7 +19,7 @@ extern struct map_desc io_desc[]; extern unsigned int io_desc_size; -extern void zonesize_init(unsigned int *); -extern void create_memmap_holes(void); -extern void pagetable_init(void); +struct meminfo; +extern void create_memmap_holes(struct meminfo *); +extern void pagetable_init(struct meminfo *); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/mm-armo.c linux/arch/arm/mm/mm-armo.c --- v2.3.99-pre5/linux/arch/arm/mm/mm-armo.c Sun Mar 19 18:35:30 2000 +++ linux/arch/arm/mm/mm-armo.c Tue Apr 25 16:54:39 2000 @@ -147,7 +147,7 @@ * some more work to get it to fit into our separate processor and * architecture structure. */ -void __init pagetable_init(void) +void __init pagetable_init(struct meminfo *mi) { pte_t *pte; int i; @@ -165,6 +165,6 @@ /* * We never have holes in the memmap */ -void __init create_memmap_holes(void) +void __init create_memmap_holes(struct meminfo *mi) { } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c --- v2.3.99-pre5/linux/arch/arm/mm/mm-armv.c Tue Apr 11 15:09:12 2000 +++ linux/arch/arm/mm/mm-armv.c Tue Apr 25 16:54:39 2000 @@ -310,7 +310,7 @@ } } -void __init pagetable_init(void) +void __init pagetable_init(struct meminfo *mi) { struct map_desc *init_maps, *p, *q; unsigned long address = 0; @@ -335,13 +335,13 @@ p ++; - for (i = 0; i < meminfo.nr_banks; i++) { - if (meminfo.bank[i].size == 0) + for (i = 0; i < mi->nr_banks; i++) { + if (mi->bank[i].size == 0) continue; - p->physical = meminfo.bank[i].start; + p->physical = mi->bank[i].start; p->virtual = __phys_to_virt(p->physical); - p->length = meminfo.bank[i].size; + p->length = mi->bank[i].size; p->domain = DOMAIN_KERNEL; p->prot_read = 0; p->prot_write = 1; @@ -414,7 +414,7 @@ * The mem_map array can get very big. Mark the end of the valid mem_map * banks with PG_skip, and setup the address validity bitmap. */ -void __init create_memmap_holes(void) +void __init create_memmap_holes(struct meminfo *mi) { unsigned int start_pfn, end_pfn = -1; struct page *pg = NULL; @@ -423,11 +423,11 @@ #define PFN(x) (((x) - PHYS_OFFSET) >> PAGE_SHIFT) #define free_bootmem(s,sz) free_bootmem(((s)<nr_banks; i++) { + if (mi->bank[i].size == 0) continue; - start_pfn = PFN(meminfo.bank[i].start); + start_pfn = PFN(mi->bank[i].start); /* * subtle here - if we have a full bank, then @@ -447,9 +447,9 @@ pg = NULL; } - end_pfn = PFN(meminfo.bank[i].start + meminfo.bank[i].size); + end_pfn = PFN(mi->bank[i].start + mi->bank[i].size); - if (end_pfn != PFN(meminfo.end)) + if (end_pfn != PFN(mi->end)) pg = mem_map + end_pfn; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/mm-ebsa110.c linux/arch/arm/mm/mm-ebsa110.c --- v2.3.99-pre5/linux/arch/arm/mm/mm-ebsa110.c Mon Nov 1 13:56:26 1999 +++ linux/arch/arm/mm/mm-ebsa110.c Tue Apr 25 16:54:39 2000 @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -15,7 +16,7 @@ #define SIZE(x) (sizeof(x) / sizeof(x[0])) -const struct map_desc io_desc[] __initdata = { +struct map_desc io_desc[] __initdata = { { IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 } }; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c --- v2.3.99-pre5/linux/arch/arm/mm/mm-rpc.c Mon Nov 1 13:56:26 1999 +++ linux/arch/arm/mm/mm-rpc.c Tue Apr 25 16:54:39 2000 @@ -18,7 +18,7 @@ struct map_desc io_desc[] __initdata = { /* VRAM */ - { SCREEN2_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 }, + { SCREEN_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 }, /* IO space */ { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, /* EASI space */ diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c --- v2.3.99-pre5/linux/arch/arm/mm/mm-sa1100.c Tue Apr 11 15:09:12 2000 +++ linux/arch/arm/mm/mm-sa1100.c Tue Apr 25 16:54:39 2000 @@ -9,6 +9,10 @@ * 1999/12/04 Nicolas Pitre * Converted memory definition for struct meminfo initialisations. * Memory is listed physically now. + * + * 2000/04/07 Nicolas Pitre + * Reworked for real-time selection of memory definitions + * */ #include @@ -23,79 +27,109 @@ #define SIZE(x) (sizeof(x) / sizeof(x[0])) -/* - * These are the RAM memory mappings for SA1100 implementations. - * Note that LART is a special case - it doesn't use physical - * address line A23 on the DRAM, so we effectively have 4 * 8MB - * in two banks. - */ -struct mem_desc { - unsigned long phys_start; - unsigned long length; -} mem_desc[] __initdata = { -#if defined(CONFIG_SA1100_BRUTUS) - { 0xc0000000, 0x00400000 }, /* 4MB */ - { 0xc8000000, 0x00400000 }, /* 4MB */ - { 0xd0000000, 0x00400000 }, /* 4MB */ - { 0xd8000000, 0x00400000 } /* 4MB */ -#elif defined(CONFIG_SA1100_EMPEG) - { 0xc0000000, 0x00400000 }, /* 4MB */ - { 0xc8000000, 0x00400000 } /* 4MB */ -#elif defined(CONFIG_SA1100_LART) - { 0xc0000000, 0x00800000 }, /* 8MB */ - { 0xc1000000, 0x00800000 }, /* 8MB */ - { 0xc8000000, 0x00800000 }, /* 8MB */ - { 0xc9000000, 0x00800000 } /* 8MB */ -#elif defined(CONFIG_SA1100_VICTOR) - { 0xc0000000, 0x00400000 } /* 4MB */ -#elif defined(CONFIG_SA1100_THINCLIENT) - { 0xc0000000, 0x01000000 } /* 16MB */ -#elif defined(CONFIG_SA1100_TIFON) - { 0xc0000000, 0x01000000 }, /* 16MB */ - { 0xc8000000, 0x01000000 } /* 16MB */ -#else -#error missing memory configuration +#define SA1100_STD_IO_MAPPING \ + /* virtual physical length domain r w c b */ \ + { 0xe0000000, 0x20000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */ \ + { 0xe4000000, 0x30000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */ \ + { 0xe8000000, 0x28000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 attr */ \ + { 0xec000000, 0x38000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 attr */ \ + { 0xf0000000, 0x2c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 mem */ \ + { 0xf4000000, 0x3c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 mem */ \ + { 0xf8000000, 0x80000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */ \ + { 0xfa000000, 0x90000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */ \ + { 0xfc000000, 0xa0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */ \ + { 0xfe000000, 0xb0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 } /* LCD + DMA */ + + +static struct map_desc assabet_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_ASSABET + { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + { 0xdc000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ + SA1100_STD_IO_MAPPING #endif }; -unsigned int __initdata mem_desc_size = SIZE(mem_desc); +static struct map_desc bitsy_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_BITSY + { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + SA1100_STD_IO_MAPPING +#endif +}; +static struct map_desc empeg_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_EMPEG + { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ + SA1100_STD_IO_MAPPING +#endif +}; -struct map_desc io_desc[] __initdata = { - /* virtual physical length domain r w c b */ -#if defined(CONFIG_SA1100_VICTOR) - { 0xd0000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ -#elif defined(CONFIG_SA1100_EMPEG) - { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ -#elif defined(CONFIG_SA1100_THINCLIENT) +static struct map_desc thinclient_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_THINCLIENT #if 1 - /* ThinClient: only one of those... */ -// { 0xd0000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */ - { 0xd0000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */ + /* ThinClient: only one of those... */ +// { 0xd0000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */ + { 0xd0000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */ #else - /* GraphicsClient: */ - { 0xd0000000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ - { 0xd0800000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 3 */ -#endif -#elif defined(CONFIG_SA1100_TIFON) - { 0xd0000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ - { 0xd0800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */ -#endif -#if defined( CONFIG_SA1101 ) - { 0xdc000000, SA1101_BASE, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1101 */ -#elif defined( CONFIG_SA1100_THINCLIENT ) - { 0xdc000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ -#endif - { 0xe0000000, 0x20000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */ - { 0xe4000000, 0x30000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */ - { 0xe8000000, 0x28000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 attr */ - { 0xec000000, 0x38000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 attr */ - { 0xf0000000, 0x2c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 mem */ - { 0xf4000000, 0x3c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 mem */ - { 0xf8000000, 0x80000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */ - { 0xfa000000, 0x90000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */ - { 0xfc000000, 0xa0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */ - { 0xfe000000, 0xb0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 } /* LCD + DMA */ + /* GraphicsClient: */ + { 0xd0000000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ + { 0xd0800000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 3 */ +#endif + { 0xdc000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ + SA1100_STD_IO_MAPPING +#endif +}; + +static struct map_desc tifon_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_TIFON + { 0xd0000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ + { 0xd0800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */ + SA1100_STD_IO_MAPPING +#endif }; -unsigned int __initdata io_desc_size = SIZE(io_desc); +static struct map_desc victor_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_VICTOR + { 0xd0000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ + SA1100_STD_IO_MAPPING +#endif +}; + + +static struct map_desc default_io_desc[] __initdata = { + SA1100_STD_IO_MAPPING +}; + + +/* + * Here it would be wiser to simply assign a pointer to the appropriate + * list, but io_desc is already declared as an array in "map.h". + */ +struct map_desc io_desc[20] __initdata = { { 0, }, }; +unsigned int io_desc_size; + +void __init select_sa1100_io_desc(void) +{ + if( machine_is_assabet() ) { + memcpy( io_desc, assabet_io_desc, sizeof(assabet_io_desc) ); + io_desc_size = SIZE(assabet_io_desc); + } else if( machine_is_bitsy() ) { + memcpy( io_desc, bitsy_io_desc, sizeof(bitsy_io_desc) ); + io_desc_size = SIZE(bitsy_io_desc); + } else if( machine_is_empeg() ) { + memcpy( io_desc, empeg_io_desc, sizeof(empeg_io_desc) ); + io_desc_size = SIZE(empeg_io_desc); + } else if( machine_is_thinclient() ) { + memcpy( io_desc, thinclient_io_desc, sizeof(thinclient_io_desc) ); + io_desc_size = SIZE(thinclient_io_desc); + } else if( machine_is_tifon() ) { + memcpy( io_desc, tifon_io_desc, sizeof(tifon_io_desc) ); + io_desc_size = SIZE(tifon_io_desc); + } else if( machine_is_victor() ) { + memcpy( io_desc, victor_io_desc, sizeof(victor_io_desc) ); + io_desc_size = SIZE(victor_io_desc); + } else { + memcpy( io_desc, default_io_desc, sizeof(default_io_desc) ); + io_desc_size = SIZE(default_io_desc); + } +} + diff -u --recursive --new-file v2.3.99-pre5/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.3.99-pre5/linux/arch/arm/mm/proc-sa110.S Tue Apr 11 15:09:12 2000 +++ linux/arch/arm/mm/proc-sa110.S Tue Apr 25 16:54:39 2000 @@ -4,7 +4,9 @@ * (C) 1997-2000 Russell King * * These are the low level assembler for performing cache and TLB - * functions on the StrongARM-110 and StrongARM-1100 + * functions on the StrongARM-110, StrongARM-1100 and StrongARM-1110. + * + * Note that SA1100 and SA1110 share everything but their name and CPU ID. */ #include #include @@ -420,13 +422,12 @@ mov pc, lr ENTRY(cpu_sa110_proc_fin) -ENTRY(cpu_sa1100_proc_fin) stmfd sp!, {r1, lr} mrs r0, cpsr orr r0, r0, #F_BIT | I_BIT msr cpsr, r0 bl cpu_sa110_flush_cache_all @ clean caches - mov r0, #0 +1: mov r0, #0 mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x1000 @ ...i............ @@ -434,8 +435,17 @@ mcr p15, 0, r0, c1, c0, 0 @ disable caches ldmfd sp!, {r1, pc} +ENTRY(cpu_sa1100_proc_fin) + stmfd sp!, {r1, lr} + mrs r0, cpsr + orr r0, r0, #F_BIT | I_BIT + msr cpsr, r0 + bl cpu_sa1100_flush_cache_all @ clean caches + b 1b + + .align 5 -idle: mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt +idle: mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt, cache aligned mov r0, r0 @ safety mov pc, lr /* @@ -483,16 +493,14 @@ bic ip, ip, #0x1100 @ ...i...s........ mcr p15, 0, ip, c1, c0, 0 @ ctrl register mov pc, r0 -/* - * Purpose : Function pointers used to access above functions - all calls - * come through these - */ + cpu_manu_name: .asciz "Intel" -ENTRY(cpu_sa110_name) - .asciz "StrongARM-110" -ENTRY(cpu_sa1100_name) +cpu_sa110_name: .asciz "StrongARM-110" +cpu_sa1100_name: .asciz "StrongARM-1100" +cpu_sa1110_name: + .asciz "StrongARM-1110" .align .section ".text.init", #alloc, #execinstr @@ -511,6 +519,13 @@ orr r0, r0, #0x1100 @ ...I...S........ mov pc, lr + .text + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type sa110_processor_functions, #object ENTRY(sa110_processor_functions) .word cpu_sa110_data_abort @@ -543,6 +558,9 @@ .size cpu_sa110_info, . - cpu_sa110_info +/* + * SA1100 and SA1110 share the same function calls + */ .type sa1100_processor_functions, #object ENTRY(sa1100_processor_functions) .word cpu_sa1100_data_abort @@ -573,6 +591,12 @@ .long cpu_sa1100_name .size cpu_sa1100_info, . - cpu_sa1100_info +cpu_sa1110_info: + .long cpu_manu_name + .long cpu_sa1110_name + .size cpu_sa1110_info, . - cpu_sa1110_info + + .type cpu_arch_name, #object cpu_arch_name: .asciz "armv4" .size cpu_arch_name, . - cpu_arch_name @@ -609,5 +633,18 @@ .long cpu_sa1100_info .long sa1100_processor_functions .size __sa1100_proc_info, . - __sa1100_proc_info + + .type __sa1110_proc_info,#object +__sa1110_proc_info: + .long 0x6901b110 + .long 0xfffffff0 + .long 0x00000c02 + b __sa110_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_sa1110_info + .long sa1100_processor_functions + .size __sa1110_proc_info, . - __sa1110_proc_info diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.99-pre5/linux/arch/i386/config.in Tue Apr 11 15:09:12 2000 +++ linux/arch/i386/config.in Mon Apr 24 13:39:34 2000 @@ -20,48 +20,54 @@ choice 'Processor family' \ "386 CONFIG_M386 \ 486/Cx486 CONFIG_M486 \ - 586/K5/5x86/6x86 CONFIG_M586 \ + 586/K5/5x86/6x86/6x86MX CONFIG_M586 \ Pentium/TSC CONFIG_M586TSC \ - PPro/6x86MX CONFIG_M686 \ + PPro CONFIG_M686 \ K6/II/III CONFIG_MK6 \ Athlon CONFIG_MK7" PPro # # Define implied options from the CPU selection here # -if [ "$CONFIG_M386" != "y" ]; then +if [ "$CONFIG_M386" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 16 +else define_bool CONFIG_X86_WP_WORKS_OK y define_bool CONFIG_X86_INVLPG y define_bool CONFIG_X86_CMPXCHG y define_bool CONFIG_X86_BSWAP y define_bool CONFIG_X86_POPAD_OK y fi -if [ "$CONFIG_M386" = "y" -o "$CONFIG_M486" = "y" ]; then - define_int CONFIG_X86_L1_CACHE_BYTES 16 -else - define_int CONFIG_X86_L1_CACHE_BYTES 32 -fi -if [ "$CONFIG_M486" = "y" -o "$CONFIG_M586" = "y" ]; then +if [ "$CONFIG_M486" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 16 define_bool CONFIG_X86_USE_STRING_486 y define_bool CONFIG_X86_ALIGNMENT_16 y fi -if [ "$CONFIG_M586TSC" = "y" ]; then +if [ "$CONFIG_M586" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 define_bool CONFIG_X86_USE_STRING_486 y define_bool CONFIG_X86_ALIGNMENT_16 y - define_bool CONFIG_X86_TSC y fi -if [ "$CONFIG_MK6" = "y" ]; then +if [ "$CONFIG_M586TSC" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 + define_bool CONFIG_X86_USE_STRING_486 y define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_TSC y - define_bool CONFIG_X86_USE_3DNOW y - define_bool CONFIG_X86_USE_PPRO_CHECKSUM y fi if [ "$CONFIG_M686" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_PGE y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y fi +if [ "$CONFIG_MK6" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_TSC y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y +fi if [ "$CONFIG_MK7" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 64 define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_USE_3DNOW y diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.99-pre5/linux/arch/i386/defconfig Tue Apr 11 15:09:12 2000 +++ linux/arch/i386/defconfig Mon Apr 24 15:53:19 2000 @@ -107,6 +107,7 @@ # # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_STRIPED is not set @@ -189,8 +190,8 @@ # CONFIG_IDEDMA_PCI_EXPERIMENTAL is not set # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC6210 is not set -# CONFIG_AEC6210_TUNING 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_AMD7409 is not set @@ -214,6 +215,7 @@ # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_VIA82CXXX_TUNING is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_IDEDMA_AUTO is not set CONFIG_BLK_DEV_IDE_MODES=y @@ -385,7 +387,10 @@ # CONFIG_PCMCIA_XIRC2PS is not set # CONFIG_ARCNET_COM20020_CS is not set # CONFIG_PCMCIA_IBMTR is not set -# CONFIG_PCMCIA_3C575 is not set + +# +# 3Com 3c575 moved to Ethernet 10/100 menu +# # CONFIG_PCMCIA_XIRTULIP is not set CONFIG_NET_PCMCIA_RADIO=y CONFIG_PCMCIA_RAYCS=y diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c --- v2.3.99-pre5/linux/arch/i386/kernel/acpi.c Tue Apr 11 15:09:12 2000 +++ linux/arch/i386/kernel/acpi.c Mon Apr 24 18:17:52 2000 @@ -583,6 +583,8 @@ dt = acpi_map_table(facp->dsdt); if (acpi_init_table(&acpi_dsdt, dt, 1)) acpi_unmap_table(dt); + + break; } else { acpi_unmap_table(dt); @@ -1127,6 +1129,7 @@ // finished sleeping, update system time acpi_update_clock(); acpi_enter_dx(ACPI_D0); + acpi_sleep_state = ACPI_S0; return 0; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c --- v2.3.99-pre5/linux/arch/i386/kernel/apic.c Sat Feb 12 11:22:10 2000 +++ linux/arch/i386/kernel/apic.c Wed Apr 12 09:33:19 2000 @@ -4,7 +4,9 @@ * (c) 1999, 2000 Ingo Molnar * * Fixes - * Maciej W. Rozycki : Bits for genuine 82489DX timers + * Maciej W. Rozycki : Bits for genuine 82489DX APICs; + * thanks to Eric Gilmore for + * testing these extensively */ #include @@ -44,32 +46,96 @@ return maxlvt; } -void disable_local_APIC (void) +static void clear_local_APIC(void) { - unsigned long value; - int maxlvt; + int maxlvt; + unsigned long v; + + maxlvt = get_maxlvt(); /* - * Disable APIC + * Careful: we have to set masks only first to deassert + * any level-triggered sources. */ - value = apic_read(APIC_SPIV); - value &= ~(1<<8); - apic_write(APIC_SPIV,value); + v = apic_read(APIC_LVTT); + apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); + v = apic_read(APIC_LVT0); + apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); + v = apic_read(APIC_LVT1); + apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED); + if (maxlvt >= 3) { + v = apic_read(APIC_LVTERR); + apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED); + } + if (maxlvt >= 4) { + v = apic_read(APIC_LVTPC); + apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED); + } /* * Clean APIC state for other OSs: */ - value = apic_read(APIC_SPIV); - value &= ~(1<<8); - apic_write(APIC_SPIV,value); - maxlvt = get_maxlvt(); - apic_write_around(APIC_LVTT, 0x00010000); - apic_write_around(APIC_LVT0, 0x00010000); - apic_write_around(APIC_LVT1, 0x00010000); + apic_write_around(APIC_LVTT, APIC_LVT_MASKED); + apic_write_around(APIC_LVT0, APIC_LVT_MASKED); + apic_write_around(APIC_LVT1, APIC_LVT_MASKED); if (maxlvt >= 3) - apic_write_around(APIC_LVTERR, 0x00010000); + apic_write_around(APIC_LVTERR, APIC_LVT_MASKED); if (maxlvt >= 4) - apic_write_around(APIC_LVTPC, 0x00010000); + apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); +} + +void __init connect_bsp_APIC(void) +{ + if (pic_mode) { + /* + * Do not trust the local APIC being empty at bootup. + */ + clear_local_APIC(); + /* + * PIC mode, enable symmetric IO mode in the IMCR, + * i.e. connect BSP's local APIC to INT and NMI lines. + */ + printk("leaving PIC mode, enabling symmetric IO mode.\n"); + outb(0x70, 0x22); + outb(0x01, 0x23); + } +} + +void disconnect_bsp_APIC(void) +{ + if (pic_mode) { + /* + * Put the board back into PIC mode (has an effect + * only on certain older boards). Note that APIC + * interrupts, including IPIs, won't work beyond + * this point! The only exception are INIT IPIs. + */ + printk("disabling symmetric IO mode, entering PIC mode.\n"); + outb(0x70, 0x22); + outb(0x00, 0x23); + } +} + +void disable_local_APIC(void) +{ + unsigned long value; + + clear_local_APIC(); + + /* + * Disable APIC (implies clearing of registers + * for 82489DX!). + */ + value = apic_read(APIC_SPIV); + value &= ~(1<<8); + apic_write_around(APIC_SPIV, value); +} + +void __init sync_Arb_IDs(void) +{ + Dprintk("Synchronizing Arb IDs.\n"); + apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG + | APIC_DM_INIT); } extern void __error_in_apic_c (void); @@ -78,6 +144,9 @@ { unsigned long value, ver, maxlvt; + value = apic_read(APIC_LVR); + ver = GET_APIC_VERSION(value); + if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f) __error_in_apic_c(); @@ -87,11 +156,12 @@ if (!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map)) BUG(); - value = apic_read(APIC_SPIV); + value = apic_read(APIC_SPIV); + value &= ~APIC_VECTOR_MASK; /* * Enable APIC */ - value |= (1<<8); + value |= (1<<8); /* * Some unknown Intel IO/APIC (or APIC) errata is biting us with @@ -108,7 +178,7 @@ */ #if 0 /* Enable focus processor (bit==0) */ - value &= ~(1<<9); + value &= ~(1<<9); #else /* Disable focus processor (bit==1) */ value |= (1<<9); @@ -117,7 +187,7 @@ * Set spurious IRQ vector */ value |= SPURIOUS_APIC_VECTOR; - apic_write(APIC_SPIV,value); + apic_write_around(APIC_SPIV, value); /* * Set up LVT0, LVT1: @@ -126,48 +196,44 @@ * strictly necessery in pure symmetric-IO mode, but sometimes * we delegate interrupts to the 8259A. */ - if (!smp_processor_id()) { - value = 0x00000700; + /* + * TODO: set up through-local-APIC from through-I/O-APIC? --macro + */ + value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; + if (!smp_processor_id() && (pic_mode || !value)) { + value = APIC_DM_EXTINT; printk("enabled ExtINT on CPU#%d\n", smp_processor_id()); } else { - value = 0x00010700; + value = APIC_DM_EXTINT | APIC_LVT_MASKED; printk("masked ExtINT on CPU#%d\n", smp_processor_id()); } - apic_write_around(APIC_LVT0,value); + apic_write_around(APIC_LVT0, value); /* * only the BP should see the LINT1 NMI signal, obviously. */ if (!smp_processor_id()) - value = 0x00000400; // unmask NMI + value = APIC_DM_NMI; else - value = 0x00010400; // mask NMI - apic_write_around(APIC_LVT1,value); + value = APIC_DM_NMI | APIC_LVT_MASKED; + if (!APIC_INTEGRATED(ver)) /* 82489DX */ + value |= APIC_LVT_LEVEL_TRIGGER; + apic_write_around(APIC_LVT1, value); - value = apic_read(APIC_LVR); - ver = GET_APIC_VERSION(value); if (APIC_INTEGRATED(ver)) { /* !82489DX */ maxlvt = get_maxlvt(); - /* - * Due to the Pentium erratum 3AP. - */ - if (maxlvt > 3) { - apic_readaround(APIC_SPIV); // not strictly necessery + if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ apic_write(APIC_ESR, 0); - } value = apic_read(APIC_ESR); printk("ESR value before enabling vector: %08lx\n", value); - value = apic_read(APIC_LVTERR); value = ERROR_APIC_VECTOR; // enables sending errors - apic_write(APIC_LVTERR,value); + apic_write_around(APIC_LVTERR, value); /* * spec says clear errors after enabling vector. */ - if (maxlvt != 3) { - apic_readaround(APIC_SPIV); + if (maxlvt > 3) apic_write(APIC_ESR, 0); - } value = apic_read(APIC_ESR); printk("ESR value after enabling vector: %08lx\n", value); } else @@ -177,22 +243,23 @@ * Set Task Priority to 'accept all'. We never change this * later on. */ - value = apic_read(APIC_TASKPRI); - value &= ~APIC_TPRI_MASK; - apic_write(APIC_TASKPRI,value); + value = apic_read(APIC_TASKPRI); + value &= ~APIC_TPRI_MASK; + apic_write_around(APIC_TASKPRI, value); /* * Set up the logical destination ID and put the * APIC into flat delivery mode. */ - value = apic_read(APIC_LDR); + value = apic_read(APIC_LDR); value &= ~APIC_LDR_MASK; value |= (1<<(smp_processor_id()+24)); - apic_write(APIC_LDR,value); + apic_write_around(APIC_LDR, value); - value = apic_read(APIC_DFR); - value |= SET_APIC_DFR(0xf); - apic_write(APIC_DFR, value); + /* + * Must be "all ones" explicitly for 82489DX. + */ + apic_write_around(APIC_DFR, 0xffffffff); } void __init init_apic_mappings(void) @@ -214,6 +281,13 @@ set_fixmap_nocache(FIX_APIC_BASE, apic_phys); Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); + /* + * Fetch the APIC ID of the BSP in case we have a + * default configuration (or the MP table is broken). + */ + if (boot_cpu_id == -1U) + boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID)); + #ifdef CONFIG_X86_IO_APIC { unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; @@ -285,7 +359,7 @@ * chipset timer can cause. */ - } while (delta<300); + } while (delta < 300); } /* @@ -305,21 +379,19 @@ { unsigned int lvtt1_value, tmp_value; - tmp_value = apic_read(APIC_LVTT); lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; - apic_write(APIC_LVTT, lvtt1_value); + apic_write_around(APIC_LVTT, lvtt1_value); /* * Divide PICLK by 16 */ tmp_value = apic_read(APIC_TDCR); - apic_write(APIC_TDCR, (tmp_value + apic_write_around(APIC_TDCR, (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) | APIC_TDR_DIV_16); - tmp_value = apic_read(APIC_TMICT); - apic_write(APIC_TMICT, clocks/APIC_DIVISOR); + apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR); } void setup_APIC_timer(void * data) @@ -353,6 +425,12 @@ t0 = apic_read(APIC_TMCCT)*APIC_DIVISOR; do { + /* + * It looks like the 82489DX cannot handle + * consecutive reads of the TMCCT register well; + * this dummy read prevents it from a lockup. + */ + apic_read(APIC_SPIV); t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR; delta = (int)(t0 - t1 - slice*(smp_processor_id()+1)); } while (delta < 0); @@ -490,6 +568,41 @@ #undef APIC_DIVISOR +#ifdef CONFIG_SMP +static inline void handle_smp_time (int user, int cpu) +{ + int system = !user; + struct task_struct * p = current; + /* + * After doing the above, we need to make like + * a normal interrupt - otherwise timer interrupts + * ignore the global interrupt lock, which is the + * WrongThing (tm) to do. + */ + + irq_enter(cpu, 0); + update_one_process(p, 1, user, system, cpu); + if (p->pid) { + p->counter -= 1; + if (p->counter <= 0) { + p->counter = 0; + p->need_resched = 1; + } + if (p->priority < DEF_PRIORITY) { + kstat.cpu_nice += user; + kstat.per_cpu_nice[cpu] += user; + } else { + kstat.cpu_user += user; + kstat.per_cpu_user[cpu] += user; + } + kstat.cpu_system += system; + kstat.per_cpu_system[cpu] += system; + + } + irq_exit(cpu, 0); +} +#endif + /* * Local timer interrupt handler. It does both profiling and * process statistics/rescheduling. @@ -502,7 +615,6 @@ inline void smp_local_timer_interrupt(struct pt_regs * regs) { - int user = (user_mode(regs) != 0); int cpu = smp_processor_id(); /* @@ -511,13 +623,8 @@ * updated with atomic operations). This is especially * useful with a profiling multiplier != 1 */ - if (!user) - x86_do_profile(regs->eip); if (--prof_counter[cpu] <= 0) { - int system = 1 - user; - struct task_struct * p = current; - /* * The multiplier may have changed since the last time we got * to this point as a result of the user writing to @@ -532,33 +639,9 @@ prof_old_multiplier[cpu] = prof_counter[cpu]; } - /* - * After doing the above, we need to make like - * a normal interrupt - otherwise timer interrupts - * ignore the global interrupt lock, which is the - * WrongThing (tm) to do. - */ - - irq_enter(cpu, 0); - update_one_process(p, 1, user, system, cpu); - if (p->pid) { - p->counter -= 1; - if (p->counter <= 0) { - p->counter = 0; - p->need_resched = 1; - } - if (p->priority < DEF_PRIORITY) { - kstat.cpu_nice += user; - kstat.per_cpu_nice[cpu] += user; - } else { - kstat.cpu_user += user; - kstat.per_cpu_user[cpu] += user; - } - kstat.cpu_system += system; - kstat.per_cpu_system[cpu] += system; - - } - irq_exit(cpu, 0); +#ifdef CONFIG_SMP + handle_smp_time(user_mode(regs), cpu); +#endif } /* @@ -603,7 +686,17 @@ */ asmlinkage void smp_spurious_interrupt(void) { - ack_APIC_irq(); + unsigned long v; + + /* + * Check if this really is a spurious interrupt and ACK it + * if it is a vectored one. Just in case... + * Spurious interrupts should not be ACKed. + */ + v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1)); + if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f))) + ack_APIC_irq(); + /* see sw-dev-man vol 3, chapter 7.4.13.5 */ printk("spurious APIC interrupt on CPU#%d, should never happen.\n", smp_processor_id()); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.3.99-pre5/linux/arch/i386/kernel/entry.S Mon Mar 27 08:08:21 2000 +++ linux/arch/i386/kernel/entry.S Mon Apr 24 13:39:34 2000 @@ -40,6 +40,7 @@ * "current" is in register %ebx during any slow entries. */ +#include #include #include #include @@ -201,7 +202,7 @@ call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value ENTRY(ret_from_sys_call) -#ifdef __SMP__ +#ifdef CONFIG_SMP movl processor(%ebx),%eax shll $5,%eax movl SYMBOL_NAME(softirq_state)(,%eax),%ecx @@ -256,7 +257,7 @@ ALIGN ret_from_exception: -#ifdef __SMP__ +#ifdef CONFIG_SMP GET_CURRENT(%ebx) movl processor(%ebx),%eax shll $5,%eax diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- v2.3.99-pre5/linux/arch/i386/kernel/head.S Tue Apr 11 15:09:12 2000 +++ linux/arch/i386/kernel/head.S Mon Apr 24 13:39:34 2000 @@ -51,7 +51,7 @@ movl %eax,%es movl %eax,%fs movl %eax,%gs -#ifdef __SMP__ +#ifdef CONFIG_SMP orw %bx,%bx jz 1f /* @@ -105,14 +105,14 @@ /* Set up the stack pointer */ lss stack_start,%esp -#ifdef __SMP__ +#ifdef CONFIG_SMP orw %bx,%bx jz 1f /* Initial CPU cleans BSS */ pushl $0 popfl jmp checkCPUtype 1: -#endif __SMP__ +#endif CONFIG_SMP /* * Clear BSS first so that there are no surprises... */ @@ -159,7 +159,7 @@ rep movsl 1: -#ifdef __SMP__ +#ifdef CONFIG_SMP checkCPUtype: #endif @@ -234,7 +234,7 @@ orl $2,%eax # set MP 2: movl %eax,%cr0 call check_x87 -#ifdef __SMP__ +#ifdef CONFIG_SMP incb ready #endif lgdt gdt_descr @@ -245,7 +245,7 @@ movl %eax,%es movl %eax,%fs movl %eax,%gs -#ifdef __SMP__ +#ifdef CONFIG_SMP movl $(__KERNEL_DS), %eax movl %eax,%ss # Reload the stack pointer (segment only) #else @@ -254,7 +254,7 @@ xorl %eax,%eax lldt %ax cld # gcc2 wants the direction flag cleared at all times -#ifdef __SMP__ +#ifdef CONFIG_SMP movb ready, %cl cmpb $1,%cl je 1f # the first CPU calls start_kernel @@ -268,7 +268,7 @@ jmp L6 # main should never return here, but # just in case, we know what happens. -#ifdef __SMP__ +#ifdef CONFIG_SMP ready: .byte 0 #endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.3.99-pre5/linux/arch/i386/kernel/i386_ksyms.c Sun Mar 19 18:35:30 2000 +++ linux/arch/i386/kernel/i386_ksyms.c Fri Apr 21 16:27:21 2000 @@ -27,6 +27,11 @@ extern int dump_fpu(elf_fpregset_t *); extern spinlock_t rtc_lock; +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) +extern void machine_real_restart(unsigned char *, int); +EXPORT_SYMBOL(machine_real_restart); +#endif + #ifdef CONFIG_SMP extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); @@ -68,7 +73,6 @@ EXPORT_SYMBOL_NOVERS(__down_read_failed); EXPORT_SYMBOL_NOVERS(__rwsem_wake); /* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy); EXPORT_SYMBOL(csum_partial_copy_generic); /* Delay loops */ EXPORT_SYMBOL(__udelay); @@ -84,7 +88,6 @@ EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); -EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strncpy_from_user); EXPORT_SYMBOL(__strncpy_from_user); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/i8259.c linux/arch/i386/kernel/i8259.c --- v2.3.99-pre5/linux/arch/i386/kernel/i8259.c Mon Mar 27 08:08:21 2000 +++ linux/arch/i386/kernel/i8259.c Wed Apr 12 09:33:19 2000 @@ -415,7 +415,7 @@ for (i = 0; i < NR_IRQS; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = 0; - irq_desc[i].depth = 0; + irq_desc[i].depth = 1; if (i < 16) { /* diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.3.99-pre5/linux/arch/i386/kernel/io_apic.c Mon Mar 27 08:08:21 2000 +++ linux/arch/i386/kernel/io_apic.c Wed Apr 12 09:33:19 2000 @@ -13,7 +13,9 @@ * and Ingo Molnar * * Fixes - * Maciej W. Rozycki : Bits for genuine 82489DX APICs + * Maciej W. Rozycki : Bits for genuine 82489DX APICs; + * thanks to Eric Gilmore for + * testing these extensively */ #include @@ -46,9 +48,6 @@ /* MP IRQ source entries */ int mp_irq_entries = 0; -/* non-0 if default (table-less) MP configuration */ -int mpc_default_type = 0; - /* * Rough estimation of how many shared IRQs there are, can * be changed anytime. @@ -166,7 +165,7 @@ #define MAX_PIRQS 8 int pirq_entries [MAX_PIRQS]; -int pirqs_enabled; +int pirqs_enabled = 0; int skip_ioapic_setup = 0; static int __init ioapic_setup(char *str) @@ -235,7 +234,8 @@ int lbus = mp_irqs[i].mpc_srcbus; if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || - mp_bus_id_to_type[lbus] == MP_BUS_EISA) && + mp_bus_id_to_type[lbus] == MP_BUS_EISA || + mp_bus_id_to_type[lbus] == MP_BUS_MCA) && (mp_irqs[i].mpc_irqtype == type) && (mp_irqs[i].mpc_srcbusirq == 0x00)) @@ -260,13 +260,15 @@ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) break; - if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) && - (mp_bus_id_to_type[lbus] == MP_BUS_PCI) && + if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) && !mp_irqs[i].mpc_irqtype && (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) && (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); + if (!(apic || IO_APIC_IRQ(irq))) + continue; + if (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3)) return irq; /* @@ -298,15 +300,27 @@ * EISA conforming in the MP table, that means its trigger type must * be read in from the ELCR */ -#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_dstirq)) +#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq)) #define default_EISA_polarity(idx) (0) -/* ISA interrupts are always polarity zero edge triggered, even when - * listed as conforming in the MP table. */ +/* ISA interrupts are always polarity zero edge triggered, + * when listed as conforming in the MP table. */ #define default_ISA_trigger(idx) (0) #define default_ISA_polarity(idx) (0) +/* PCI interrupts are always polarity one level triggered, + * when listed as conforming in the MP table. */ + +#define default_PCI_trigger(idx) (1) +#define default_PCI_polarity(idx) (1) + +/* MCA interrupts are always polarity zero level triggered, + * when listed as conforming in the MP table. */ + +#define default_MCA_trigger(idx) (1) +#define default_MCA_polarity(idx) (0) + static int __init MPBIOS_polarity(int idx) { int bus = mp_irqs[idx].mpc_srcbus; @@ -326,14 +340,19 @@ polarity = default_ISA_polarity(idx); break; } - case MP_BUS_EISA: + case MP_BUS_EISA: /* EISA pin */ { polarity = default_EISA_polarity(idx); break; } case MP_BUS_PCI: /* PCI pin */ { - polarity = 1; + polarity = default_PCI_polarity(idx); + break; + } + case MP_BUS_MCA: /* MCA pin */ + { + polarity = default_MCA_polarity(idx); break; } default: @@ -385,19 +404,24 @@ { switch (mp_bus_id_to_type[bus]) { - case MP_BUS_ISA: + case MP_BUS_ISA: /* ISA pin */ { trigger = default_ISA_trigger(idx); break; } - case MP_BUS_EISA: + case MP_BUS_EISA: /* EISA pin */ { trigger = default_EISA_trigger(idx); break; } - case MP_BUS_PCI: /* PCI pin, level */ + case MP_BUS_PCI: /* PCI pin */ { - trigger = 1; + trigger = default_PCI_trigger(idx); + break; + } + case MP_BUS_MCA: /* MCA pin */ + { + trigger = default_MCA_trigger(idx); break; } default: @@ -460,6 +484,7 @@ { case MP_BUS_ISA: /* ISA pin */ case MP_BUS_EISA: + case MP_BUS_MCA: { irq = mp_irqs[idx].mpc_srcbusirq; break; @@ -624,8 +649,8 @@ disable_8259A_irq(0); - apic_readaround(APIC_LVT0); - apic_write(APIC_LVT0, 0x00010700); // mask LVT0 + /* mask LVT0 */ + apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); init_8259A(1); @@ -650,8 +675,8 @@ /* * Add it to the IO-APIC irq-routing table: */ - io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1)); + io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); enable_8259A_irq(0); } @@ -725,8 +750,8 @@ printk(KERN_DEBUG ".... IRQ redirection table:\n"); - printk(KERN_DEBUG " NR Log Phy "); - printk(KERN_DEBUG "Mask Trig IRR Pol Stat Dest Deli Vect: \n"); + printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol" + " Stat Dest Deli Vect: \n"); for (i = 0; i <= reg_01.entries; i++) { struct IO_APIC_route_entry entry; @@ -831,13 +856,8 @@ print_APIC_bitfield(APIC_IRR); if (APIC_INTEGRATED(ver)) { /* !82489DX */ - /* - * Due to the Pentium erratum 3AP. - */ - if (maxlvt > 3) { - apic_readaround(APIC_SPIV); // not strictly necessery + if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ apic_write(APIC_ESR, 0); - } v = apic_read(APIC_ESR); printk(KERN_DEBUG "... APIC ESR: %08x\n", v); } @@ -879,6 +899,32 @@ print_local_APIC(NULL); } +void /*__init*/ print_PIC(void) +{ + unsigned int v, flags; + + printk(KERN_DEBUG "\nprinting PIC contents\n"); + + v = inb(0xa1) << 8 | inb(0x21); + printk(KERN_DEBUG "... PIC IMR: %04x\n", v); + + v = inb(0xa0) << 8 | inb(0x20); + printk(KERN_DEBUG "... PIC IRR: %04x\n", v); + + __save_flags(flags); + __cli(); + outb(0x0b,0xa0); + outb(0x0b,0x20); + v = inb(0xa0) << 8 | inb(0x20); + outb(0x0a,0xa0); + outb(0x0a,0x20); + __restore_flags(flags); + printk(KERN_DEBUG "... PIC ISR: %04x\n", v); + + v = inb(0x4d1) << 8 | inb(0x4d0); + printk(KERN_DEBUG "... PIC ELCR: %04x\n", v); +} + static void __init enable_IO_APIC(void) { struct IO_APIC_reg_01 reg_01; @@ -890,16 +936,7 @@ } if (!pirqs_enabled) for (i = 0; i < MAX_PIRQS; i++) - pirq_entries[i] =- 1; - - if (pic_mode) { - /* - * PIC mode, enable symmetric IO mode in the IMCR. - */ - printk("leaving PIC mode, enabling symmetric IO mode.\n"); - outb(0x70, 0x22); - outb(0x01, 0x23); - } + pirq_entries[i] = -1; /* * The number of IO-APIC IRQ registers (== #pins): @@ -925,15 +962,7 @@ */ clear_IO_APIC(); - /* - * Put it back into PIC mode (has an effect only on - * certain older boards) - */ - if (pic_mode) { - printk("disabling symmetric IO mode, entering PIC mode.\n"); - outb_p(0x70, 0x22); - outb_p(0x00, 0x23); - } + disconnect_bsp_APIC(); } /* @@ -986,48 +1015,6 @@ } } -static void __init construct_default_ISA_mptable(void) -{ - int i, pos = 0; - const int bus_type = (mpc_default_type == 2 || mpc_default_type == 3 || - mpc_default_type == 6) ? MP_BUS_EISA : MP_BUS_ISA; - - for (i = 0; i < 16; i++) { - if (!IO_APIC_IRQ(i)) - continue; - - mp_irqs[pos].mpc_irqtype = mp_INT; - mp_irqs[pos].mpc_irqflag = 0; /* default */ - mp_irqs[pos].mpc_srcbus = 0; - mp_irqs[pos].mpc_srcbusirq = i; - mp_irqs[pos].mpc_dstapic = 0; - mp_irqs[pos].mpc_dstirq = i; - pos++; - } - mp_irq_entries = pos; - mp_bus_id_to_type[0] = bus_type; - - /* - * MP specification 1.4 defines some extra rules for default - * configurations, fix them up here: - */ - switch (mpc_default_type) - { - case 2: - /* - * IRQ0 is not connected: - */ - mp_irqs[0].mpc_irqtype = mp_ExtINT; - break; - default: - /* - * pin 2 is IRQ0: - */ - mp_irqs[0].mpc_dstirq = 2; - } - -} - /* * There is a nasty bug in some older SMP boards, their mptable lies * about the timer IRQ. We do the following to work around the situation: @@ -1041,9 +1028,17 @@ unsigned int t1 = jiffies; sti(); - mdelay(40); + /* Let ten ticks pass... */ + mdelay((10 * 1000) / HZ); - if (jiffies-t1>1) + /* + * Expect a few ticks at least, to be sure some possible + * glue logic does not lock up after one or two first + * ticks in a non-ExtINT mode. Also the local APIC + * might have cached one ExtINT interrupt. Finally, at + * least one tick may be lost due to delays. + */ + if (jiffies - t1 > 4) return 1; return 0; @@ -1257,8 +1252,14 @@ static void enable_NMI_through_LVT0 (void * dummy) { - apic_readaround(APIC_LVT0); - apic_write(APIC_LVT0, 0x00000400); // unmask and set to NMI + unsigned int v, ver; + + ver = apic_read(APIC_LVR); + ver = GET_APIC_VERSION(ver); + v = APIC_DM_NMI; /* unmask and set to NMI */ + if (!APIC_INTEGRATED(ver)) /* 82489DX */ + v |= APIC_LVT_LEVEL_TRIGGER; + apic_write_around(APIC_LVT0, v); } static void setup_nmi (void) @@ -1303,24 +1304,23 @@ printk(KERN_INFO "..TIMER: vector=%d pin1=%d pin2=%d\n", vector, pin1, pin2); - /* - * Ok, does IRQ0 through the IOAPIC work? - */ - if (timer_irq_works()) { - if (nmi_watchdog) { - disable_8259A_irq(0); - init_8259A(1); - setup_nmi(); - enable_8259A_irq(0); - if (nmi_irq_works()) - return; - } else - return; - } - if (pin1 != -1) { - printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); + /* + * Ok, does IRQ0 through the IOAPIC work? + */ + unmask_IO_APIC_irq(0); + if (timer_irq_works()) { + if (nmi_watchdog) { + disable_8259A_irq(0); + init_8259A(1); + setup_nmi(); + enable_8259A_irq(0); + nmi_irq_works(); + } + return; + } clear_IO_APIC_pin(0, pin1); + printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); } printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); @@ -1334,10 +1334,9 @@ printk("works.\n"); if (nmi_watchdog) { setup_nmi(); - if (nmi_irq_works()) - return; - } else - return; + nmi_irq_works(); + } + return; } /* * Cleanup, just in case ... @@ -1355,9 +1354,8 @@ disable_8259A_irq(0); irq_desc[0].handler = &lapic_irq_type; - init_8259A(1); // AEOI mode - apic_readaround(APIC_LVT0); - apic_write(APIC_LVT0, 0x00000000 | vector); // Fixed mode + init_8259A(1); /* AEOI mode */ + apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ enable_8259A_irq(0); if (timer_irq_works()) { @@ -1392,20 +1390,11 @@ printk("ENABLING IO-APIC IRQs\n"); /* - * If there are no explicit MP IRQ entries, it's either one of the - * default configuration types or we are broken. In both cases it's - * fine to set up most of the low 16 IO-APIC pins to ISA defaults. - */ - if (!mp_irq_entries) { - printk("no explicit IRQ entries, using default mptable\n"); - construct_default_ISA_mptable(); - } - - /* * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS * mptable: */ setup_ioapic_ids_from_mpc(); + sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); @@ -1421,6 +1410,7 @@ { if (!smp_found_config) return; + connect_bsp_APIC(); setup_local_APIC(); setup_IO_APIC(); setup_APIC_clocks(); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.3.99-pre5/linux/arch/i386/kernel/irq.c Tue Apr 11 15:09:12 2000 +++ linux/arch/i386/kernel/irq.c Wed Apr 12 09:38:52 2000 @@ -462,8 +462,8 @@ * @irq: Interrupt to disable * * Disable the selected interrupt line. Disables of an interrupt - * stack. Unlike disable_irq, this function does not ensure existing - * instances of the irq handler have completed before returning. + * stack. Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. * * This function may be called from IRQ context. */ @@ -1127,7 +1127,7 @@ irq_dir[irq] = proc_mkdir(name, root_irq_dir); /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); entry->nlink = 1; entry->data = (void *)(long)irq; @@ -1148,7 +1148,7 @@ root_irq_dir = proc_mkdir("irq", 0); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir); + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); entry->nlink = 1; entry->data = (void *)&prof_cpu_mask; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c --- v2.3.99-pre5/linux/arch/i386/kernel/mca.c Tue Mar 14 19:10:39 2000 +++ linux/arch/i386/kernel/mca.c Wed Apr 12 09:38:52 2000 @@ -366,12 +366,12 @@ /** * mca_find_adapter - scan for adapters * @id: MCA identification to search for - * @start: Starting slot + * @start: starting slot * * Search the MCA configuration for adapters matching the 16bit * ID given. The first time it should be called with start as zero * and then further calls made passing the return value of the - * previous call until MCA_NOTFOUND is returned. + * previous call until %MCA_NOTFOUND is returned. * * Disabled adapters are not reported. */ @@ -411,12 +411,12 @@ /** * mca_find_unused_adapter - scan for unused adapters * @id: MCA identification to search for - * @start: Starting slot + * @start: starting slot * * Search the MCA configuration for adapters matching the 16bit * ID given. The first time it should be called with start as zero * and then further calls made passing the return value of the - * previous call until MCA_NOTFOUND is returned. + * previous call until %MCA_NOTFOUND is returned. * * Adapters that have been claimed by drivers and those that * are disabled are not reported. This function thus allows a driver @@ -647,10 +647,10 @@ * function is called with the buffer, slot, and device pointer (or * some equally informative context information, or nothing, if you * prefer), and is expected to put useful information into the - * buffer. The adapter name, id, and POS registers get printed + * buffer. The adapter name, ID, and POS registers get printed * before this is called though, so don't do it again. * - * This should be called with a NULL procfn when a module + * This should be called with a %NULL @procfn when a module * unregisters, thus preventing kernel crashes and other such * nastiness. */ diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/mpparse.c linux/arch/i386/kernel/mpparse.c --- v2.3.99-pre5/linux/arch/i386/kernel/mpparse.c Sat Feb 26 22:31:39 2000 +++ linux/arch/i386/kernel/mpparse.c Wed Apr 12 09:33:19 2000 @@ -9,7 +9,7 @@ * Erich Boleyn : MP v1.4 and additional changes. * Alan Cox : Added EBDA scanning * Ingo Molnar : various cleanups and rewrites - * Maciej W. Rozycki : Bits for genuine 82489DX APICs + * Maciej W. Rozycki : Bits for default MP configurations */ #include @@ -34,7 +34,7 @@ * Various Linux-internal data structures created from the * MP-table. */ -int apic_version [NR_CPUS]; +int apic_version [MAX_APICS]; int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, }; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, }; int mp_current_pci_id = 0; @@ -42,9 +42,9 @@ unsigned long mp_lapic_addr = 0; /* Processor that is doing the boot up */ -unsigned int boot_cpu_id = 0; +unsigned int boot_cpu_id = -1U; /* Internal processor count */ -static unsigned int num_processors = 1; +static unsigned int num_processors = 0; /* Bitmask of physically existing CPUs */ unsigned long phys_cpu_present_map = 0; @@ -132,13 +132,12 @@ if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { Dprintk(" Bootup CPU\n"); boot_cpu_id = m->mpc_apicid; - } else - /* Boot CPU already counted */ - num_processors++; + } + num_processors++; - if (m->mpc_apicid > NR_CPUS) { - printk("Processor #%d unused. (Max %d processors).\n", - m->mpc_apicid, NR_CPUS); + if (m->mpc_apicid > MAX_APICS) { + printk("Processor #%d INVALID. (Max ID: %d).\n", + m->mpc_apicid, MAX_APICS); return; } ver = m->mpc_apicver; @@ -164,18 +163,18 @@ if (strncmp(str, "ISA", 3) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; - } else { - if (strncmp(str, "EISA", 4) == 0) { + } else if (strncmp(str, "EISA", 4) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA; - } else { - if (strncmp(str, "PCI", 3) == 0) { + } else if (strncmp(str, "PCI", 3) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id; mp_current_pci_id++; + } else if (strncmp(str, "MCA", 3) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA; } else { printk("Unknown bustype %s\n", str); panic("cannot handle bus - mail to linux-smp@vger.rutgers.edu"); - } } } + } } static void __init MP_ioapic_info (struct mpc_config_ioapic *m) @@ -197,12 +196,22 @@ static void __init MP_intsrc_info (struct mpc_config_intsrc *m) { mp_irqs [mp_irq_entries] = *m; + Dprintk("Int: type %d, pol %d, trig %d, bus %d," + " IRQ %02x, APIC ID %x, APIC INT %02x\n", + m->mpc_irqtype, m->mpc_irqflag & 3, + (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus, + m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq); if (++mp_irq_entries == MAX_IRQ_SOURCES) panic("Max # of irq sources exceeded!!\n"); } static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m) { + Dprintk("Lint: type %d, pol %d, trig %d, bus %d," + " IRQ %02x, APIC ID %x, APIC LINT %02x\n", + m->mpc_irqtype, m->mpc_irqflag & 3, + (m->mpc_irqflag >> 2) &3, m->mpc_srcbusid, + m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint); /* * Well it seems all SMP boards in existence * use ExtINT/LVT1 == LINT0 and @@ -316,6 +325,122 @@ return num_processors; } +static void __init construct_default_ioirq_mptable(int mpc_default_type) +{ + struct mpc_config_intsrc intsrc; + int i; + + intsrc.mpc_type = MP_INTSRC; + intsrc.mpc_irqflag = 0; /* conforming */ + intsrc.mpc_srcbus = 0; + intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid; + + intsrc.mpc_irqtype = mp_INT; + for (i = 0; i < 16; i++) { + switch (mpc_default_type) { + case 2: + if (i == 0 || i == 13) + continue; /* IRQ0 & IRQ13 not connected */ + /* fall through */ + default: + if (i == 2) + continue; /* IRQ2 is never connected */ + } + + intsrc.mpc_srcbusirq = i; + intsrc.mpc_dstirq = i ? i : 2; /* IRQ0 to INTIN2 */ + MP_intsrc_info(&intsrc); + } + + intsrc.mpc_irqtype = mp_ExtINT; + intsrc.mpc_srcbusirq = 0; + intsrc.mpc_dstirq = 0; /* 8259A to INTIN0 */ + MP_intsrc_info(&intsrc); +} + +static inline void __init construct_default_ISA_mptable(int mpc_default_type) +{ + struct mpc_config_processor processor; + struct mpc_config_bus bus; + struct mpc_config_ioapic ioapic; + struct mpc_config_lintsrc lintsrc; + int linttypes[2] = { mp_ExtINT, mp_NMI }; + int i; + + /* + * local APIC has default address + */ + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + + /* + * 2 CPUs, numbered 0 & 1. + */ + processor.mpc_type = MP_PROCESSOR; + /* Either an integrated APIC or a discrete 82489DX. */ + processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01; + processor.mpc_cpuflag = CPU_ENABLED; + processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | + (boot_cpu_data.x86_model << 4) | + boot_cpu_data.x86_mask; + processor.mpc_featureflag = boot_cpu_data.x86_capability; + processor.mpc_reserved[0] = 0; + processor.mpc_reserved[1] = 0; + for (i = 0; i < 2; i++) { + processor.mpc_apicid = i; + MP_processor_info(&processor); + } + + bus.mpc_type = MP_BUS; + bus.mpc_busid = 0; + switch (mpc_default_type) { + default: + printk("???\nUnknown standard configuration %d\n", + mpc_default_type); + /* fall through */ + case 1: + case 5: + memcpy(bus.mpc_bustype, "ISA ", 6); + break; + case 2: + case 6: + case 3: + memcpy(bus.mpc_bustype, "EISA ", 6); + break; + case 4: + case 7: + memcpy(bus.mpc_bustype, "MCA ", 6); + } + MP_bus_info(&bus); + if (mpc_default_type > 4) { + bus.mpc_busid = 1; + memcpy(bus.mpc_bustype, "PCI ", 6); + MP_bus_info(&bus); + } + + ioapic.mpc_type = MP_IOAPIC; + ioapic.mpc_apicid = 2; + ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01; + ioapic.mpc_flags = MPC_APIC_USABLE; + ioapic.mpc_apicaddr = 0xFEC00000; + MP_ioapic_info(&ioapic); + + /* + * We set up most of the low 16 IO-APIC pins according to MPS rules. + */ + construct_default_ioirq_mptable(mpc_default_type); + + lintsrc.mpc_type = MP_LINTSRC; + lintsrc.mpc_irqflag = 0; /* conforming */ + lintsrc.mpc_srcbusid = 0; + lintsrc.mpc_srcbusirq = 0; + lintsrc.mpc_destapic = MP_APIC_ALL; + for (i = 0; i < 2; i++) { + lintsrc.mpc_irqtype = linttypes[i]; + lintsrc.mpc_destapiclint = i; + MP_lintsrc_info(&lintsrc); + } +} + static struct intel_mp_floating *mpf_found; /* @@ -332,83 +457,43 @@ printk(" Virtual Wire compatibility mode.\n"); pic_mode = 0; } - /* - * default CPU id - if it's different in the mptable - * then we change it before first using it. - */ - boot_cpu_id = 0; + /* * Now see if we need to read further. */ if (mpf->mpf_feature1 != 0) { + printk("Default MP configuration #%d\n", mpf->mpf_feature1); + construct_default_ISA_mptable(mpf->mpf_feature1); - /* - * local APIC has default address - */ - mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + } else if (mpf->mpf_physptr) { /* - * 2 CPUs, numbered 0 & 1. + * Read the physical hardware table. Anything here will + * override the defaults. */ - phys_cpu_present_map = 3; - num_processors = 2; + smp_read_mpc((void *)mpf->mpf_physptr); - nr_ioapics = 1; - mp_ioapics[0].mpc_apicaddr = 0xFEC00000; - mp_ioapics[0].mpc_apicid = 2; /* - * Save the default type number, we - * need it later to set the IO-APIC - * up properly: + * If there are no explicit MP IRQ entries, then we are + * broken. We set up most of the low 16 IO-APIC pins to + * ISA defaults and hope it will work. */ - mpc_default_type = mpf->mpf_feature1; + if (!mp_irq_entries) { + struct mpc_config_bus bus; - printk("Bus #0 is "); - } + printk("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); - switch (mpf->mpf_feature1) { - case 1: - case 5: - printk("ISA\n"); - break; - case 2: - printk("EISA with no IRQ0 and no IRQ13 DMA chaining\n"); - break; - case 6: - case 3: - printk("EISA\n"); - break; - case 4: - case 7: - printk("MCA\n"); - break; - case 0: - if (!mpf->mpf_physptr) - BUG(); - break; - default: - printk("???\nUnknown standard configuration %d\n", - mpf->mpf_feature1); - return; - } - if (mpf->mpf_feature1 > 4) { - printk("Bus #1 is PCI\n"); + bus.mpc_type = MP_BUS; + bus.mpc_busid = 0; + memcpy(bus.mpc_bustype, "ISA ", 6); + MP_bus_info(&bus); - /* - * Set local APIC version to the integrated form. - * It's initialized to zero otherwise, representing - * a discrete 82489DX. - */ - apic_version[0] = 0x10; - apic_version[1] = 0x10; - } - /* - * Read the physical hardware table. Anything here will override the - * defaults. - */ - if (mpf->mpf_physptr) - smp_read_mpc((void *)mpf->mpf_physptr); + construct_default_ioirq_mptable(0); + } + + } else + BUG(); printk("Processors: %d\n", num_processors); /* diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.3.99-pre5/linux/arch/i386/kernel/mtrr.c Tue Apr 11 15:09:12 2000 +++ linux/arch/i386/kernel/mtrr.c Mon Apr 24 13:39:34 2000 @@ -289,7 +289,7 @@ #define MTRRfix4K_F0000_MSR 0x26e #define MTRRfix4K_F8000_MSR 0x26f -#ifdef __SMP__ +#ifdef CONFIG_SMP # define MTRR_CHANGE_MASK_FIXED 0x01 # define MTRR_CHANGE_MASK_VARIABLE 0x02 # define MTRR_CHANGE_MASK_DEFTYPE 0x04 @@ -302,7 +302,7 @@ #define LINE_SIZE 80 #define JIFFIE_TIMEOUT 100 -#ifdef __SMP__ +#ifdef CONFIG_SMP # define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type) #else # define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \ @@ -767,7 +767,7 @@ unsigned long size, mtrr_type type, int do_safe) = NULL; -#ifdef __SMP__ +#ifdef CONFIG_SMP struct mtrr_var_range { @@ -1015,7 +1015,7 @@ printk ("mtrr: probably your BIOS does not setup all CPUs\n"); } /* End Function mtrr_state_warn */ -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ static char *attrib_to_str (int x) { @@ -1110,7 +1110,7 @@ * * Memory type region registers control the caching on newer Intel and * non Intel processors. This function allows drivers to request an - * MTRR is added. The details and hardware specifics of each processors + * MTRR is added. The details and hardware specifics of each processor's * implementation are hidden from the caller, but nevertheless the * caller should expect to need to provide a power of two size on an * equivalent power of two boundary. @@ -1125,13 +1125,13 @@ * * The available types are * - * MTRR_TYPE_UNCACHEABLE - No caching + * %MTRR_TYPE_UNCACHEABLE - No caching * - * MTRR_TYPE_WRITEBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever * - * MTRR_TYPE_WRCOMB - Write data back soon but allow bursts + * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * - * MTRR_TYPE_WRTHROUGH - Cache reads but not writes + * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes * * BUGS: Needs a quiet flag for the cases where drivers do not mind * failures and do not wish system log messages to be sent. @@ -1608,7 +1608,7 @@ EXPORT_SYMBOL(mtrr_add); EXPORT_SYMBOL(mtrr_del); -#ifdef __SMP__ +#ifdef CONFIG_SMP typedef struct { @@ -1663,7 +1663,7 @@ struct set_mtrr_context ctxt; unsigned char ccr[7]; int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 }; -#ifdef __SMP__ +#ifdef CONFIG_SMP int i; #endif @@ -1709,7 +1709,7 @@ setCx86 (CX86_CCR5, ccr[5]); } -#ifdef __SMP__ +#ifdef CONFIG_SMP for(i=0; i<7; i++) ccr_state[i] = ccr[i]; for(i=0; i<8; i++) cyrix_get_arr(i, @@ -1782,7 +1782,7 @@ } } /* End Function mtrr_setup */ -#ifdef __SMP__ +#ifdef CONFIG_SMP static volatile unsigned long smp_changes_mask __initdata = 0; static struct mtrr_state smp_mtrr_state __initdata = {0, 0}; @@ -1851,12 +1851,12 @@ break; } } /* End Function mtrr_init_secondary_cpu */ -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ int __init mtrr_init(void) { if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0; -#ifdef __SMP__ +#ifdef CONFIG_SMP switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: @@ -1866,7 +1866,7 @@ mtrr_state_warn (smp_changes_mask); break; } -#else /* __SMP__ */ +#else /* CONFIG_SMP */ mtrr_setup (); switch (boot_cpu_data.x86_vendor) { @@ -1877,7 +1877,7 @@ centaur_mcr_init (); break; } -#endif /* !__SMP__ */ +#endif /* !CONFIG_SMP */ #ifdef CONFIG_PROC_FS proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c --- v2.3.99-pre5/linux/arch/i386/kernel/pci-irq.c Wed Apr 12 10:02:34 2000 +++ linux/arch/i386/kernel/pci-irq.c Sat Apr 15 21:12:11 2000 @@ -29,7 +29,7 @@ * Avoid using: 13, 14 and 15 (FP error and IDE). * Penalize: 3, 4, 7, 12 (known ISA uses: serial, parallel and mouse) */ -unsigned int pcibios_irq_mask = ~0; +unsigned int pcibios_irq_mask = 0xfff8; static unsigned pirq_penalty[16] = { 10000, 10000, 10000, 100, 100, 0, 0, 100, @@ -305,10 +305,7 @@ return 0; } DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs); - if (pcibios_irq_mask != ~0) - mask &= pcibios_irq_mask; - else - mask &= pirq_table->exclusive_irqs; + mask &= pcibios_irq_mask; /* Find the best IRQ to assign */ newirq = 0; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.3.99-pre5/linux/arch/i386/kernel/process.c Fri Mar 10 16:40:39 2000 +++ linux/arch/i386/kernel/process.c Tue Apr 25 17:45:43 2000 @@ -589,7 +589,6 @@ * More important, however, is the fact that this allows us much * more flexibility. */ -extern int cpus_initialized; void __switch_to(struct task_struct *prev_p, struct task_struct *next_p) { struct thread_struct *prev = &prev_p->thread, diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.99-pre5/linux/arch/i386/kernel/setup.c Tue Apr 11 15:09:12 2000 +++ linux/arch/i386/kernel/setup.c Tue Apr 25 17:45:43 2000 @@ -495,6 +495,10 @@ if (!memcmp(from+4, "nopentium", 9)) { from += 9+4; boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE; + } else if (!memcmp(from+4, "exactmap", 8)) { + from += 8+4; + e820.nr_map = 0; + usermem = 1; } else { /* If the user specifies memory size, we * blow away any automatically generated @@ -1531,8 +1535,7 @@ return p - buffer; } -int cpus_initialized = 0; -unsigned long cpu_initialized = 0; +static unsigned long cpu_initialized __initdata = 0; /* * cpu_init() initializes state that is per-CPU. Some data is already @@ -1549,7 +1552,6 @@ printk("CPU#%d already initialized!\n", nr); for (;;) __sti(); } - cpus_initialized++; printk("Initializing CPU#%d\n", nr); if (cpu_has_vme || cpu_has_tsc || cpu_has_de) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.3.99-pre5/linux/arch/i386/kernel/signal.c Mon Mar 27 08:08:21 2000 +++ linux/arch/i386/kernel/signal.c Tue Apr 25 17:52:01 2000 @@ -339,9 +339,9 @@ int tmp, err = 0; tmp = 0; - __asm__("movl %%gs,%w0" : "=r"(tmp): "0"(tmp)); + __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); err |= __put_user(tmp, (unsigned int *)&sc->gs); - __asm__("movl %%fs,%w0" : "=r"(tmp): "0"(tmp)); + __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); err |= __put_user(tmp, (unsigned int *)&sc->fs); err |= __put_user(regs->xes, (unsigned int *)&sc->es); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.3.99-pre5/linux/arch/i386/kernel/smp.c Sat Feb 12 11:22:10 2000 +++ linux/arch/i386/kernel/smp.c Wed Apr 12 09:33:20 2000 @@ -111,108 +111,26 @@ * We use 'broadcast', CPU->CPU IPIs and self-IPIs too. */ -static unsigned int cached_APIC_ICR; -static unsigned int cached_APIC_ICR2; - -/* - * Caches reserved bits, APIC reads are (mildly) expensive - * and force otherwise unnecessary CPU synchronization. - * - * (We could cache other APIC registers too, but these are the - * main ones used in RL.) - */ -#define slow_ICR (apic_read(APIC_ICR) & ~0xFDFFF) -#define slow_ICR2 (apic_read(APIC_ICR2) & 0x00FFFFFF) - -void cache_APIC_registers (void) -{ - cached_APIC_ICR = slow_ICR; - cached_APIC_ICR2 = slow_ICR2; - mb(); -} - -static inline unsigned int __get_ICR (void) -{ -#if FORCE_READ_AROUND_WRITE - /* - * Wait for the APIC to become ready - this should never occur. It's - * a debugging check really. - */ - int count = 0; - unsigned int cfg; - - while (count < 1000) - { - cfg = slow_ICR; - if (!(cfg&(1<<12))) - return cfg; - printk("CPU #%d: ICR still busy [%08x]\n", - smp_processor_id(), cfg); - irq_err_count++; - count++; - udelay(10); - } - printk("CPU #%d: previous IPI still not cleared after 10mS\n", - smp_processor_id()); - return cfg; -#else - return cached_APIC_ICR; -#endif -} - -static inline unsigned int __get_ICR2 (void) -{ -#if FORCE_READ_AROUND_WRITE - return slow_ICR2; -#else - return cached_APIC_ICR2; -#endif -} - -#define LOGICAL_DELIVERY 1 - static inline int __prepare_ICR (unsigned int shortcut, int vector) { - unsigned int cfg; - - cfg = __get_ICR(); - cfg |= APIC_DEST_DM_FIXED|shortcut|vector -#if LOGICAL_DELIVERY - |APIC_DEST_LOGICAL -#endif - ; - - return cfg; + return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL; } static inline int __prepare_ICR2 (unsigned int mask) { - unsigned int cfg; - - cfg = __get_ICR2(); -#if LOGICAL_DELIVERY - cfg |= SET_APIC_DEST_FIELD(mask); -#else - cfg |= SET_APIC_DEST_FIELD(mask); -#endif - - return cfg; + return SET_APIC_DEST_FIELD(mask); } static inline void __send_IPI_shortcut(unsigned int shortcut, int vector) { + /* + * Subtle. In the case of the 'never do double writes' workaround + * we have to lock out interrupts to be safe. As we don't care + * of the value read we use an atomic rmw access to avoid costly + * cli/sti. Otherwise we use an even cheaper single atomic write + * to the APIC. + */ unsigned int cfg; -/* - * Subtle. In the case of the 'never do double writes' workaround we - * have to lock out interrupts to be safe. Otherwise it's just one - * single atomic write to the APIC, no need for cli/sti. - */ -#if FORCE_READ_AROUND_WRITE - unsigned long flags; - - __save_flags(flags); - __cli(); -#endif /* * No need to touch the target chip field @@ -222,10 +140,7 @@ /* * Send the IPI. The write to APIC_ICR fires this off. */ - apic_write(APIC_ICR, cfg); -#if FORCE_READ_AROUND_WRITE - __restore_flags(flags); -#endif + apic_write_around(APIC_ICR, cfg); } static inline void send_IPI_allbutself(int vector) @@ -252,19 +167,16 @@ static inline void send_IPI_mask(int mask, int vector) { unsigned long cfg; -#if FORCE_READ_AROUND_WRITE unsigned long flags; __save_flags(flags); __cli(); -#endif /* * prepare target chip field */ - cfg = __prepare_ICR2(mask); - apic_write(APIC_ICR2, cfg); + apic_write_around(APIC_ICR2, cfg); /* * program the ICR @@ -274,10 +186,8 @@ /* * Send the IPI. The write to APIC_ICR fires this off. */ - apic_write(APIC_ICR, cfg); -#if FORCE_READ_AROUND_WRITE + apic_write_around(APIC_ICR, cfg); __restore_flags(flags); -#endif } /* diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c --- v2.3.99-pre5/linux/arch/i386/kernel/smpboot.c Tue Feb 1 01:35:43 2000 +++ linux/arch/i386/kernel/smpboot.c Wed Apr 12 09:33:20 2000 @@ -28,6 +28,7 @@ * from Jose Renau * Ingo Molnar : various cleanups and rewrites * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. + * Maciej W. Rozycki : Bits for genuine 82489DX APICs */ #include @@ -489,11 +490,43 @@ return do_fork(CLONE_VM|CLONE_PID, 0, ®s); } +#if APIC_DEBUG +static inline void inquire_remote_apic(int apicid) +{ + int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; + char *names[] = { "ID", "VERSION", "SPIV" }; + int timeout, status; + + printk("Inquiring remote APIC #%d...\n", apicid); + + for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) { + printk("... APIC #%d %s: ", apicid, names[i]); + + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); + apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]); + + timeout = 0; + do { + udelay(100); + status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK; + } while (status == APIC_ICR_RR_INPROG && timeout++ < 1000); + + switch (status) { + case APIC_ICR_RR_VALID: + status = apic_read(APIC_RRR); + printk("%08x\n", status); + break; + default: + printk("failed\n"); + } + } +} +#endif + static void __init do_boot_cpu (int apicid) { - unsigned long cfg; struct task_struct *idle; - unsigned long send_status, accept_status; + unsigned long send_status, accept_status, boot_status, maxlvt; int timeout, num_starts, j, cpu; unsigned long start_eip; @@ -527,7 +560,7 @@ start_eip = setup_trampoline(); /* So we see what's up */ - printk("Booting processor %d eip %lx\n", cpu, start_eip); + printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); /* @@ -549,16 +582,17 @@ * Be paranoid about clearing APIC errors. */ if (APIC_INTEGRATED(apic_version[apicid])) { - apic_readaround(APIC_SPIV); + apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); - accept_status = (apic_read(APIC_ESR) & 0xEF); + apic_read(APIC_ESR); } /* * Status is now clean */ - send_status = 0; + send_status = 0; accept_status = 0; + boot_status = 0; /* * Starting actual IPI sequence... @@ -567,37 +601,41 @@ Dprintk("Asserting INIT.\n"); /* - * Turn INIT on - */ - cfg = apic_read(APIC_ICR2); - cfg &= 0x00FFFFFF; - - /* - * Target chip + * Turn INIT on target chip */ - apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid)); + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); /* * Send IPI */ - cfg = apic_read(APIC_ICR); - cfg &= ~0xCDFFF; - cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_ASSERT | APIC_DEST_DM_INIT); - apic_write(APIC_ICR, cfg); + apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT + | APIC_DM_INIT); + + Dprintk("Waiting for send to finish...\n"); + timeout = 0; + do { + Dprintk("+"); + udelay(100); + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); + + mdelay(10); - udelay(200); Dprintk("Deasserting INIT.\n"); /* Target chip */ - cfg = apic_read(APIC_ICR2); - cfg &= 0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(apicid)); + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); /* Send IPI */ - cfg = apic_read(APIC_ICR); - cfg &= ~0xCDFFF; - cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_DM_INIT); - apic_write(APIC_ICR, cfg); + apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); + + Dprintk("Waiting for send to finish...\n"); + timeout = 0; + do { + Dprintk("+"); + udelay(100); + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); /* * Should we send STARTUP IPIs ? @@ -616,9 +654,11 @@ */ Dprintk("#startup loops: %d.\n", num_starts); + maxlvt = get_maxlvt(); + for (j = 1; j <= num_starts; j++) { Dprintk("Sending STARTUP #%d.\n",j); - apic_readaround(APIC_SPIV); + apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); Dprintk("After apic_write.\n"); @@ -628,17 +668,12 @@ */ /* Target chip */ - cfg = apic_read(APIC_ICR2); - cfg &= 0x00FFFFFF; - apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid)); + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); /* Boot on the stack */ - cfg = apic_read(APIC_ICR); - cfg &= ~0xCDFFF; - cfg |= (APIC_DEST_DM_STARTUP | (start_eip >> 12)); - /* Kick the second */ - apic_write(APIC_ICR, cfg); + apic_write_around(APIC_ICR, APIC_DM_STARTUP + | (start_eip >> 12)); Dprintk("Startup point 1.\n"); @@ -647,13 +682,20 @@ do { Dprintk("+"); udelay(100); - send_status = apic_read(APIC_ICR) & 0x1000; + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; } while (send_status && (timeout++ < 1000)); /* * Give the other CPU some time to accept the IPI. */ udelay(200); + /* + * Due to the Pentium erratum 3AP. + */ + if (maxlvt > 3) { + apic_read_around(APIC_SPIV); + apic_write(APIC_ESR, 0); + } accept_status = (apic_read(APIC_ESR) & 0xEF); if (send_status || accept_status) break; @@ -676,7 +718,7 @@ /* * Wait 5s total for a response */ - for (timeout = 0; timeout < 1000000000; timeout++) { + for (timeout = 0; timeout < 50000; timeout++) { if (test_bit(cpu, &cpu_callin_map)) break; /* It has booted */ udelay(100); @@ -687,15 +729,22 @@ Dprintk("OK.\n"); printk("CPU%d: ", cpu); print_cpu_info(&cpu_data[cpu]); + Dprintk("CPU has booted.\n"); } else { + boot_status = 1; if (*((volatile unsigned char *)phys_to_virt(8192)) - == 0xA5) /* trampoline code not run */ + == 0xA5) + /* trampoline started but...? */ printk("Stuck ??\n"); else - printk("CPU booted but not responding.\n"); + /* trampoline code not run */ + printk("Not responding.\n"); +#if APIC_DEBUG + inquire_remote_apic(apicid); +#endif } - Dprintk("CPU has booted.\n"); - } else { + } + if (send_status || accept_status || boot_status) { x86_cpu_to_apicid[cpu] = -1; x86_apicid_to_cpu[apicid] = -1; cpucount--; @@ -858,6 +907,7 @@ Dprintk("Getting LVT1: %x\n", reg); } + connect_bsp_APIC(); setup_local_APIC(); if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id) @@ -877,7 +927,7 @@ if (!(phys_cpu_present_map & (1 << apicid))) continue; - if ((max_cpus >= 0) && (max_cpus < cpucount+1)) + if ((max_cpus >= 0) && (max_cpus <= cpucount+1)) continue; do_boot_cpu(apicid); @@ -934,7 +984,6 @@ printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n"); Dprintk("Boot done.\n"); - cache_APIC_registers(); #ifndef CONFIG_VISWS /* * Here we can be sure that there is an IO-APIC in the system. Let's diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.3.99-pre5/linux/arch/i386/kernel/traps.c Thu Mar 2 14:36:22 2000 +++ linux/arch/i386/kernel/traps.c Tue Apr 25 17:52:01 2000 @@ -696,7 +696,7 @@ ((limit) & 0x0ffff); } #define _set_tssldt_desc(n,addr,limit,type) \ -__asm__ __volatile__ ("movw %3,0(%2)\n\t" \ +__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ "movw %%ax,2(%2)\n\t" \ "rorl $16,%%eax\n\t" \ "movb %%al,4(%2)\n\t" \ diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/kernel/visws_apic.c linux/arch/i386/kernel/visws_apic.c --- v2.3.99-pre5/linux/arch/i386/kernel/visws_apic.c Tue Dec 7 09:32:41 1999 +++ linux/arch/i386/kernel/visws_apic.c Wed Apr 12 09:33:20 2000 @@ -376,7 +376,7 @@ for (i = 0; i < 16; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = 0; - irq_desc[i].depth = 0; + irq_desc[i].depth = 1; /* * Cobalt IRQs are mapped to standard ISA diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/lib/delay.c linux/arch/i386/lib/delay.c --- v2.3.99-pre5/linux/arch/i386/lib/delay.c Tue Mar 14 19:10:39 2000 +++ linux/arch/i386/lib/delay.c Mon Apr 24 13:39:34 2000 @@ -10,11 +10,12 @@ * we have to worry about. */ +#include #include #include #include -#ifdef __SMP__ +#ifdef CONFIG_SMP #include #endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.3.99-pre5/linux/arch/i386/mm/fault.c Fri Jan 21 18:19:16 2000 +++ linux/arch/i386/mm/fault.c Mon Apr 24 15:48:55 2000 @@ -51,7 +51,7 @@ start &= PAGE_MASK; for (;;) { - if (handle_mm_fault(current, vma, start, 1) <= 0) + if (handle_mm_fault(current->mm, vma, start, 1) <= 0) goto bad_area; if (!size) break; @@ -193,7 +193,7 @@ * the fault. */ { - int fault = handle_mm_fault(tsk, vma, address, write); + int fault = handle_mm_fault(mm, vma, address, write); if (fault < 0) goto out_of_memory; if (!fault) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/Makefile linux/arch/ia64/Makefile --- v2.3.99-pre5/linux/arch/ia64/Makefile Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/Makefile Fri Apr 21 15:21:23 2000 @@ -9,6 +9,7 @@ # NM := $(CROSS_COMPILE)nm -B +AWK := awk LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds # next line is for HP compiler backend: @@ -16,10 +17,10 @@ # The next line is needed when compiling with the July snapshot of the Cygnus compiler: #EXTRA = -D__GCC_DOESNT_KNOW_IN_REGS__ # next two lines are for the September snapshot of the Cygnus compiler: -AFLAGS += -D__GCC_MULTIREG_RETVALS__ +AFLAGS += -D__GCC_MULTIREG_RETVALS__ -Wa,-x EXTRA = -D__GCC_MULTIREG_RETVALS__ -CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127 +CFLAGS := $(CFLAGS) -pipe $(EXTRA) -Wa,-x -ffixed-r13 -mfixed-range=f10-f15,f32-f127 ifdef CONFIG_IA64_GENERIC CORE_FILES := arch/$(ARCH)/hp/hp.a \ @@ -34,14 +35,14 @@ else # !GENERIC -ifeq ($(CONFIG_IA64_HP_SIM),y) +ifdef CONFIG_IA64_HP_SIM SUBDIRS := arch/$(ARCH)/hp \ $(SUBDIRS) CORE_FILES := arch/$(ARCH)/hp/hp.a \ $(CORE_FILES) endif -ifeq ($(CONFIG_IA64_SGI_SN1_SIM),y) +ifdef CONFIG_IA64_SGI_SN1_SIM SUBDIRS := arch/$(ARCH)/sn/sn1 \ arch/$(ARCH)/sn \ $(SUBDIRS) @@ -49,14 +50,14 @@ $(CORE_FILES) endif -ifeq ($(CONFIG_IA64_SOFTSDV),y) +ifdef CONFIG_IA64_SOFTSDV SUBDIRS := arch/$(ARCH)/dig \ $(SUBDIRS) CORE_FILES := arch/$(ARCH)/dig/dig.a \ $(CORE_FILES) endif -ifeq ($(CONFIG_IA64_DIG),y) +ifdef CONFIG_IA64_DIG SUBDIRS := arch/$(ARCH)/dig \ $(SUBDIRS) CORE_FILES := arch/$(ARCH)/dig/dig.a \ @@ -65,14 +66,9 @@ endif # !GENERIC -ifeq ($(CONFIG_IA32_SUPPORT),y) +ifdef CONFIG_IA32_SUPPORT SUBDIRS := arch/$(ARCH)/ia32 $(SUBDIRS) CORE_FILES := arch/$(ARCH)/ia32/ia32.o $(CORE_FILES) -endif - -ifdef CONFIG_KDB - LIBS := $(LIBS) $(TOPDIR)/arch/$(ARCH)/kdb/kdb.a - SUBDIRS := $(SUBDIRS) arch/$(ARCH)/kdb endif HEAD := arch/$(ARCH)/kernel/head.o arch/ia64/kernel/init_task.o diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.3.99-pre5/linux/arch/ia64/config.in Tue Apr 11 15:09:12 2000 +++ linux/arch/ia64/config.in Fri Apr 21 15:21:23 2000 @@ -4,6 +4,8 @@ comment 'General setup' define_bool CONFIG_IA64 y +define_bool CONFIG_ITANIUM y # easy choice for now... ;-) + define_bool CONFIG_ISA n define_bool CONFIG_SBUS n @@ -25,7 +27,7 @@ bool ' Enable BigSur hacks' CONFIG_IA64_BIGSUR_HACKS bool ' Enable Lion hacks' CONFIG_IA64_LION_HACKS bool ' Emulate PAL/SAL/EFI firmware' CONFIG_IA64_FW_EMU - bool ' Get PCI IRQ routing from firmware/ACPI' CONFIG_IA64_IRQ_ACPI + bool ' Enable IA64 Machine Check Abort' CONFIG_IA64_MCA fi if [ "$CONFIG_IA64_GENERIC" = "y" ]; then @@ -185,10 +187,5 @@ bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS -bool 'Built-in Kernel Debugger support' CONFIG_KDB -if [ "$CONFIG_KDB" = "y" ]; then - bool 'Compile the kernel with frame pointers' CONFIG_KDB_FRAMEPTR - int 'KDB Kernel Symbol Table size?' CONFIG_KDB_STBSIZE 10000 -fi endmenu diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/defconfig linux/arch/ia64/defconfig --- v2.3.99-pre5/linux/arch/ia64/defconfig Tue Apr 11 15:09:12 2000 +++ linux/arch/ia64/defconfig Thu Apr 13 22:54:26 2000 @@ -115,8 +115,8 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC6210 is not set -# CONFIG_AEC6210_TUNING 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_AMD7409 is not set diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/dig/Makefile linux/arch/ia64/dig/Makefile --- v2.3.99-pre5/linux/arch/ia64/dig/Makefile Tue Apr 11 15:09:12 2000 +++ linux/arch/ia64/dig/Makefile Fri Apr 21 15:21:23 2000 @@ -15,7 +15,7 @@ O_TARGET = dig.a O_OBJS = iosapic.o setup.o -ifeq ($(CONFIG_IA64_GENERIC),y) +ifdef CONFIG_IA64_GENERIC O_OBJS += machvec.o endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/dig/iosapic.c linux/arch/ia64/dig/iosapic.c --- v2.3.99-pre5/linux/arch/ia64/dig/iosapic.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/dig/iosapic.c Fri Apr 21 15:21:23 2000 @@ -7,16 +7,20 @@ * Copyright (C) 1999-2000 David Mosberger-Tang * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999,2000 Walt Drummond + * + * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O APIC code. + * In particular, we now have separate handlers for edge + * and level triggered interrupts. */ #include #include #include -#include #include #include #include #include +#include #include #include @@ -27,172 +31,19 @@ #undef DEBUG_IRQ_ROUTING -/* - * IRQ vectors 0..15 are treated as the legacy interrupts of the PC-AT - * platform. No new drivers should ever ask for specific irqs, but we - * provide compatibility here in case there is an old driver that does - * ask for specific irqs (serial, keyboard, stuff like that). Since - * IA-64 doesn't allow irq 0..15 to be used for external interrupts - * anyhow, this in no way prevents us from doing the Right Thing - * with new drivers. - */ +static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; + struct iosapic_vector iosapic_vector[NR_IRQS] = { [0 ... NR_IRQS-1] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }; -#ifndef CONFIG_IA64_IRQ_ACPI -/* - * Defines the default interrupt routing information for the LION platform - * XXX - this information should be obtained from the ACPI and hardcoded since - * we do not have ACPI AML support. - */ - -struct intr_routing_entry intr_routing[] = { - {0,0,0,2,0,0,0,0}, - {0,0,1,1,0,0,0,0}, - {0,0,2,0xff,0,0,0,0}, - {0,0,3,3,0,0,0,0}, - {0,0,4,4,0,0,0,0}, - {0,0,5,5,0,0,0,0}, - {0,0,6,6,0,0,0,0}, - {0,0,7,7,0,0,0,0}, - {0,0,8,8,0,0,0,0}, - {0,0,9,9,0,0,0,0}, - {0,0,10,10,0,0,0,0}, - {0,0,11,11,0,0,0,0}, - {0,0,12,12,0,0,0,0}, - {0,0,13,13,0,0,0,0}, - {0,0,14,14,0,0,0,0}, - {0,0,15,15,0,0,0,0}, -#ifdef CONFIG_IA64_LION_HACKS - {1, 0, 0x04, 16, 0, 0, 1, 1}, /* bus 0, device id 1, INTA */ - {1, 0, 0x05, 26, 0, 0, 1, 1}, /* bus 0, device id 1, INTB */ - {1, 0, 0x06, 36, 0, 0, 1, 1}, /* bus 0, device id 1, INTC */ - {1, 0, 0x07, 42, 0, 0, 1, 1}, /* bus 0, device id 1, INTD */ - - {1, 0, 0x08, 17, 0, 0, 1, 1}, /* bus 0, device id 2, INTA */ - {1, 0, 0x09, 27, 0, 0, 1, 1}, /* bus 0, device id 2, INTB */ - {1, 0, 0x0a, 37, 0, 0, 1, 1}, /* bus 0, device id 2, INTC */ - {1, 0, 0x0b, 42, 0, 0, 1, 1}, /* bus 0, device id 2, INTD */ - - {1, 0, 0x0f, 50, 0, 0, 1, 1}, /* bus 0, device id 3, INTD */ - - {1, 0, 0x14, 51, 0, 0, 1, 1}, /* bus 0, device id 5, INTA */ - - {1, 0, 0x18, 49, 0, 0, 1, 1}, /* bus 0, device id 6, INTA */ - - {1, 1, 0x04, 18, 0, 0, 1, 1}, /* bus 1, device id 1, INTA */ - {1, 1, 0x05, 28, 0, 0, 1, 1}, /* bus 1, device id 1, INTB */ - {1, 1, 0x06, 38, 0, 0, 1, 1}, /* bus 1, device id 1, INTC */ - {1, 1, 0x07, 43, 0, 0, 1, 1}, /* bus 1, device id 1, INTD */ - - {1, 1, 0x08, 48, 0, 0, 1, 1}, /* bus 1, device id 2, INTA */ - - {1, 1, 0x0c, 19, 0, 0, 1, 1}, /* bus 1, device id 3, INTA */ - {1, 1, 0x0d, 29, 0, 0, 1, 1}, /* bus 1, device id 3, INTB */ - {1, 1, 0x0e, 38, 0, 0, 1, 1}, /* bus 1, device id 3, INTC */ - {1, 1, 0x0f, 44, 0, 0, 1, 1}, /* bus 1, device id 3, INTD */ - - {1, 1, 0x10, 20, 0, 0, 1, 1}, /* bus 1, device id 4, INTA */ - {1, 1, 0x11, 30, 0, 0, 1, 1}, /* bus 1, device id 4, INTB */ - {1, 1, 0x12, 39, 0, 0, 1, 1}, /* bus 1, device id 4, INTC */ - {1, 1, 0x13, 45, 0, 0, 1, 1}, /* bus 1, device id 4, INTD */ - - {1, 2, 0x04, 21, 0, 0, 1, 1}, /* bus 2, device id 1, INTA */ - {1, 2, 0x05, 31, 0, 0, 1, 1}, /* bus 2, device id 1, INTB */ - {1, 2, 0x06, 39, 0, 0, 1, 1}, /* bus 2, device id 1, INTC */ - {1, 2, 0x07, 45, 0, 0, 1, 1}, /* bus 2, device id 1, INTD */ - - {1, 2, 0x08, 22, 0, 0, 1, 1}, /* bus 2, device id 2, INTA */ - {1, 2, 0x09, 32, 0, 0, 1, 1}, /* bus 2, device id 2, INTB */ - {1, 2, 0x0a, 40, 0, 0, 1, 1}, /* bus 2, device id 2, INTC */ - {1, 2, 0x0b, 46, 0, 0, 1, 1}, /* bus 2, device id 2, INTD */ - - {1, 2, 0x0c, 23, 0, 0, 1, 1}, /* bus 2, device id 3, INTA */ - {1, 2, 0x0d, 33, 0, 0, 1, 1}, /* bus 2, device id 3, INTB */ - {1, 2, 0x0e, 40, 0, 0, 1, 1}, /* bus 2, device id 3, INTC */ - {1, 2, 0x0f, 46, 0, 0, 1, 1}, /* bus 2, device id 3, INTD */ - - {1, 3, 0x04, 24, 0, 0, 1, 1}, /* bus 3, device id 1, INTA */ - {1, 3, 0x05, 34, 0, 0, 1, 1}, /* bus 3, device id 1, INTB */ - {1, 3, 0x06, 41, 0, 0, 1, 1}, /* bus 3, device id 1, INTC */ - {1, 3, 0x07, 47, 0, 0, 1, 1}, /* bus 3, device id 1, INTD */ - - {1, 3, 0x08, 25, 0, 0, 1, 1}, /* bus 3, device id 2, INTA */ - {1, 3, 0x09, 35, 0, 0, 1, 1}, /* bus 3, device id 2, INTB */ - {1, 3, 0x0a, 41, 0, 0, 1, 1}, /* bus 3, device id 2, INTC */ - {1, 3, 0x0b, 47, 0, 0, 1, 1}, /* bus 3, device id 2, INTD */ -#else - /* - * BigSur platform, bus 0, device 1,2,4 and bus 1 device 0-3 - */ - {1,1,0x0,19,0,0,1,1}, /* bus 1, device id 0, INTA */ - {1,1,0x1,18,0,0,1,1}, /* bus 1, device id 0, INTB */ - {1,1,0x2,17,0,0,1,1}, /* bus 1, device id 0, INTC */ - {1,1,0x3,16,0,0,1,1}, /* bus 1, device id 0, INTD */ - - {1,1,0x4,23,0,0,1,1}, /* bus 1, device id 1, INTA */ - {1,1,0x5,22,0,0,1,1}, /* bus 1, device id 1, INTB */ - {1,1,0x6,21,0,0,1,1}, /* bus 1, device id 1, INTC */ - {1,1,0x7,20,0,0,1,1}, /* bus 1, device id 1, INTD */ - - {1,1,0x8,27,0,0,1,1}, /* bus 1, device id 2, INTA */ - {1,1,0x9,26,0,0,1,1}, /* bus 1, device id 2, INTB */ - {1,1,0xa,25,0,0,1,1}, /* bus 1, device id 2, INTC */ - {1,1,0xb,24,0,0,1,1}, /* bus 1, device id 2, INTD */ - - {1,1,0xc,31,0,0,1,1}, /* bus 1, device id 3, INTA */ - {1,1,0xd,30,0,0,1,1}, /* bus 1, device id 3, INTB */ - {1,1,0xe,29,0,0,1,1}, /* bus 1, device id 3, INTC */ - {1,1,0xf,28,0,0,1,1}, /* bus 1, device id 3, INTD */ - - {1,0,0x4,35,0,0,1,1}, /* bus 0, device id 1, INTA */ - {1,0,0x5,34,0,0,1,1}, /* bus 0, device id 1, INTB */ - {1,0,0x6,33,0,0,1,1}, /* bus 0, device id 1, INTC */ - {1,0,0x7,32,0,0,1,1}, /* bus 0, device id 1, INTD */ - - {1,0,0x8,39,0,0,1,1}, /* bus 0, device id 2, INTA */ - {1,0,0x9,38,0,0,1,1}, /* bus 0, device id 2, INTB */ - {1,0,0xa,37,0,0,1,1}, /* bus 0, device id 2, INTC */ - {1,0,0xb,36,0,0,1,1}, /* bus 0, device id 2, INTD */ - - {1,0,0x10,43,0,0,1,1}, /* bus 0, device id 4, INTA */ - {1,0,0x11,42,0,0,1,1}, /* bus 0, device id 4, INTB */ - {1,0,0x12,41,0,0,1,1}, /* bus 0, device id 4, INTC */ - {1,0,0x13,40,0,0,1,1}, /* bus 0, device id 4, INTD */ - - {1,0,0x14,17,0,0,1,1}, /* bus 0, device id 5, INTA */ - {1,0,0x18,18,0,0,1,1}, /* bus 0, device id 6, INTA */ - {1,0,0x1c,19,0,0,1,1}, /* bus 0, device id 7, INTA */ -#endif - {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, -}; - -int -iosapic_get_PCI_irq_vector(int bus, int slot, int pci_pin) -{ - int i = -1; - - while (intr_routing[++i].srcbus != 0xff) { - if (intr_routing[i].srcbus == BUS_PCI) { - if ((intr_routing[i].srcbusirq == ((slot << 2) | pci_pin)) - && (intr_routing[i].srcbusno == bus)) { - return(intr_routing[i].iosapic_pin); - } - } - } - return -1; -} - -#else /* CONFIG_IA64_IRQ_ACPI */ - /* * find the IRQ in the IOSAPIC map for the PCI device on bus/slot/pin */ int -iosapic_get_PCI_irq_vector(int bus, int slot, int pci_pin) +iosapic_get_PCI_irq_vector (int bus, int slot, int pci_pin) { - int i; + int i; for (i = 0; i < NR_IRQS; i++) { if ((iosapic_bustype(i) == BUS_PCI) && @@ -201,17 +52,15 @@ return i; } } - return -1; } -#endif /* !CONFIG_IA64_IRQ_ACPI */ static void set_rte (unsigned long iosapic_addr, int entry, int pol, int trigger, int delivery, long dest, int vector) { - int low32; - int high32; + u32 low32; + u32 high32; low32 = ((pol << IO_SAPIC_POLARITY_SHIFT) | (trigger << IO_SAPIC_TRIGGER_SHIFT) | @@ -221,81 +70,137 @@ /* dest contains both id and eid */ high32 = (dest << IO_SAPIC_DEST_SHIFT); - /* - * program the rte - */ writel(IO_SAPIC_RTE_HIGH(entry), iosapic_addr + IO_SAPIC_REG_SELECT); writel(high32, iosapic_addr + IO_SAPIC_WINDOW); writel(IO_SAPIC_RTE_LOW(entry), iosapic_addr + IO_SAPIC_REG_SELECT); writel(low32, iosapic_addr + IO_SAPIC_WINDOW); } +static void +nop (unsigned int irq) +{ + /* do nothing... */ +} static void -enable_pin (unsigned int pin, unsigned long iosapic_addr) +mask_irq (unsigned int irq) { - int low32; + unsigned long flags, iosapic_addr = iosapic_addr(irq); + u32 low32; - writel(IO_SAPIC_RTE_LOW(pin), iosapic_addr + IO_SAPIC_REG_SELECT); - low32 = readl(iosapic_addr + IO_SAPIC_WINDOW); + spin_lock_irqsave(&iosapic_lock, flags); + { + writel(IO_SAPIC_RTE_LOW(iosapic_pin(irq)), iosapic_addr + IO_SAPIC_REG_SELECT); + low32 = readl(iosapic_addr + IO_SAPIC_WINDOW); - low32 &= ~(1 << IO_SAPIC_MASK_SHIFT); /* Zero only the mask bit */ - writel(low32, iosapic_addr + IO_SAPIC_WINDOW); + low32 |= (1 << IO_SAPIC_MASK_SHIFT); /* Zero only the mask bit */ + writel(low32, iosapic_addr + IO_SAPIC_WINDOW); + } + spin_unlock_irqrestore(&iosapic_lock, flags); } - static void -disable_pin (unsigned int pin, unsigned long iosapic_addr) +unmask_irq (unsigned int irq) { - int low32; + unsigned long flags, iosapic_addr = iosapic_addr(irq); + u32 low32; - writel(IO_SAPIC_RTE_LOW(pin), iosapic_addr + IO_SAPIC_REG_SELECT); - low32 = readl(iosapic_addr + IO_SAPIC_WINDOW); + spin_lock_irqsave(&iosapic_lock, flags); + { + writel(IO_SAPIC_RTE_LOW(iosapic_pin(irq)), iosapic_addr + IO_SAPIC_REG_SELECT); + low32 = readl(iosapic_addr + IO_SAPIC_WINDOW); - low32 |= (1 << IO_SAPIC_MASK_SHIFT); /* Set only the mask bit */ - writel(low32, iosapic_addr + IO_SAPIC_WINDOW); + low32 &= ~(1 << IO_SAPIC_MASK_SHIFT); /* Zero only the mask bit */ + writel(low32, iosapic_addr + IO_SAPIC_WINDOW); + } + spin_unlock_irqrestore(&iosapic_lock, flags); } -#define iosapic_shutdown_irq iosapic_disable_irq -static unsigned int -iosapic_startup_irq (unsigned int irq) +static void +iosapic_set_affinity (unsigned int irq, unsigned long mask) { - int pin; + printk("iosapic_set_affinity: not implemented yet\n"); +} + +/* + * Handlers for level-triggered interrupts. + */ - pin = iosapic_pin(irq); - if (pin < 0) - /* happens during irq auto probing... */ - return 0; - set_rte(iosapic_addr(irq), pin, iosapic_polarity(irq), iosapic_trigger(irq), - iosapic_dmode(irq), (ia64_get_lid() >> 16) & 0xffff, irq); - enable_pin(pin, iosapic_addr(irq)); +static unsigned int +iosapic_startup_level_irq (unsigned int irq) +{ + unmask_irq(irq); return 0; } static void -iosapic_enable_irq (unsigned int irq) +iosapic_end_level_irq (unsigned int irq) { - int pin = iosapic_pin(irq); + writel(irq, iosapic_addr(irq) + IO_SAPIC_EOI); +} + +#define iosapic_shutdown_level_irq mask_irq +#define iosapic_enable_level_irq unmask_irq +#define iosapic_disable_level_irq mask_irq +#define iosapic_ack_level_irq nop + +struct hw_interrupt_type irq_type_iosapic_level = { + typename: "IO-SAPIC-level", + startup: iosapic_startup_level_irq, + shutdown: iosapic_shutdown_level_irq, + enable: iosapic_enable_level_irq, + disable: iosapic_disable_level_irq, + ack: iosapic_ack_level_irq, + end: iosapic_end_level_irq, + set_affinity: iosapic_set_affinity +}; + +/* + * Handlers for edge-triggered interrupts. + */ - if (pin < 0) - /* happens during irq auto probing... */ - return; - enable_pin(pin, iosapic_addr(irq)); +static unsigned int +iosapic_startup_edge_irq (unsigned int irq) +{ + unmask_irq(irq); + /* + * IOSAPIC simply drops interrupts pended while the + * corresponding pin was masked, so we can't know if an + * interrupt is pending already. Let's hope not... + */ + return 0; } static void -iosapic_disable_irq (unsigned int irq) +iosapic_ack_edge_irq (unsigned int irq) { - int pin = iosapic_pin(irq); - - if (pin < 0) - return; - disable_pin(pin, iosapic_addr(irq)); + /* + * Once we have recorded IRQ_PENDING already, we can mask the + * interrupt for real. This prevents IRQ storms from unhandled + * devices. + */ + if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED)) + mask_irq(irq); } +#define iosapic_enable_edge_irq unmask_irq +#define iosapic_disable_edge_irq nop +#define iosapic_end_edge_irq nop + +struct hw_interrupt_type irq_type_iosapic_edge = { + typename: "IO-SAPIC-edge", + startup: iosapic_startup_edge_irq, + shutdown: iosapic_disable_edge_irq, + enable: iosapic_enable_edge_irq, + disable: iosapic_disable_edge_irq, + ack: iosapic_ack_edge_irq, + end: iosapic_end_edge_irq, + set_affinity: iosapic_set_affinity +}; + unsigned int -iosapic_version(unsigned long base_addr) +iosapic_version (unsigned long base_addr) { /* * IOSAPIC Version Register return 32 bit structure like: @@ -310,99 +215,19 @@ return readl(IO_SAPIC_WINDOW + base_addr); } -static void -iosapic_ack_irq (unsigned int irq) -{ -} - -static void -iosapic_end_irq (unsigned int irq) -{ - if (iosapic_trigger(irq) == IO_SAPIC_LEVEL) /* ACK Level trigger interrupts */ - writel(irq, iosapic_addr(irq) + IO_SAPIC_EOI); -} - -static void -iosapic_set_affinity (unsigned int irq, unsigned long mask) -{ - printk("iosapic_set_affinity: not implemented yet\n"); -} - void iosapic_init (unsigned long address) { - int i; -#ifdef CONFIG_IA64_IRQ_ACPI + struct hw_interrupt_type *irq_type; struct pci_vector_struct *vectors; - int irq; -#else - int vector; -#endif + int i, irq; - /* - * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support - * enabled. - */ - outb(0xff, 0xA1); - outb(0xff, 0x21); - -#if defined(CONFIG_IA64_SOFTSDV_HACKS) - memset(iosapic_vector, 0x0, sizeof(iosapic_vector)); - for (i = 0; i < NR_IRQS; i++) { - iosapic_pin(i) = 0xff; - iosapic_addr(i) = (unsigned long) ioremap(address, 0); - } - /* XXX this should come from systab or some such: */ -# if 0 - /* this doesn't look right --davidm 00/03/07 */ - iosapic_pin(TIMER_IRQ) = 5; /* System Clock Interrupt */ -# endif - iosapic_pin(0x40) = 3; /* Keyboard */ - iosapic_pin(0x92) = 9; /* COM1 Serial Port */ - iosapic_pin(0x80) = 4; /* Periodic Interrupt */ - iosapic_pin(0xc0) = 2; /* Mouse */ - iosapic_pin(0xe0) = 1; /* IDE Disk */ - iosapic_pin(0xf0) = 6; /* E-IDE CDROM */ - iosapic_pin(0xa0) = 10; /* Real PCI Interrupt */ -#elif !defined(CONFIG_IA64_IRQ_ACPI) - /* - * For systems where the routing info in ACPI is - * unavailable/wrong, use the intr_routing information to - * initialize the iosapic array - */ - i = -1; - while (intr_routing[++i].srcbus != 0xff) { - if (intr_routing[i].srcbus == BUS_ISA) { - vector = isa_irq_to_vector(intr_routing[i].srcbusirq); - } else if (intr_routing[i].srcbus == BUS_PCI) { - vector = intr_routing[i].iosapic_pin; - } else { - printk("unknown bus type %d for intr_routing[%d]\n", - intr_routing[i].srcbus, i); - continue; - } - iosapic_pin(vector) = intr_routing[i].iosapic_pin; - iosapic_dmode(vector) = intr_routing[i].mode; - iosapic_polarity(vector) = intr_routing[i].polarity; - iosapic_trigger(vector) = intr_routing[i].trigger; -# ifdef DEBUG_IRQ_ROUTING - printk("irq[0x%x(0x%x)]:0x%x, %d, %d, %d\n", vector, intr_routing[i].srcbusirq, - iosapic_pin(vector), iosapic_dmode(vector), iosapic_polarity(vector), - iosapic_trigger(vector)); -# endif - } -#else /* !defined(CONFIG_IA64_SOFTSDV_HACKS) && defined(CONFIG_IA64_IRQ_ACPI) */ /* - * Map the legacy ISA devices into the IOAPIC data; We'll override these - * later with data from the ACPI Interrupt Source Override table. - * - * Huh, the Lion w/ FPSWA firmware has entries for _all_ of the legacy IRQs, - * including those that are not different from PC/AT standard. I don't know - * if this is a bug in the other firmware or not. I'm going to leave this code - * here, so that this works on BigSur but will go ask Intel. --wfd 2000-Jan-19 - * + * Map the legacy ISA devices into the IOSAPIC data. Some of + * these may get reprogrammed later on with data from the ACPI + * Interrupt Source Override table. */ - for (i =0 ; i < 16; i++) { + for (i = 0; i < 16; i++) { irq = isa_irq_to_vector(i); iosapic_pin(irq) = i; iosapic_bus(irq) = BUS_ISA; @@ -445,41 +270,37 @@ irq, iosapic_pin(irq)); #endif } -#endif /* !CONFIG_IA64_IRQ_ACPI */ -} -struct hw_interrupt_type irq_type_iosapic = { - typename: "IOSAPIC", - startup: iosapic_startup_irq, - shutdown: iosapic_shutdown_irq, - enable: iosapic_enable_irq, - disable: iosapic_disable_irq, - ack: iosapic_ack_irq, - end: iosapic_end_irq, - set_affinity: iosapic_set_affinity -}; + for (i = 0; i < NR_IRQS; ++i) { + if (iosapic_pin(i) != -1) { + if (iosapic_trigger(i) == IO_SAPIC_LEVEL) + irq_type = &irq_type_iosapic_level; + else + irq_type = &irq_type_iosapic_edge; + if (irq_desc[i].handler != &no_irq_type) + printk("dig_irq_init: warning: changing vector %d from %s to %s\n", + i, irq_desc[i].handler->typename, + irq_type->typename); + irq_desc[i].handler = irq_type; + + /* program the IOSAPIC routing table: */ + set_rte(iosapic_addr(i), iosapic_pin(i), iosapic_polarity(i), + iosapic_trigger(i), iosapic_dmode(i), + (ia64_get_lid() >> 16) & 0xffff, i); + } + } +} void dig_irq_init (void) { - int i; - /* - * Claim all non-legacy irq vectors as ours unless they're - * claimed by someone else already (e.g., timer or IPI are - * handled internally). + * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support + * enabled. */ -#if 0 - for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) { - if (irq_desc[i].handler == &no_irq_type) - irq_desc[i].handler = &irq_type_iosapic; - } -#else - for (i = 0; i <= IA64_MAX_VECTORED_IRQ; ++i) { - if (irq_desc[i].handler == &no_irq_type) - irq_desc[i].handler = &irq_type_iosapic; - } -#endif + outb(0xff, 0xA1); + outb(0xff, 0x21); + #ifndef CONFIG_IA64_DIG iosapic_init(IO_SAPIC_DEFAULT_ADDR); #endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/dig/setup.c linux/arch/ia64/dig/setup.c --- v2.3.99-pre5/linux/arch/ia64/dig/setup.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/dig/setup.c Fri Apr 21 15:21:23 2000 @@ -47,17 +47,11 @@ unsigned int orig_x, orig_y, num_cols, num_rows, font_height; /* - * This assumes that the EFI partition is physical disk 1 - * partition 1 and the Linux root disk is physical disk 1 - * partition 2. + * Default to /dev/sda2. This assumes that the EFI partition + * is physical disk 1 partition 1 and the Linux root disk is + * physical disk 1 partition 2. */ -#ifdef CONFIG_IA64_LION_HACKS - /* default to /dev/sda2 on Lion... */ ROOT_DEV = to_kdev_t(0x0802); /* default to second partition on first drive */ -#else - /* default to /dev/dha2 on BigSur... */ - ROOT_DEV = to_kdev_t(0x0302); /* default to second partition on first drive */ -#endif #ifdef CONFIG_SMP init_smp_config(); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/hp/Makefile linux/arch/ia64/hp/Makefile --- v2.3.99-pre5/linux/arch/ia64/hp/Makefile Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/hp/Makefile Fri Apr 21 15:21:23 2000 @@ -10,7 +10,7 @@ O_TARGET = hp.a O_OBJS = hpsim_console.o hpsim_irq.o hpsim_setup.o -ifeq ($(CONFIG_IA64_GENERIC),y) +ifdef CONFIG_IA64_GENERIC O_OBJS += hpsim_machvec.o endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/Makefile linux/arch/ia64/ia32/Makefile --- v2.3.99-pre5/linux/arch/ia64/ia32/Makefile Tue Apr 11 15:09:12 2000 +++ linux/arch/ia64/ia32/Makefile Fri Apr 21 15:21:23 2000 @@ -10,7 +10,7 @@ all: ia32.o O_TARGET := ia32.o -O_OBJS := ia32_entry.o ia32_signal.o sys_ia32.o ia32_support.o binfmt_elf32.o +O_OBJS := ia32_entry.o sys_ia32.o ia32_signal.o ia32_support.o ia32_traps.o binfmt_elf32.o clean:: diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c --- v2.3.99-pre5/linux/arch/ia64/ia32/binfmt_elf32.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/ia32/binfmt_elf32.c Fri Apr 21 15:21:23 2000 @@ -134,6 +134,19 @@ regs->cr_ipsr &= ~IA64_PSR_AC; regs->loadrs = 0; + /* + * According to the ABI %edx points to an `atexit' handler. + * Since we don't have one we'll set it to 0 and initialize + * all the other registers just to make things more deterministic, + * ala the i386 implementation. + */ + regs->r8 = 0; /* %eax */ + regs->r11 = 0; /* %ebx */ + regs->r9 = 0; /* %ecx */ + regs->r10 = 0; /* %edx */ + regs->r13 = 0; /* %ebp */ + regs->r14 = 0; /* %esi */ + regs->r15 = 0; /* %edi */ } #undef STACK_TOP diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S --- v2.3.99-pre5/linux/arch/ia64/ia32/ia32_entry.S Sat Feb 26 22:31:39 2000 +++ linux/arch/ia64/ia32/ia32_entry.S Fri Apr 21 15:21:23 2000 @@ -1,14 +1,55 @@ #include #include + // + // Get possibly unaligned sigmask argument into an aligned + // kernel buffer + .text + .proc ia32_rt_sigsuspend + .global ia32_rt_sigsuspend +ia32_rt_sigsuspend: + + // We'll cheat and not do an alloc here since we are ultimately + // going to do a simple branch to the IA64 sys_rt_sigsuspend. + // r32 is still the first argument which is the signal mask. + // We copy this 4-byte aligned value to an 8-byte aligned buffer + // in the task structure and then jump to the IA64 code. + + mov r8=r0 // no memory access errors yet + add r10=4,r32 + ;; +1: + ld4 r2=[r32] // get first half of sigmask + ld4 r3=[r10] // get second half of sigmask +2: + cmp.lt p6,p0=r8,r0 // check memory access + ;; +(p6) br.ret.sptk.many rp // it failed + + adds r32=IA64_TASK_THREAD_SIGMASK_OFFSET,r13 + adds r10=IA64_TASK_THREAD_SIGMASK_OFFSET+4,r13 + ;; + st4 [r32]=r2 + st4 [r10]=r3 + br.cond.sptk.many sys_rt_sigsuspend + + .section __ex_table,"a" + data4 @gprel(1b) + data4 (2b-1b)|1 + .previous + + + .endp ia32_rt_sigsuspend + .global ia32_ret_from_syscall - .proc ia64_ret_from_syscall + .proc ia32_ret_from_syscall ia32_ret_from_syscall: cmp.ge p6,p7=r8,r0 // syscall executed successfully? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 ;; st8 [r2]=r8 // store return value in slot for r8 br.cond.sptk.few ia64_leave_kernel + .endp ia32_ret_from_syscall // // Invoke a system call, but do some tracing before and after the call. @@ -35,10 +76,21 @@ .endp ia32_trace_syscall .align 16 + .global sys32_vfork + .proc sys32_vfork +sys32_vfork: + alloc r16=ar.pfs,2,2,3,0;; + mov out0=IA64_CLONE_VFORK|IA64_CLONE_VM|SIGCHLD // out0 = clone_flags + br.cond.sptk.few .fork1 // do the work + .endp sys32_vfork + + .align 16 .global sys32_fork .proc sys32_fork sys32_fork: alloc r16=ar.pfs,2,2,3,0;; + mov out0=SIGCHLD // out0 = clone_flags +.fork1: movl r28=1f mov loc1=rp br.cond.sptk.many save_switch_stack @@ -46,7 +98,6 @@ mov loc0=r16 // save ar.pfs across do_fork adds out2=IA64_SWITCH_STACK_SIZE+16,sp adds r2=IA64_SWITCH_STACK_SIZE+IA64_PT_REGS_R12_OFFSET+16,sp - mov out0=SIGCHLD // out0 = clone_flags ;; ld8 out1=[r2] // fetch usp from pt_regs.r12 br.call.sptk.few rp=do_fork @@ -88,7 +139,7 @@ data8 sys_setuid data8 sys_getuid data8 sys_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ - data8 sys_ptrace + data8 sys32_ptrace data8 sys32_alarm data8 sys_ni_syscall data8 sys_ni_syscall @@ -105,7 +156,7 @@ data8 sys_rmdir /* 40 */ data8 sys_dup data8 sys32_pipe - data8 sys_times + data8 sys32_times data8 sys_ni_syscall /* old prof syscall holder */ data8 sys_brk /* 45 */ data8 sys_setgid @@ -139,7 +190,7 @@ data8 sys_sethostname data8 sys32_setrlimit /* 75 */ data8 sys32_getrlimit - data8 sys_getrusage + data8 sys32_getrusage data8 sys32_gettimeofday data8 sys32_settimeofday data8 sys_getgroups /* 80 */ @@ -241,7 +292,7 @@ data8 sys_rt_sigpending data8 sys_rt_sigtimedwait data8 sys_rt_sigqueueinfo - data8 sys_rt_sigsuspend + data8 ia32_rt_sigsuspend data8 sys_pread /* 180 */ data8 sys_pwrite data8 sys_chown diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/ia32_signal.c linux/arch/ia64/ia32/ia32_signal.c --- v2.3.99-pre5/linux/arch/ia64/ia32/ia32_signal.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ia64/ia32/ia32_signal.c Fri Apr 21 15:21:23 2000 @@ -94,7 +94,9 @@ err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); /* non-iBCS2 extensions.. */ +#endif err |= __put_user(mask, &sc->oldmask); +#if 0 err |= __put_user(current->tss.cr2, &sc->cr2); #endif @@ -196,7 +198,7 @@ return (void *)((esp - frame_size) & -8ul); } -static void +static int setup_frame_ia32(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { @@ -247,20 +249,21 @@ regs->eflags &= ~TF_MASK; #endif -#if 1 - printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n", - current->comm, current->pid, frame, regs->cr_iip, frame->pretcode); +#if 0 + printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n", + current->comm, current->pid, sig, frame, regs->cr_iip, frame->pretcode); #endif - return; + return 1; give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); + return 0; } -static void +static int setup_rt_frame_ia32(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { @@ -316,29 +319,29 @@ regs->eflags &= ~TF_MASK; #endif -#if 1 +#if 0 printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n", current->comm, current->pid, frame, regs->cr_iip, frame->pretcode); #endif - return; + return 1; give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); + return 0; } -long +int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame_ia32(sig, ka, info, set, regs); + return(setup_rt_frame_ia32(sig, ka, info, set, regs)); else - setup_frame_ia32(sig, ka, set, regs); - + return(setup_frame_ia32(sig, ka, set, regs)); } asmlinkage int diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/ia32_traps.c linux/arch/ia64/ia32/ia32_traps.c --- v2.3.99-pre5/linux/arch/ia64/ia32/ia32_traps.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/ia32/ia32_traps.c Fri Apr 21 15:21:23 2000 @@ -0,0 +1,47 @@ +#include +#include + +#include +#include + +int +ia32_exception (struct pt_regs *regs, unsigned long isr) +{ + struct siginfo siginfo; + + switch ((isr >> 16) & 0xff) { + case 1: + case 2: + if (isr == 0) + siginfo.si_code = TRAP_TRACE; + else if (isr & 0x4) + siginfo.si_code = TRAP_BRANCH; + else + siginfo.si_code = TRAP_BRKPT; + break; + + case 3: + siginfo.si_code = TRAP_BRKPT; + break; + + case 0: /* Divide fault */ + case 4: /* Overflow */ + case 5: /* Bounds fault */ + case 6: /* Invalid Op-code */ + case 7: /* FP DNA */ + case 8: /* Double Fault */ + case 9: /* Invalid TSS */ + case 11: /* Segment not present */ + case 12: /* Stack fault */ + case 13: /* General Protection Fault */ + case 16: /* Pending FP error */ + case 17: /* Alignment check */ + case 19: /* SSE Numeric error */ + default: + return -1; + } + siginfo.si_signo = SIGTRAP; + siginfo.si_errno = 0; + send_sig_info(SIGTRAP, &siginfo, current); + return 0; +} diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.3.99-pre5/linux/arch/ia64/ia32/sys_ia32.c Tue Apr 11 15:09:12 2000 +++ linux/arch/ia64/ia32/sys_ia32.c Fri Apr 21 15:21:24 2000 @@ -58,32 +58,6 @@ #define A(__x) ((unsigned long)(__x)) #define AA(__x) ((unsigned long)(__x)) -/* - * This is trivial, and on the face of it looks like it - * could equally well be done in user mode. - * - * Not so, for quite unobvious reasons - register pressure. - * In user mode vfork() cannot have a stack frame, and if - * done by calling the "clone()" system call directly, you - * do not have enough call-clobbered registers to hold all - * the information you need. - */ -asmlinkage int sys32_vfork( -int dummy0, -int dummy1, -int dummy2, -int dummy3, -int dummy4, -int dummy5, -int dummy6, -int dummy7, -int stack) -{ - struct pt_regs *regs = (struct pt_regs *)&stack; - - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->r12, regs); -} - static int nargs(unsigned int arg, char **ap) { @@ -842,82 +816,6 @@ return sys32_select(a.n, a.inp, a.outp, a.exp, a.tvp); } -struct rusage32 { - struct timeval32 ru_utime; - struct timeval32 ru_stime; - int ru_maxrss; - int ru_ixrss; - int ru_idrss; - int ru_isrss; - int ru_minflt; - int ru_majflt; - int ru_nswap; - int ru_inblock; - int ru_oublock; - int ru_msgsnd; - int ru_msgrcv; - int ru_nsignals; - int ru_nvcsw; - int ru_nivcsw; -}; - -static int -put_rusage (struct rusage32 *ru, struct rusage *r) -{ - int err; - - err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); - err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); - err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); - err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec); - err |= __put_user (r->ru_maxrss, &ru->ru_maxrss); - err |= __put_user (r->ru_ixrss, &ru->ru_ixrss); - err |= __put_user (r->ru_idrss, &ru->ru_idrss); - err |= __put_user (r->ru_isrss, &ru->ru_isrss); - err |= __put_user (r->ru_minflt, &ru->ru_minflt); - err |= __put_user (r->ru_majflt, &ru->ru_majflt); - err |= __put_user (r->ru_nswap, &ru->ru_nswap); - err |= __put_user (r->ru_inblock, &ru->ru_inblock); - err |= __put_user (r->ru_oublock, &ru->ru_oublock); - err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd); - err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv); - err |= __put_user (r->ru_nsignals, &ru->ru_nsignals); - err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw); - err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw); - return err; -} - -extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, - int options, struct rusage * ru); - -asmlinkage int -sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, - struct rusage32 *ru) -{ - if (!ru) - return sys_wait4(pid, stat_addr, options, NULL); - else { - struct rusage r; - int ret; - unsigned int status; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); - set_fs (old_fs); - if (put_rusage (ru, &r)) return -EFAULT; - if (stat_addr && put_user (status, stat_addr)) - return -EFAULT; - return ret; - } -} - -asmlinkage int -sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options) -{ - return sys32_wait4(pid, stat_addr, options, NULL); -} - struct timespec32 { int tv_sec; int tv_nsec; @@ -1586,367 +1484,904 @@ { union semun fourth; u32 pad; - int err = -EINVAL; + int err, err2; + struct semid64_ds s; + struct semid_ds32 *usp; + mm_segment_t old_fs; if (!uptr) - goto out; + return -EINVAL; err = -EFAULT; if (get_user (pad, (u32 *)uptr)) - goto out; + return err; if(third == SETVAL) fourth.val = (int)pad; else fourth.__pad = (void *)A(pad); - if (IPCOP_MASK (third) & - (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SEM_INFO) | - IPCOP_MASK (GETVAL) | IPCOP_MASK (GETPID) | - IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) | - IPCOP_MASK (GETALL) | IPCOP_MASK (SETALL) | - IPCOP_MASK (IPC_RMID))) { + switch (third) { + + case IPC_INFO: + case IPC_RMID: + case IPC_SET: + case SEM_INFO: + case GETVAL: + case GETPID: + case GETNCNT: + case GETZCNT: + case GETALL: + case SETVAL: + case SETALL: err = sys_semctl (first, second, third, fourth); - } else { - struct semid_ds s; - struct semid_ds32 *usp = (struct semid_ds32 *)A(pad); - mm_segment_t old_fs; - int need_back_translation; - - if (third == IPC_SET) { - err = get_user (s.sem_perm.uid, &usp->sem_perm.uid); - err |= __get_user(s.sem_perm.gid, &usp->sem_perm.gid); - err |= __get_user(s.sem_perm.mode, &usp->sem_perm.mode); - if (err) - goto out; - fourth.__pad = &s; - } - need_back_translation = - (IPCOP_MASK (third) & - (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0; - if (need_back_translation) - fourth.__pad = &s; + break; + + case IPC_STAT: + case SEM_STAT: + usp = (struct semid_ds32 *)A(pad); + fourth.__pad = &s; old_fs = get_fs (); set_fs (KERNEL_DS); err = sys_semctl (first, second, third, fourth); set_fs (old_fs); - if (need_back_translation) { - int err2 = put_user(s.sem_perm.key, &usp->sem_perm.key); - err2 |= __put_user(s.sem_perm.uid, &usp->sem_perm.uid); - err2 |= __put_user(s.sem_perm.gid, &usp->sem_perm.gid); - err2 |= __put_user(s.sem_perm.cuid, - &usp->sem_perm.cuid); - err2 |= __put_user (s.sem_perm.cgid, - &usp->sem_perm.cgid); - err2 |= __put_user (s.sem_perm.mode, - &usp->sem_perm.mode); - err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq); - err2 |= __put_user (s.sem_otime, &usp->sem_otime); - err2 |= __put_user (s.sem_ctime, &usp->sem_ctime); - err2 |= __put_user (s.sem_nsems, &usp->sem_nsems); - if (err2) err = -EFAULT; - } + err2 = put_user(s.sem_perm.key, &usp->sem_perm.key); + err2 |= __put_user(s.sem_perm.uid, &usp->sem_perm.uid); + err2 |= __put_user(s.sem_perm.gid, &usp->sem_perm.gid); + err2 |= __put_user(s.sem_perm.cuid, + &usp->sem_perm.cuid); + err2 |= __put_user (s.sem_perm.cgid, + &usp->sem_perm.cgid); + err2 |= __put_user (s.sem_perm.mode, + &usp->sem_perm.mode); + err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq); + err2 |= __put_user (s.sem_otime, &usp->sem_otime); + err2 |= __put_user (s.sem_ctime, &usp->sem_ctime); + err2 |= __put_user (s.sem_nsems, &usp->sem_nsems); + if (err2) + err = -EFAULT; + break; + } -out: + return err; } static int do_sys32_msgsnd (int first, int second, int third, void *uptr) { - struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) - + 4, GFP_USER); - struct msgbuf32 *up = (struct msgbuf32 *)uptr; - mm_segment_t old_fs; - int err; + struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + + 4, GFP_USER); + struct msgbuf32 *up = (struct msgbuf32 *)uptr; + mm_segment_t old_fs; + int err; + + if (!p) + return -ENOMEM; + err = get_user (p->mtype, &up->mtype); + err |= __copy_from_user (p->mtext, &up->mtext, second); + if (err) + goto out; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgsnd (first, p, second, third); + set_fs (old_fs); +out: + kfree (p); + return err; +} + +static int +do_sys32_msgrcv (int first, int second, int msgtyp, int third, + int version, void *uptr) +{ + struct msgbuf32 *up; + struct msgbuf *p; + mm_segment_t old_fs; + int err; + + if (!version) { + struct ipc_kludge *uipck = (struct ipc_kludge *)uptr; + struct ipc_kludge ipck; + + err = -EINVAL; + if (!uptr) + goto out; + err = -EFAULT; + if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge))) + goto out; + uptr = (void *)A(ipck.msgp); + msgtyp = ipck.msgtyp; + } + err = -ENOMEM; + p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER); + if (!p) + goto out; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgrcv (first, p, second + 4, msgtyp, third); + set_fs (old_fs); + if (err < 0) + goto free_then_out; + up = (struct msgbuf32 *)uptr; + if (put_user (p->mtype, &up->mtype) || + __copy_to_user (&up->mtext, p->mtext, err)) + err = -EFAULT; +free_then_out: + kfree (p); +out: + return err; +} + +static int +do_sys32_msgctl (int first, int second, void *uptr) +{ + int err, err2; + struct msqid_ds m; + struct msqid64_ds m64; + struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; + mm_segment_t old_fs; + + switch (second) { + + case IPC_INFO: + case IPC_RMID: + case MSG_INFO: + err = sys_msgctl (first, second, (struct msqid_ds *)uptr); + break; + + case IPC_SET: + err = get_user (m.msg_perm.uid, &up->msg_perm.uid); + err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid); + err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode); + err |= __get_user (m.msg_qbytes, &up->msg_qbytes); + if (err) + break; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgctl (first, second, &m); + set_fs (old_fs); + break; + + case IPC_STAT: + case MSG_STAT: + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgctl (first, second, &m64); + set_fs (old_fs); + err2 = put_user (m64.msg_perm.key, &up->msg_perm.key); + err2 |= __put_user(m64.msg_perm.uid, &up->msg_perm.uid); + err2 |= __put_user(m64.msg_perm.gid, &up->msg_perm.gid); + err2 |= __put_user(m64.msg_perm.cuid, &up->msg_perm.cuid); + err2 |= __put_user(m64.msg_perm.cgid, &up->msg_perm.cgid); + err2 |= __put_user(m64.msg_perm.mode, &up->msg_perm.mode); + err2 |= __put_user(m64.msg_perm.seq, &up->msg_perm.seq); + err2 |= __put_user(m64.msg_stime, &up->msg_stime); + err2 |= __put_user(m64.msg_rtime, &up->msg_rtime); + err2 |= __put_user(m64.msg_ctime, &up->msg_ctime); + err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes); + err2 |= __put_user(m64.msg_qnum, &up->msg_qnum); + err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes); + err2 |= __put_user(m64.msg_lspid, &up->msg_lspid); + err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid); + if (err2) + err = -EFAULT; + break; + + } + + return err; +} + +static int +do_sys32_shmat (int first, int second, int third, int version, void *uptr) +{ + unsigned long raddr; + u32 *uaddr = (u32 *)A((u32)third); + int err = -EINVAL; + + if (version == 1) + return err; + err = sys_shmat (first, uptr, second, &raddr); + if (err) + return err; + err = put_user (raddr, uaddr); + return err; +} + +static int +do_sys32_shmctl (int first, int second, void *uptr) +{ + int err = -EFAULT, err2; + struct shmid_ds s; + struct shmid64_ds s64; + struct shmid_ds32 *up = (struct shmid_ds32 *)uptr; + mm_segment_t old_fs; + struct shm_info32 { + int used_ids; + u32 shm_tot, shm_rss, shm_swp; + u32 swap_attempts, swap_successes; + } *uip = (struct shm_info32 *)uptr; + struct shm_info si; + + switch (second) { + + case IPC_INFO: + case IPC_RMID: + case SHM_LOCK: + case SHM_UNLOCK: + err = sys_shmctl (first, second, (struct shmid_ds *)uptr); + break; + case IPC_SET: + err = get_user (s.shm_perm.uid, &up->shm_perm.uid); + err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid); + err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode); + if (err) + break; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_shmctl (first, second, &s); + set_fs (old_fs); + break; + + case IPC_STAT: + case SHM_STAT: + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_shmctl (first, second, &s64); + set_fs (old_fs); + if (err < 0) + break; + err2 = put_user (s64.shm_perm.key, &up->shm_perm.key); + err2 |= __put_user (s64.shm_perm.uid, &up->shm_perm.uid); + err2 |= __put_user (s64.shm_perm.gid, &up->shm_perm.gid); + err2 |= __put_user (s64.shm_perm.cuid, + &up->shm_perm.cuid); + err2 |= __put_user (s64.shm_perm.cgid, + &up->shm_perm.cgid); + err2 |= __put_user (s64.shm_perm.mode, + &up->shm_perm.mode); + err2 |= __put_user (s64.shm_perm.seq, &up->shm_perm.seq); + err2 |= __put_user (s64.shm_atime, &up->shm_atime); + err2 |= __put_user (s64.shm_dtime, &up->shm_dtime); + err2 |= __put_user (s64.shm_ctime, &up->shm_ctime); + err2 |= __put_user (s64.shm_segsz, &up->shm_segsz); + err2 |= __put_user (s64.shm_nattch, &up->shm_nattch); + err2 |= __put_user (s64.shm_cpid, &up->shm_cpid); + err2 |= __put_user (s64.shm_lpid, &up->shm_lpid); + if (err2) + err = -EFAULT; + break; + + case SHM_INFO: + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_shmctl (first, second, &si); + set_fs (old_fs); + if (err < 0) + break; + err2 = put_user (si.used_ids, &uip->used_ids); + err2 |= __put_user (si.shm_tot, &uip->shm_tot); + err2 |= __put_user (si.shm_rss, &uip->shm_rss); + err2 |= __put_user (si.shm_swp, &uip->shm_swp); + err2 |= __put_user (si.swap_attempts, + &uip->swap_attempts); + err2 |= __put_user (si.swap_successes, + &uip->swap_successes); + if (err2) + err = -EFAULT; + break; + + } + return err; +} + +asmlinkage int +sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) +{ + int version, err; + + lock_kernel(); + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + switch (call) { + + case SEMOP: + /* struct sembuf is the same on 32 and 64bit :)) */ + err = sys_semop (first, (struct sembuf *)AA(ptr), + second); + break; + case SEMGET: + err = sys_semget (first, second, third); + break; + case SEMCTL: + err = do_sys32_semctl (first, second, third, + (void *)AA(ptr)); + break; + + case MSGSND: + err = do_sys32_msgsnd (first, second, third, + (void *)AA(ptr)); + break; + case MSGRCV: + err = do_sys32_msgrcv (first, second, fifth, third, + version, (void *)AA(ptr)); + break; + case MSGGET: + err = sys_msgget ((key_t) first, second); + break; + case MSGCTL: + err = do_sys32_msgctl (first, second, (void *)AA(ptr)); + break; + + case SHMAT: + err = do_sys32_shmat (first, second, third, + version, (void *)AA(ptr)); + break; + case SHMDT: + err = sys_shmdt ((char *)AA(ptr)); + break; + case SHMGET: + err = sys_shmget (first, second, third); + break; + case SHMCTL: + err = do_sys32_shmctl (first, second, (void *)AA(ptr)); + break; + default: + err = -EINVAL; + break; + } + + unlock_kernel(); + return err; +} + +/* + * sys_time() can be implemented in user-level using + * sys_gettimeofday(). IA64 did this but i386 Linux did not + * so we have to implement this system call here. + */ +asmlinkage long sys32_time(int * tloc) +{ + int i; + + /* SMP: This is fairly trivial. We grab CURRENT_TIME and + stuff it to user space. No side effects */ + i = CURRENT_TIME; + if (tloc) { + if (put_user(i,tloc)) + i = -EFAULT; + } + return i; +} + +struct rusage32 { + struct timeval32 ru_utime; + struct timeval32 ru_stime; + int ru_maxrss; + int ru_ixrss; + int ru_idrss; + int ru_isrss; + int ru_minflt; + int ru_majflt; + int ru_nswap; + int ru_inblock; + int ru_oublock; + int ru_msgsnd; + int ru_msgrcv; + int ru_nsignals; + int ru_nvcsw; + int ru_nivcsw; +}; + +static int +put_rusage (struct rusage32 *ru, struct rusage *r) +{ + int err; + + err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); + err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); + err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); + err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec); + err |= __put_user (r->ru_maxrss, &ru->ru_maxrss); + err |= __put_user (r->ru_ixrss, &ru->ru_ixrss); + err |= __put_user (r->ru_idrss, &ru->ru_idrss); + err |= __put_user (r->ru_isrss, &ru->ru_isrss); + err |= __put_user (r->ru_minflt, &ru->ru_minflt); + err |= __put_user (r->ru_majflt, &ru->ru_majflt); + err |= __put_user (r->ru_nswap, &ru->ru_nswap); + err |= __put_user (r->ru_inblock, &ru->ru_inblock); + err |= __put_user (r->ru_oublock, &ru->ru_oublock); + err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd); + err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv); + err |= __put_user (r->ru_nsignals, &ru->ru_nsignals); + err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw); + err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw); + return err; +} + +extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, + int options, struct rusage * ru); + +asmlinkage int +sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, + struct rusage32 *ru) +{ + if (!ru) + return sys_wait4(pid, stat_addr, options, NULL); + else { + struct rusage r; + int ret; + unsigned int status; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); + set_fs (old_fs); + if (put_rusage (ru, &r)) return -EFAULT; + if (stat_addr && put_user (status, stat_addr)) + return -EFAULT; + return ret; + } +} + +asmlinkage int +sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options) +{ + return sys32_wait4(pid, stat_addr, options, NULL); +} + + +extern asmlinkage int +sys_getrusage(int who, struct rusage *ru); + +asmlinkage int +sys32_getrusage(int who, struct rusage32 *ru) +{ + struct rusage r; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_getrusage(who, &r); + set_fs (old_fs); + if (put_rusage (ru, &r)) return -EFAULT; + return ret; +} + +struct tms32 { + __kernel_clock_t32 tms_utime; + __kernel_clock_t32 tms_stime; + __kernel_clock_t32 tms_cutime; + __kernel_clock_t32 tms_cstime; +}; + +extern asmlinkage long sys_times(struct tms * tbuf); + +asmlinkage long +sys32_times(struct tms32 *tbuf) +{ + struct tms t; + long ret; + mm_segment_t old_fs = get_fs (); + int err; + + set_fs (KERNEL_DS); + ret = sys_times(tbuf ? &t : NULL); + set_fs (old_fs); + if (tbuf) { + err = put_user (t.tms_utime, &tbuf->tms_utime); + err |= __put_user (t.tms_stime, &tbuf->tms_stime); + err |= __put_user (t.tms_cutime, &tbuf->tms_cutime); + err |= __put_user (t.tms_cstime, &tbuf->tms_cstime); + if (err) + ret = -EFAULT; + } + return ret; +} + +unsigned int +ia32_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr, unsigned int *val) +{ + size_t copied; + unsigned int ret; + + copied = access_process_vm(child, addr, val, sizeof(*val), 0); + return(copied != sizeof(ret) ? -EIO : 0); +} + +unsigned int +ia32_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr, unsigned int val) +{ + + if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val)) + return -EIO; + return 0; +} + +/* + * The order in which registers are stored in the ptrace regs structure + */ +#define PT_EBX 0 +#define PT_ECX 1 +#define PT_EDX 2 +#define PT_ESI 3 +#define PT_EDI 4 +#define PT_EBP 5 +#define PT_EAX 6 +#define PT_DS 7 +#define PT_ES 8 +#define PT_FS 9 +#define PT_GS 10 +#define PT_ORIG_EAX 11 +#define PT_EIP 12 +#define PT_CS 13 +#define PT_EFL 14 +#define PT_UESP 15 +#define PT_SS 16 + +unsigned int +getreg(struct task_struct *child, int regno) +{ + struct pt_regs *child_regs; + + child_regs = ia64_task_regs(child); + switch (regno / sizeof(int)) { + + case PT_EBX: + return(child_regs->r11); + case PT_ECX: + return(child_regs->r9); + case PT_EDX: + return(child_regs->r10); + case PT_ESI: + return(child_regs->r14); + case PT_EDI: + return(child_regs->r15); + case PT_EBP: + return(child_regs->r13); + case PT_EAX: + case PT_ORIG_EAX: + return(child_regs->r8); + case PT_EIP: + return(child_regs->cr_iip); + case PT_UESP: + return(child_regs->r12); + case PT_EFL: + return(child->thread.eflag); + case PT_DS: + case PT_ES: + case PT_FS: + case PT_GS: + case PT_SS: + return((unsigned int)__USER_DS); + case PT_CS: + return((unsigned int)__USER_CS); + default: + printk("getregs:unknown register %d\n", regno); + break; + + } + return(0); +} + +void +putreg(struct task_struct *child, int regno, unsigned int value) +{ + struct pt_regs *child_regs; + + child_regs = ia64_task_regs(child); + switch (regno / sizeof(int)) { + + case PT_EBX: + child_regs->r11 = value; + break; + case PT_ECX: + child_regs->r9 = value; + break; + case PT_EDX: + child_regs->r10 = value; + break; + case PT_ESI: + child_regs->r14 = value; + break; + case PT_EDI: + child_regs->r15 = value; + break; + case PT_EBP: + child_regs->r13 = value; + break; + case PT_EAX: + case PT_ORIG_EAX: + child_regs->r8 = value; + break; + case PT_EIP: + child_regs->cr_iip = value; + break; + case PT_UESP: + child_regs->r12 = value; + break; + case PT_EFL: + child->thread.eflag = value; + break; + case PT_DS: + case PT_ES: + case PT_FS: + case PT_GS: + case PT_SS: + if (value != __USER_DS) + printk("setregs:try to set invalid segment register %d = %x\n", regno, value); + break; + case PT_CS: + if (value != __USER_CS) + printk("setregs:try to set invalid segment register %d = %x\n", regno, value); + break; + default: + printk("getregs:unknown register %d\n", regno); + break; + + } +} + +static inline void +ia32f2ia64f(void *dst, void *src) +{ + + __asm__ ("ldfe f6=[%1] ;;\n\t" + "stf.spill [%0]=f6" + : + : "r"(dst), "r"(src)); + return; +} + +static inline void +ia64f2ia32f(void *dst, void *src) +{ - if (!p) - return -ENOMEM; - err = get_user (p->mtype, &up->mtype); - err |= __copy_from_user (p->mtext, &up->mtext, second); - if (err) - goto out; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgsnd (first, p, second, third); - set_fs (old_fs); -out: - kfree (p); - return err; + __asm__ ("ldf.fill f6=[%1] ;;\n\t" + "stfe [%0]=f6" + : + : "r"(dst), "r"(src)); + return; } -static int -do_sys32_msgrcv (int first, int second, int msgtyp, int third, - int version, void *uptr) +void +put_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos) { - struct msgbuf32 *up; - struct msgbuf *p; - mm_segment_t old_fs; - int err; + struct _fpreg_ia32 *f; + char buf[32]; - if (!version) { - struct ipc_kludge *uipck = (struct ipc_kludge *)uptr; - struct ipc_kludge ipck; + f = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15); + if ((regno += tos) >= 8) + regno -= 8; + switch (regno) { + + case 0: + ia64f2ia32f(f, &ptp->f8); + break; + case 1: + ia64f2ia32f(f, &ptp->f9); + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + ia64f2ia32f(f, &swp->f10 + (regno - 2)); + break; - err = -EINVAL; - if (!uptr) - goto out; - err = -EFAULT; - if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge))) - goto out; - uptr = (void *)A(ipck.msgp); - msgtyp = ipck.msgtyp; } - err = -ENOMEM; - p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER); - if (!p) - goto out; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgrcv (first, p, second + 4, msgtyp, third); - set_fs (old_fs); - if (err < 0) - goto free_then_out; - up = (struct msgbuf32 *)uptr; - if (put_user (p->mtype, &up->mtype) || - __copy_to_user (&up->mtext, p->mtext, err)) - err = -EFAULT; -free_then_out: - kfree (p); -out: - return err; + __copy_to_user(reg, f, sizeof(*reg)); + return; } -static int -do_sys32_msgctl (int first, int second, void *uptr) +void +get_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos) { - int err; - if (IPCOP_MASK (second) & - (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (MSG_INFO) | - IPCOP_MASK (IPC_RMID))) { - err = sys_msgctl (first, second, (struct msqid_ds *)uptr); - } else { - struct msqid_ds m; - struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; - mm_segment_t old_fs; - - if (second == IPC_SET) { - err = get_user (m.msg_perm.uid, &up->msg_perm.uid); - err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid); - err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode); - err |= __get_user (m.msg_qbytes, &up->msg_qbytes); - if (err) - goto out; - } - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgctl (first, second, &m); - set_fs (old_fs); - if (IPCOP_MASK (second) & - (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) { - int err2 = put_user (m.msg_perm.key, &up->msg_perm.key); - err2 |= __put_user(m.msg_perm.uid, &up->msg_perm.uid); - err2 |= __put_user(m.msg_perm.gid, &up->msg_perm.gid); - err2 |= __put_user(m.msg_perm.cuid, &up->msg_perm.cuid); - err2 |= __put_user(m.msg_perm.cgid, &up->msg_perm.cgid); - err2 |= __put_user(m.msg_perm.mode, &up->msg_perm.mode); - err2 |= __put_user(m.msg_perm.seq, &up->msg_perm.seq); - err2 |= __put_user(m.msg_stime, &up->msg_stime); - err2 |= __put_user(m.msg_rtime, &up->msg_rtime); - err2 |= __put_user(m.msg_ctime, &up->msg_ctime); - err2 |= __put_user(m.msg_cbytes, &up->msg_cbytes); - err2 |= __put_user(m.msg_qnum, &up->msg_qnum); - err2 |= __put_user(m.msg_qbytes, &up->msg_qbytes); - err2 |= __put_user(m.msg_lspid, &up->msg_lspid); - err2 |= __put_user(m.msg_lrpid, &up->msg_lrpid); - if (err2) - err = -EFAULT; - } - } + if ((regno += tos) >= 8) + regno -= 8; + switch (regno) { -out: - return err; + case 0: + __copy_from_user(&ptp->f8, reg, sizeof(*reg)); + break; + case 1: + __copy_from_user(&ptp->f9, reg, sizeof(*reg)); + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + __copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg)); + break; + + } + return; } -static int -do_sys32_shmat (int first, int second, int third, int version, void *uptr) +int +save_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save) { - unsigned long raddr; - u32 *uaddr = (u32 *)A((u32)third); - int err = -EINVAL; - - if (version == 1) - goto out; - err = sys_shmat (first, uptr, second, &raddr); - if (err) - goto out; - err = put_user (raddr, uaddr); -out: - return err; + struct switch_stack *swp; + struct pt_regs *ptp; + int i, tos; + + if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) + return(-EIO); + __put_user(tsk->thread.fcr, &save->cw); + __put_user(tsk->thread.fsr, &save->sw); + __put_user(tsk->thread.fsr >> 32, &save->tag); + __put_user(tsk->thread.fir, &save->ipoff); + __put_user(__USER_CS, &save->cssel); + __put_user(tsk->thread.fdr, &save->dataoff); + __put_user(__USER_DS, &save->datasel); + /* + * Stack frames start with 16-bytes of temp space + */ + swp = (struct switch_stack *)(tsk->thread.ksp + 16); + ptp = ia64_task_regs(tsk); + tos = (tsk->thread.fsr >> 11) & 3; + for (i = 0; i < 8; i++) + put_fpreg(i, &save->_st[i], ptp, swp, tos); + return(0); } -static int -do_sys32_shmctl (int first, int second, void *uptr) +int +restore_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save) { - int err; - - if (IPCOP_MASK (second) & - (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SHM_LOCK) - | IPCOP_MASK (SHM_UNLOCK) | IPCOP_MASK (IPC_RMID))) { - err = sys_shmctl (first, second, (struct shmid_ds *)uptr); - } else { - struct shmid_ds s; - struct shmid_ds32 *up = (struct shmid_ds32 *)uptr; - mm_segment_t old_fs; - - if (second == IPC_SET) { - err = get_user (s.shm_perm.uid, &up->shm_perm.uid); - err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid); - err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode); - if (err) - goto out; - } - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_shmctl (first, second, &s); - set_fs (old_fs); - if (err < 0) - goto out; - - /* Mask it even in this case so it becomes a CSE. */ - if (second == SHM_INFO) { - struct shm_info32 { - int used_ids; - u32 shm_tot, shm_rss, shm_swp; - u32 swap_attempts, swap_successes; - } *uip = (struct shm_info32 *)uptr; - struct shm_info *kp = (struct shm_info *)&s; - int err2 = put_user (kp->used_ids, &uip->used_ids); - err2 |= __put_user (kp->shm_tot, &uip->shm_tot); - err2 |= __put_user (kp->shm_rss, &uip->shm_rss); - err2 |= __put_user (kp->shm_swp, &uip->shm_swp); - err2 |= __put_user (kp->swap_attempts, - &uip->swap_attempts); - err2 |= __put_user (kp->swap_successes, - &uip->swap_successes); - if (err2) - err = -EFAULT; - } else if (IPCOP_MASK (second) & - (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) { - int err2 = put_user (s.shm_perm.key, &up->shm_perm.key); - err2 |= __put_user (s.shm_perm.uid, &up->shm_perm.uid); - err2 |= __put_user (s.shm_perm.gid, &up->shm_perm.gid); - err2 |= __put_user (s.shm_perm.cuid, - &up->shm_perm.cuid); - err2 |= __put_user (s.shm_perm.cgid, - &up->shm_perm.cgid); - err2 |= __put_user (s.shm_perm.mode, - &up->shm_perm.mode); - err2 |= __put_user (s.shm_perm.seq, &up->shm_perm.seq); - err2 |= __put_user (s.shm_atime, &up->shm_atime); - err2 |= __put_user (s.shm_dtime, &up->shm_dtime); - err2 |= __put_user (s.shm_ctime, &up->shm_ctime); - err2 |= __put_user (s.shm_segsz, &up->shm_segsz); - err2 |= __put_user (s.shm_nattch, &up->shm_nattch); - err2 |= __put_user (s.shm_cpid, &up->shm_cpid); - err2 |= __put_user (s.shm_lpid, &up->shm_lpid); - if (err2) - err = -EFAULT; - } - } -out: - return err; + struct switch_stack *swp; + struct pt_regs *ptp; + int i, tos; + int fsrlo, fsrhi; + + if (!access_ok(VERIFY_READ, save, sizeof(*save))) + return(-EIO); + __get_user(tsk->thread.fcr, (unsigned int *)&save->cw); + __get_user(fsrlo, (unsigned int *)&save->sw); + __get_user(fsrhi, (unsigned int *)&save->tag); + tsk->thread.fsr = ((long)fsrhi << 32) | (long)fsrlo; + __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff); + __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff); + /* + * Stack frames start with 16-bytes of temp space + */ + swp = (struct switch_stack *)(tsk->thread.ksp + 16); + ptp = ia64_task_regs(tsk); + tos = (tsk->thread.fsr >> 11) & 3; + for (i = 0; i < 8; i++) + get_fpreg(i, &save->_st[i], ptp, swp, tos); + return(0); } -asmlinkage int -sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) +asmlinkage long sys_ptrace(long, pid_t, unsigned long, unsigned long, long, long, long, long, long); + +/* + * Note that the IA32 version of `ptrace' calls the IA64 routine for + * many of the requests. This will only work for requests that do + * not need access to the calling processes `pt_regs' which is located + * at the address of `stack'. Once we call the IA64 `sys_ptrace' then + * the address of `stack' will not be the address of the `pt_regs'. + */ +asmlinkage long +sys32_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, + long arg4, long arg5, long arg6, long arg7, long stack) { - int version, err; + struct pt_regs *regs = (struct pt_regs *) &stack; + struct task_struct *child; + long i, ret; + unsigned int value; lock_kernel(); - version = call >> 16; /* hack for backward compatibility */ - call &= 0xffff; + if (request == PTRACE_TRACEME) { + ret = sys_ptrace(request, pid, addr, data, + arg4, arg5, arg6, arg7, stack); + goto out; + } - if (call <= SEMCTL) - switch (call) { - case SEMOP: - /* struct sembuf is the same on 32 and 64bit :)) */ - err = sys_semop (first, (struct sembuf *)AA(ptr), - second); - goto out; - case SEMGET: - err = sys_semget (first, second, third); - goto out; - case SEMCTL: - err = do_sys32_semctl (first, second, third, - (void *)AA(ptr)); - goto out; - default: - err = -EINVAL; - goto out; - }; - if (call <= MSGCTL) - switch (call) { - case MSGSND: - err = do_sys32_msgsnd (first, second, third, - (void *)AA(ptr)); - goto out; - case MSGRCV: - err = do_sys32_msgrcv (first, second, fifth, third, - version, (void *)AA(ptr)); - goto out; - case MSGGET: - err = sys_msgget ((key_t) first, second); - goto out; - case MSGCTL: - err = do_sys32_msgctl (first, second, (void *)AA(ptr)); - goto out; - default: - err = -EINVAL; + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + read_unlock(&tasklist_lock); + if (!child) + goto out; + ret = -EPERM; + if (pid == 1) /* no messing around with init! */ + goto out; + + if (request == PTRACE_ATTACH) { + ret = sys_ptrace(request, pid, addr, data, + arg4, arg5, arg6, arg7, stack); + goto out; + } + ret = -ESRCH; + if (!(child->flags & PF_PTRACED)) + goto out; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) goto out; + } + if (child->p_pptr != current) + goto out; + + switch (request) { + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: /* read word at location addr */ + ret = ia32_peek(regs, child, addr, &value); + if (ret == 0) + ret = put_user(value, (unsigned int *)data); + else + ret = -EIO; + goto out; + + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: /* write the word at location addr */ + ret = ia32_poke(regs, child, addr, (unsigned int)data); + goto out; + + case PTRACE_PEEKUSR: /* read word at addr in USER area */ + ret = 0; + break; + + case PTRACE_POKEUSR: /* write word at addr in USER area */ + ret = 0; + break; + + case IA32_PTRACE_GETREGS: + if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) { + ret = -EIO; + break; } - if (call <= SHMCTL) - switch (call) { - case SHMAT: - err = do_sys32_shmat (first, second, third, - version, (void *)AA(ptr)); - goto out; - case SHMDT: - err = sys_shmdt ((char *)AA(ptr)); - goto out; - case SHMGET: - err = sys_shmget (first, second, third); - goto out; - case SHMCTL: - err = do_sys32_shmctl (first, second, (void *)AA(ptr)); - goto out; - default: - err = -EINVAL; - goto out; + for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) { + __put_user(getreg(child, i),(unsigned int *) data); + data += sizeof(int); } + ret = 0; + break; - err = -EINVAL; + case IA32_PTRACE_SETREGS: + { + unsigned int tmp; + if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) { + ret = -EIO; + break; + } + for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) { + __get_user(tmp, (unsigned int *) data); + putreg(child, i, tmp); + data += sizeof(int); + } + ret = 0; + break; + } -out: - unlock_kernel(); - return err; -} + case IA32_PTRACE_GETFPREGS: + ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *)data); + break; -/* - * sys_time() can be implemented in user-level using - * sys_gettimeofday(). IA64 did this but i386 Linux did not - * so we have to implement this system call here. - */ -asmlinkage long sys32_time(int * tloc) -{ - int i; + case IA32_PTRACE_SETFPREGS: + ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *)data); + break; + + case PTRACE_SYSCALL: /* continue, stop after next syscall */ + case PTRACE_CONT: /* restart after signal. */ + case PTRACE_KILL: + case PTRACE_SINGLESTEP: /* execute chile for one instruction */ + case PTRACE_DETACH: /* detach a process */ + unlock_kernel(); + ret = sys_ptrace(request, pid, addr, data, + arg4, arg5, arg6, arg7, stack); + return(ret); + + default: + ret = -EIO; + break; - /* SMP: This is fairly trivial. We grab CURRENT_TIME and - stuff it to user space. No side effects */ - i = CURRENT_TIME; - if (tloc) { - if (put_user(i,tloc)) - i = -EFAULT; } - return i; + out: + unlock_kernel(); + return ret; } #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ @@ -2719,37 +3154,6 @@ return ret; } -struct tms32 { - __kernel_clock_t32 tms_utime; - __kernel_clock_t32 tms_stime; - __kernel_clock_t32 tms_cutime; - __kernel_clock_t32 tms_cstime; -}; - -extern asmlinkage long sys_times(struct tms * tbuf); - -asmlinkage long -sys32_times(struct tms32 *tbuf) -{ - struct tms t; - long ret; - mm_segment_t old_fs = get_fs (); - int err; - - set_fs (KERNEL_DS); - ret = sys_times(tbuf ? &t : NULL); - set_fs (old_fs); - if (tbuf) { - err = put_user (t.tms_utime, &tbuf->tms_utime); - err |= __put_user (t.tms_stime, &tbuf->tms_stime); - err |= __put_user (t.tms_cutime, &tbuf->tms_cutime); - err |= __put_user (t.tms_cstime, &tbuf->tms_cstime); - if (err) - ret = -EFAULT; - } - return ret; -} - extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist); asmlinkage int @@ -2789,23 +3193,6 @@ return ret; } -extern asmlinkage int -sys_getrusage(int who, struct rusage *ru); - -asmlinkage int -sys32_getrusage(int who, struct rusage32 *ru) -{ - struct rusage r; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_getrusage(who, &r); - set_fs (old_fs); - if (put_rusage (ru, &r)) return -EFAULT; - return ret; -} - /* XXX These as well... */ extern __inline__ struct socket * @@ -4355,4 +4742,3 @@ return ret; } #endif // NOTYET - diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/Makefile linux/arch/ia64/kdb/Makefile --- v2.3.99-pre5/linux/arch/ia64/kdb/Makefile Tue Apr 11 15:09:12 2000 +++ linux/arch/ia64/kdb/Makefile Wed Dec 31 16:00:00 1969 @@ -1,21 +0,0 @@ -# -# Makefile for ia64-specific kdb files.. -# -# Copyright 1999, Silicon Graphics Inc. -# -# Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. -# Code for IA64 written by Goutham Rao and -# Sreenivas Subramoney -# - -SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) - -.S.o: - $(CC) $(AFLAGS) -traditional -c $< -o $*.o - -L_TARGET = kdb.a -L_OBJS = kdbsupport.o kdb_io.o kdb_bt.o kdb_traps.o - -include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/kdb_bt.c linux/arch/ia64/kdb/kdb_bt.c --- v2.3.99-pre5/linux/arch/ia64/kdb/kdb_bt.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kdb/kdb_bt.c Wed Dec 31 16:00:00 1969 @@ -1,104 +0,0 @@ -/** - * Minimalist Kernel Debugger - * Machine dependent stack traceback code for IA-64. - * - * Copyright (C) 1999 Goutham Rao - * Copyright (C) 1999 Sreenivas Subramoney - * Intel Corporation, August 1999. - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang - * - * 99/12/03 D. Mosberger Reimplemented based on API. - * 99/12/06 D. Mosberger Added support for backtracing other processes. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Minimal stack back trace functionality. - */ -int -kdb_bt (int argc, const char **argv, const char **envp, struct pt_regs *regs) -{ - struct task_struct *task = current; - struct ia64_frame_info info; - char *name; - int diag; - - if (strcmp(argv[0], "btp") == 0) { - unsigned long pid; - - diag = kdbgetularg(argv[1], &pid); - if (diag) - return diag; - - task = find_task_by_pid(pid); - if (!task) { - kdb_printf("No process with pid == %d found\n", pid); - return 0; - } - regs = ia64_task_regs(task); - } else if (argc) { - kdb_printf("bt
is unsupported for IA-64\n"); - return 0; - } - - if (task == current) { - /* - * Upon entering kdb, the stack frame looks like this: - * - * +---------------------+ - * | struct pt_regs | - * +---------------------+ - * | | - * | kernel stack | - * | | - * +=====================+ <--- top of stack upon entering kdb - * | struct pt_regs | - * +---------------------+ - * | struct switch_stack | - * +---------------------+ - */ - if (user_mode(regs)) { - /* We are not implementing stack backtrace from user mode code */ - kdb_printf ("Not in Kernel\n"); - return 0; - } - ia64_unwind_init_from_current(&info, regs); - } else { - /* - * For a blocked task, the stack frame looks like this: - * - * +---------------------+ - * | struct pt_regs | - * +---------------------+ - * | | - * | kernel stack | - * | | - * +---------------------+ - * | struct switch_stack | - * +=====================+ <--- task->thread.ksp - */ - ia64_unwind_init_from_blocked_task(&info, task); - } - - kdb_printf("Ret Address Reg Stack base Name\n\n") ; - do { - unsigned long ip = ia64_unwind_get_ip(&info); - - name = kdbnearsym(ip); - if (!name) { - kdb_printf("Interrupt\n"); - return 0; - } - kdb_printf("0x%016lx: [0x%016lx] %s\n", ip, ia64_unwind_get_bsp(&info), name); - } while (ia64_unwind_to_previous_frame(&info) >= 0); - return 0; -} diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/kdb_io.c linux/arch/ia64/kdb/kdb_io.c --- v2.3.99-pre5/linux/arch/ia64/kdb/kdb_io.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kdb/kdb_io.c Wed Dec 31 16:00:00 1969 @@ -1,350 +0,0 @@ -/* - * Kernel Debugger Console I/O handler - * - * Copyright (C) 1999 Silicon Graphics, Inc. - * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) - * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) - * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) - * - * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. - * - * Modifications from: - * Chuck Fleckenstein 1999/07/20 - * Move kdb_info struct declaration to this file - * for cases where serial support is not compiled into - * the kernel. - * - * Masahiro Adegawa 1999/07/20 - * Handle some peculiarities of japanese 86/106 - * keyboards. - * - * marc@mucom.co.il 1999/07/20 - * Catch buffer overflow for serial input. - * - * Scott Foehner - * Port to ia64 - */ - -#include -#include -#include -#include -#include - -#include - -#include "pc_keyb.h" - -int kdb_port = 0; - -/* - * This module contains code to read characters from the keyboard or a serial - * port. - * - * It is used by the kernel debugger, and is polled, not interrupt driven. - * - */ - -/* - * send: Send a byte to the keyboard controller. Used primarily to - * alter LED settings. - */ - -static void -kdb_kbdsend(unsigned char byte) -{ - while (inb(KBD_STATUS_REG) & KBD_STAT_IBF) - ; - outb(KBD_DATA_REG, byte); -} - -static void -kdb_kbdsetled(int leds) -{ - kdb_kbdsend(KBD_CMD_SET_LEDS); - kdb_kbdsend((unsigned char)leds); -} - -static void -console_read (char *buffer, size_t bufsize) -{ - struct console *in; - struct console *out; - char *cp, ch; - - for (in = console_drivers; in; in = in->next) { - if ((in->flags & CON_ENABLED) && (in->read || in->wait_key)) - break; - } - for (out = console_drivers; out; out = out->next) { - if ((out->flags & CON_ENABLED) && out->write) - break; - } - - if ((!in->read && !in->wait_key) || !out->write) { - panic("kdb_io: can't do console i/o!"); - } - - if (in->read) { - /* this is untested... */ - (*in->read)(in, buffer, bufsize); - return; - } - - bufsize -= 2; /* leave room for CR & NUL terminator */ - cp = buffer; - while (1) { - ch = (*in->wait_key)(in); - switch (ch) { - case '\b': - if (cp > buffer) { - --cp, ++bufsize; - (*out->write)(out, "\b \b", 3); - } - break; - - case '\025': - while (cp > buffer) { - --cp, ++bufsize; - (*out->write)(out, "\b \b", 3); - } - break; - - case '\r': - case '\n': - (*out->write)(out, "\r\n", 2); - *cp++ = '\n'; - *cp++ = '\0'; - return; - - default: - if (bufsize > 0) { - (*out->write)(out, &ch, 1); - --bufsize; - *cp++ = ch; - } - break; - } - } -} - -char * -kdb_getscancode(char *buffer, size_t bufsize) -{ - /* - * XXX Shouldn't kdb _always_ use console based I/O? That's what the console - * abstraction is for, after all... ---davidm - */ -#ifdef CONFIG_IA64_HP_SIM - extern spinlock_t console_lock; - unsigned long flags; - - spin_lock_irqsave(&console_lock, flags); - console_read(buffer, bufsize); - spin_unlock_irqrestore(&console_lock, flags); - return buffer; -#else /* !CONFIG_IA64_HP_SIM */ - char *cp = buffer; - int scancode, scanstatus; - static int shift_lock = 0; /* CAPS LOCK state (0-off, 1-on) */ - static int shift_key = 0; /* Shift next keypress */ - static int ctrl_key = 0; - static int leds = 2; /* Num lock */ - u_short keychar; - extern u_short plain_map[], shift_map[], ctrl_map[]; - - bufsize -= 2; /* Reserve space for newline and null byte */ - - /* - * If we came in via a serial console, we allow that to - * be the input window for kdb. - */ - if (kdb_port != 0) { - char ch; - int status; -#define serial_inp(info, offset) inb((info) + (offset)) -#define serial_out(info, offset, v) outb((v), (info) + (offset)) - - while(1) { - while ((status = serial_inp(kdb_port, UART_LSR)) - & UART_LSR_DR) { -readchar: - ch = serial_inp(kdb_port, UART_RX); - if (ch == 8) { /* BS */ - if (cp > buffer) { - --cp, bufsize++; - printk("%c %c", 0x08, 0x08); - } - continue; - } - serial_out(kdb_port, UART_TX, ch); - if (ch == 13) { /* CR */ - *cp++ = '\n'; - *cp++ = '\0'; - serial_out(kdb_port, UART_TX, 10); - return(buffer); - } - /* - * Discard excess characters - */ - if (bufsize > 0) { - *cp++ = ch; - bufsize--; - } - } - while (((status = serial_inp(kdb_port, UART_LSR)) - & UART_LSR_DR) == 0); - } - } - - while (1) { - - /* - * Wait for a valid scancode - */ - - while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) - ; - - /* - * Fetch the scancode - */ - scancode = inb(KBD_DATA_REG); - scanstatus = inb(KBD_STATUS_REG); - - /* - * Ignore mouse events. - */ - if (scanstatus & KBD_STAT_MOUSE_OBF) - continue; - - /* - * Ignore release, trigger on make - * (except for shift keys, where we want to - * keep the shift state so long as the key is - * held down). - */ - - if (((scancode&0x7f) == 0x2a) - || ((scancode&0x7f) == 0x36)) { - /* - * Next key may use shift table - */ - if ((scancode & 0x80) == 0) { - shift_key=1; - } else { - shift_key=0; - } - continue; - } - - if ((scancode&0x7f) == 0x1d) { - /* - * Left ctrl key - */ - if ((scancode & 0x80) == 0) { - ctrl_key = 1; - } else { - ctrl_key = 0; - } - continue; - } - - if ((scancode & 0x80) != 0) - continue; - - scancode &= 0x7f; - - /* - * Translate scancode - */ - - if (scancode == 0x3a) { - /* - * Toggle caps lock - */ - shift_lock ^= 1; - leds ^= 0x4; /* toggle caps lock led */ - - kdb_kbdsetled(leds); - continue; - } - - if (scancode == 0x0e) { - /* - * Backspace - */ - if (cp > buffer) { - --cp, bufsize++; - - /* - * XXX - erase character on screen - */ - printk("%c %c", 0x08, 0x08); - } - continue; - } - - if (scancode == 0xe0) { - continue; - } - - /* - * For Japanese 86/106 keyboards - * See comment in drivers/char/pc_keyb.c. - * - Masahiro Adegawa - */ - if (scancode == 0x73) { - scancode = 0x59; - } else if (scancode == 0x7d) { - scancode = 0x7c; - } - - if (!shift_lock && !shift_key) { - keychar = plain_map[scancode]; - } else if (shift_lock || shift_key) { - keychar = shift_map[scancode]; - } else if (ctrl_key) { - keychar = ctrl_map[scancode]; - } else { - keychar = 0x0020; - printk("Unknown state/scancode (%d)\n", scancode); - } - - if ((scancode & 0x7f) == 0x1c) { - /* - * enter key. All done. - */ - printk("\n"); - break; - } - - /* - * echo the character. - */ - printk("%c", keychar&0xff); - - if (bufsize) { - --bufsize; - *cp++ = keychar&0xff; - } else { - printk("buffer overflow\n"); - break; - } - - } - - *cp++ = '\n'; /* White space for parser */ - *cp++ = '\0'; /* String termination */ - -#if defined(NOTNOW) - cp = buffer; - while (*cp) { - printk("char 0x%x\n", *cp++); - } -#endif - - return buffer; -#endif /* !CONFIG_IA64_HP_SIM */ -} - diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/kdb_traps.c linux/arch/ia64/kdb/kdb_traps.c --- v2.3.99-pre5/linux/arch/ia64/kdb/kdb_traps.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kdb/kdb_traps.c Wed Dec 31 16:00:00 1969 @@ -1,55 +0,0 @@ -#include -#include -#include -#include - -static struct kdb_bp_support { - unsigned long addr ; - int slot ; -} kdb_bp_info[NR_CPUS] ; - - -extern void kdb_bp_install (void); - -/* - * This gets invoked right before a call to ia64_fault(). - * Returns zero the normal fault handler should be invoked. - */ -long -ia64_kdb_fault_handler (unsigned long vector, unsigned long isr, unsigned long ifa, - unsigned long iim, unsigned long itir, unsigned long arg5, - unsigned long arg6, unsigned long arg7, unsigned long stack) -{ - struct switch_stack *sw = (struct switch_stack *) &stack; - struct pt_regs *regs = (struct pt_regs *) (sw + 1); - int bundle_slot; - - /* - * TBD - * If KDB is configured, enter KDB for any fault. - */ - if ((vector == 29) || (vector == 35) || (vector == 36)) { - if (!user_mode(regs)) { - bundle_slot = ia64_psr(regs)->ri; - if (vector == 29) { - if (bundle_slot == 0) { - kdb_bp_info[0].addr = regs->cr_iip; - kdb_bp_info[0].slot = bundle_slot; - kdb(KDB_REASON_FLTDBG, 0, regs); - } else { - if ((bundle_slot < 3) && - (kdb_bp_info[0].addr == regs->cr_iip)) - { - ia64_psr(regs)->id = 1; - ia64_psr(regs)->db = 1; - kdb_bp_install() ; - } else /* some error ?? */ - kdb(KDB_REASON_FLTDBG, 0, regs); - } - } else /* single step or taken branch */ - kdb(KDB_REASON_DEBUG, 0, regs); - return 1; - } - } - return 0; -} diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/kdbsupport.c linux/arch/ia64/kdb/kdbsupport.c --- v2.3.99-pre5/linux/arch/ia64/kdb/kdbsupport.c Sat Feb 26 22:31:39 2000 +++ linux/arch/ia64/kdb/kdbsupport.c Wed Dec 31 16:00:00 1969 @@ -1,1329 +0,0 @@ -/* - * Minimalist Kernel Debugger - * - * Copyright (C) 1999 Silicon Graphics, Inc. - * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) - * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) - * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) - * Copyright (C) David Mosberger-Tang - * - * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. - * - * Modifications from: - * Richard Bass 1999/07/20 - * Many bug fixes and enhancements. - * Scott Foehner - * Port to ia64 - * Srinivasa Thirumalachar - * RSE support for ia64 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -extern kdb_state_t kdb_state ; -k_machreg_t dbregs[KDB_DBREGS]; - -static int __init -kdb_setup (char *str) -{ - kdb_flags |= KDB_FLAG_EARLYKDB; - return 1; -} - -__setup("kdb", kdb_setup); - -static int -kdb_ia64_itm (int argc, const char **argv, const char **envp, struct pt_regs *regs) -{ - int diag; - unsigned long val; - - diag = kdbgetularg(argv[1], &val); - if (diag) - return diag; - kdb_printf("new itm=%0xlx\n", val); - - ia64_set_itm(val); - return 0; -} - -static int -kdb_ia64_sir (int argc, const char **argv, const char **envp, struct pt_regs *regs) -{ - u64 lid, tpr, lrr0, lrr1, itv, pmv, cmcv; - - asm ("mov %0=cr.lid" : "=r"(lid)); - asm ("mov %0=cr.tpr" : "=r"(tpr)); - asm ("mov %0=cr.lrr0" : "=r"(lrr0)); - asm ("mov %0=cr.lrr1" : "=r"(lrr1)); - printk("lid=0x%lx, tpr=0x%lx, lrr0=0x%lx, llr1=0x%lx\n", lid, tpr, lrr0, lrr1); - - asm ("mov %0=cr.itv" : "=r"(itv)); - asm ("mov %0=cr.pmv" : "=r"(pmv)); - asm ("mov %0=cr.cmcv" : "=r"(cmcv)); - printk("itv=0x%lx, pmv=0x%lx, cmcv=0x%lx\n", itv, pmv, cmcv); - - printk("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n", - ia64_get_irr0(), ia64_get_irr1(), ia64_get_irr2(), ia64_get_irr3()); - - printk("itc=0x%016lx, itm=0x%016lx\n", ia64_get_itc(), ia64_get_itm()); - return 0; -} - -void __init -kdb_init (void) -{ - extern void kdb_inittab(void); - unsigned long reg; - - kdb_inittab(); - kdb_initbptab(); -#if 0 - kdb_disinit(); -#endif - kdb_printf("kdb version %d.%d by Scott Lurndal. "\ - "Copyright SGI, All Rights Reserved\n", - KDB_MAJOR_VERSION, KDB_MINOR_VERSION); - - /* Enable debug registers */ - __asm__ ("mov %0=psr":"=r"(reg)); - reg |= IA64_PSR_DB; - __asm__ ("mov psr.l=%0"::"r"(reg)); - ia64_srlz_d(); - - /* Init kdb state */ - kdb_state.bkpt_handling_state = BKPTSTATE_NOT_HANDLED ; - - kdb_register("irr", kdb_ia64_sir, "", "Show interrupt registers", 0); - kdb_register("itm", kdb_ia64_itm, "", "Set new ITM value", 0); -} - -/* - * kdbprintf - * kdbgetword - * kdb_getstr - */ - -char * -kbd_getstr(char *buffer, size_t bufsize, char *prompt) -{ - extern char* kdb_getscancode(char *, size_t); - -#if defined(CONFIG_SMP) - kdb_printf(prompt, smp_processor_id()); -#else - kdb_printf("%s", prompt); -#endif - - return kdb_getscancode(buffer, bufsize); - -} - -int -kdb_printf(const char *fmt, ...) -{ - char buffer[256]; - va_list ap; - int diag; - int linecount; - - diag = kdbgetintenv("LINES", &linecount); - if (diag) - linecount = 22; - - va_start(ap, fmt); - vsprintf(buffer, fmt, ap); - va_end(ap); - - printk("%s", buffer); -#if 0 - if (strchr(buffer, '\n') != NULL) { - kdb_nextline++; - } - - if (kdb_nextline == linecount) { - char buf1[16]; - char buf2[32]; - extern char* kdb_getscancode(char *, size_t); - char *moreprompt; - - /* - * Pause until cr. - */ - moreprompt = kdbgetenv("MOREPROMPT"); - if (moreprompt == NULL) { - moreprompt = "more> "; - } - -#if defined(CONFIG_SMP) - if (strchr(moreprompt, '%')) { - sprintf(buf2, moreprompt, smp_processor_id()); - moreprompt = buf2; - } -#endif - - printk(moreprompt); - (void) kdb_getscancode(buf1, sizeof(buf1)); - - kdb_nextline = 1; - - if ((buf1[0] == 'q') - || (buf1[0] == 'Q')) { - kdb_longjmp(&kdbjmpbuf, 1); - } - } -#endif - return 0; -} - -unsigned long -kdbgetword(unsigned long addr, int width) -{ - /* - * This function checks the address for validity. Any address - * in the range PAGE_OFFSET to high_memory is legal, any address - * which maps to a vmalloc region is legal, and any address which - * is a user address, we use get_user() to verify validity. - */ - - if (addr < PAGE_OFFSET) { - /* - * Usermode address. - */ - unsigned long diag; - unsigned long ulval; - - switch (width) { - case 8: - { unsigned long *lp; - - lp = (unsigned long *) addr; - diag = get_user(ulval, lp); - break; - } - case 4: - { unsigned int *ip; - - ip = (unsigned int *) addr; - diag = get_user(ulval, ip); - break; - } - case 2: - { unsigned short *sp; - - sp = (unsigned short *) addr; - diag = get_user(ulval, sp); - break; - } - case 1: - { unsigned char *cp; - - cp = (unsigned char *) addr; - diag = get_user(ulval, cp); - break; - } - default: - printk("kdbgetword: Bad width\n"); - return 0L; - } - - if (diag) { - if ((kdb_flags & KDB_FLAG_SUPRESS) == 0) { - printk("kdb: Bad user address 0x%lx\n", addr); - kdb_flags |= KDB_FLAG_SUPRESS; - } - return 0L; - } - kdb_flags &= ~KDB_FLAG_SUPRESS; - return ulval; - } - - if (addr > (unsigned long)high_memory) { - extern int kdb_vmlist_check(unsigned long, unsigned long); - - if (!kdb_vmlist_check(addr, addr+width)) { - /* - * Would appear to be an illegal kernel address; - * Print a message once, and don't print again until - * a legal address is used. - */ - if ((kdb_flags & KDB_FLAG_SUPRESS) == 0) { - printk("kdb: Bad kernel address 0x%lx\n", addr); - kdb_flags |= KDB_FLAG_SUPRESS; - } - return 0L; - } - } - - /* - * A good address. Reset error flag. - */ - kdb_flags &= ~KDB_FLAG_SUPRESS; - - switch (width) { - case 8: - { unsigned long *lp; - - lp = (unsigned long *)(addr); - return *lp; - } - case 4: - { unsigned int *ip; - - ip = (unsigned int *)(addr); - return *ip; - } - case 2: - { unsigned short *sp; - - sp = (unsigned short *)(addr); - return *sp; - } - case 1: - { unsigned char *cp; - - cp = (unsigned char *)(addr); - return *cp; - } - } - - printk("kdbgetword: Bad width\n"); - return 0L; -} - -/* - * Start of breakpoint management routines - */ - -/* - * Arg: bp structure - */ - -int -kdb_allocdbreg(kdb_bp_t *bp) -{ - int i=0; - - /* For inst bkpt, just return. No hw reg alloc to be done. */ - - if (bp->bp_mode == BKPTMODE_INST) { - return i; - } else if (bp->bp_mode == BKPTMODE_DATAW) { - for(i=0; ibp_mode == BKPTMODE_DATAW) - dbregs[bp->bp_reg] = 0xffffffff; -} - -void -kdb_initdbregs(void) -{ - int i; - - for(i=0; ibp_addr ; - bundle_t *bundle = (bundle_t *)bp->bp_longinst; - - /* save current bundle */ - *bundle = *(bundle_t *)addr ; - - /* Set the break point! */ - ((bundle_t *)addr)->lform.low8 = ( - (((bundle_t *)addr)->lform.low8 & ~INST_SLOT0_MASK) | - BREAK_INSTR); - - /* set flag */ - bp->bp_instvalid = 1 ; - - /* flush icache as it is stale now */ - ia64_flush_icache_page((unsigned long)addr) ; - -#ifdef KDB_DEBUG - kdb_printf ("[0x%016lx]: install 0x%016lx with 0x%016lx\n", - addr, bundle->lform.low8, addr[0]) ; -#endif - return 0 ; -} - -int -install_databkpt(kdb_bp_t *bp) -{ - unsigned long dbreg_addr = bp->bp_reg * 2; - unsigned long dbreg_cond = dbreg_addr + 1; - unsigned long value = 0x8fffffffffffffff; - unsigned long addr = (unsigned long)bp->bp_addr; - __asm__ ("mov dbr[%0]=%1"::"r"(dbreg_cond),"r"(value)); -// __asm__ ("movl %0,%%db0\n\t"::"r"(contents)); - __asm__ ("mov dbr[%0]=%1"::"r"(dbreg_addr),"r"(addr)); - ia64_insn_group_barrier(); - ia64_srlz_i(); - ia64_insn_group_barrier(); - -#ifdef KDB_DEBUG - kdb_printf("installed dbkpt at 0x%016lx\n", addr) ; -#endif - return 0; -} - -int -kdbinstalldbreg(kdb_bp_t *bp) -{ - if (bp->bp_mode == BKPTMODE_INST) { - return install_instbkpt(bp) ; - } else if (bp->bp_mode == BKPTMODE_DATAW) { - return install_databkpt(bp) ; - } - return 0; -} - -void -remove_instbkpt(kdb_bp_t *bp) -{ - unsigned long *addr = (unsigned long *)bp->bp_addr ; - bundle_t *bundle = (bundle_t *)bp->bp_longinst; - - if (!bp->bp_instvalid) - /* Nothing to remove. If we just alloced the bkpt - * but never resumed, the bp_inst will not be valid. */ - return ; - -#ifdef KDB_DEBUG - kdb_printf ("[0x%016lx]: remove 0x%016lx with 0x%016lx\n", - addr, addr[0], bundle->lform.low8) ; -#endif - - /* restore current bundle */ - *(bundle_t *)addr = *bundle ; - /* reset the flag */ - bp->bp_instvalid = 0 ; - ia64_flush_icache_page((unsigned long)addr) ; -} - -void -remove_databkpt(kdb_bp_t *bp) -{ - int regnum = bp->bp_reg ; - unsigned long dbreg_addr = regnum * 2; - unsigned long dbreg_cond = dbreg_addr + 1; - unsigned long value = 0x0fffffffffffffff; - __asm__ ("mov dbr[%0]=%1"::"r"(dbreg_cond),"r"(value)); -// __asm__ ("movl %0,%%db0\n\t"::"r"(contents)); - ia64_insn_group_barrier(); - ia64_srlz_i(); - ia64_insn_group_barrier(); - -#ifdef KDB_DEBUG - kdb_printf("removed dbkpt at 0x%016lx\n", bp->bp_addr) ; -#endif -} - -void -kdbremovedbreg(kdb_bp_t *bp) -{ - if (bp->bp_mode == BKPTMODE_INST) { - remove_instbkpt(bp) ; - } else if (bp->bp_mode == BKPTMODE_DATAW) { - remove_databkpt(bp) ; - } -} - -k_machreg_t -kdb_getdr6(void) -{ - return kdb_getdr(6); -} - -k_machreg_t -kdb_getdr7(void) -{ - return kdb_getdr(7); -} - -k_machreg_t -kdb_getdr(int regnum) -{ - k_machreg_t contents = 0; - unsigned long reg = (unsigned long)regnum; - - __asm__ ("mov %0=ibr[%1]"::"r"(contents),"r"(reg)); -// __asm__ ("mov ibr[%0]=%1"::"r"(dbreg_cond),"r"(value)); - - return contents; -} - - -k_machreg_t -kdb_getcr(int regnum) -{ - k_machreg_t contents = 0; - return contents; -} - -void -kdb_putdr6(k_machreg_t contents) -{ - kdb_putdr(6, contents); -} - -void -kdb_putdr7(k_machreg_t contents) -{ - kdb_putdr(7, contents); -} - -void -kdb_putdr(int regnum, k_machreg_t contents) -{ -} - -void -get_fault_regs(fault_regs_t *fr) -{ - fr->ifa = 0 ; - fr->isr = 0 ; - - __asm__ ("rsm psr.ic;;") ; - ia64_srlz_d(); - __asm__ ("mov %0=cr.ifa" : "=r"(fr->ifa)); - __asm__ ("mov %0=cr.isr" : "=r"(fr->isr)); - __asm__ ("ssm psr.ic;;") ; - ia64_srlz_d(); -} - -/* - * kdb_db_trap - * - * Perform breakpoint processing upon entry to the - * processor debugger fault. Determine and print - * the active breakpoint. - * - * Parameters: - * ef Exception frame containing machine register state - * reason Why did we enter kdb - fault or break - * Outputs: - * None. - * Returns: - * 0 Standard instruction or data breakpoint encountered - * 1 Single Step fault ('ss' command) - * 2 Single Step fault, caller should continue ('ssb' command) - * Locking: - * None. - * Remarks: - * Yup, there be goto's here. - */ - -int -kdb_db_trap(struct pt_regs *ef, int reason) -{ - int i, rv=0; - - /* Trying very hard to not change the interface to kdb. - * So, eventhough we have these values in the fault function - * it is not passed in but read again. - */ - fault_regs_t faultregs ; - - if (reason == KDB_REASON_FLTDBG) - get_fault_regs(&faultregs) ; - - /* NOTE : XXX: This has to be done only for data bkpts */ - /* Prevent it from continuously faulting */ - ef->cr_ipsr |= 0x0000002000000000; - - if (ef->cr_ipsr & 0x0000010000000000) { - /* single step */ - ef->cr_ipsr &= 0xfffffeffffffffff; - if ((kdb_state.bkpt_handling_state == BKPTSTATE_HANDLED) - && (kdb_state.cmd_given == CMDGIVEN_GO)) - ; - else - kdb_printf("SS trap at 0x%lx\n", ef->cr_iip + ia64_psr(ef)->ri); - rv = 1; - kdb_state.reason_for_entry = ENTRYREASON_SSTEP ; - goto handled; - } else - kdb_state.reason_for_entry = ENTRYREASON_GO ; - - /* - * Determine which breakpoint was encountered. - */ - for(i=0; icr_iip) || - ((faultregs.ifa) && - (breakpoints[i].bp_addr == faultregs.ifa)))) { - /* - * Hit this breakpoint. Remove it while we are - * handling hit to avoid recursion. XXX ?? - */ - if (breakpoints[i].bp_addr == faultregs.ifa) - kdb_printf("Data breakpoint #%d for 0x%lx at 0x%lx\n", - i, breakpoints[i].bp_addr, ef->cr_iip + ia64_psr(ef)->ri); - else - kdb_printf("%s breakpoint #%d at 0x%lx\n", - rwtypes[0], - i, breakpoints[i].bp_addr); - - /* - * For an instruction breakpoint, disassemble - * the current instruction. - */ -#if 0 - if (rw == 0) { - kdb_id1(ef->eip); - } -#endif - - goto handled; - } - } - -#if 0 -unknown: -#endif - kdb_printf("Unknown breakpoint. Should forward. \n"); - /* Need a flag for this. The skip should be done XXX - * when a go or single step command is done for this session. - * For now it is here. - */ - ia64_increment_ip(ef) ; - return rv ; - -handled: - - /* We are here after handling a break inst/data bkpt */ - if (kdb_state.bkpt_handling_state == BKPTSTATE_NOT_HANDLED) { - kdb_state.bkpt_handling_state = BKPTSTATE_HANDLED ; - if (kdb_state.reason_for_entry == ENTRYREASON_GO) { - kdb_setsinglestep(ef) ; - kdb_state.kdb_action = ACTION_NOBPINSTALL; - /* We dont want bp install just this once */ - kdb_state.cmd_given = CMDGIVEN_UNKNOWN ; - } - } else if (kdb_state.bkpt_handling_state == BKPTSTATE_HANDLED) { - kdb_state.bkpt_handling_state = BKPTSTATE_NOT_HANDLED ; - if (kdb_state.reason_for_entry == ENTRYREASON_SSTEP) { - if (kdb_state.cmd_given == CMDGIVEN_GO) - kdb_state.kdb_action = ACTION_NOPROMPT ; - kdb_state.cmd_given = CMDGIVEN_UNKNOWN ; - } - } else - kdb_printf("Unknown value of bkpt state\n") ; - - return rv; - -} - -void -kdb_setsinglestep(struct pt_regs *regs) -{ - regs->cr_ipsr |= 0x0000010000000000; -#if 0 - regs->eflags |= EF_TF; -#endif -} - -/* - * Symbol table functions. - */ - -/* - * kdbgetsym - * - * Return the symbol table entry for the given symbol - * - * Parameters: - * symname Character string containing symbol name - * Outputs: - * Returns: - * NULL Symbol doesn't exist - * ksp Pointer to symbol table entry - * Locking: - * None. - * Remarks: - */ - -__ksymtab_t * -kdbgetsym(const char *symname) -{ - __ksymtab_t *ksp = __kdbsymtab; - int i; - - if (symname == NULL) - return NULL; - - for (i=0; i<__kdbsymtabsize; i++, ksp++) { - if (ksp->name && (strcmp(ksp->name, symname)==0)) { - return ksp; - } - } - - return NULL; -} - -/* - * kdbgetsymval - * - * Return the address of the given symbol. - * - * Parameters: - * symname Character string containing symbol name - * Outputs: - * Returns: - * 0 Symbol name is NULL - * addr Address corresponding to symname - * Locking: - * None. - * Remarks: - */ - -unsigned long -kdbgetsymval(const char *symname) -{ - __ksymtab_t *ksp = kdbgetsym(symname); - - return (ksp?ksp->value:0); -} - -/* - * kdbaddmodsym - * - * Add a symbol to the kernel debugger symbol table. Called when - * a new module is loaded into the kernel. - * - * Parameters: - * symname Character string containing symbol name - * value Value of symbol - * Outputs: - * Returns: - * 0 Successfully added to table. - * 1 Duplicate symbol - * 2 Symbol table full - * Locking: - * None. - * Remarks: - */ - -int -kdbaddmodsym(char *symname, unsigned long value) -{ - - /* - * Check for duplicate symbols. - */ - if (kdbgetsym(symname)) { - printk("kdb: Attempt to register duplicate symbol '%s' @ 0x%lx\n", - symname, value); - return 1; - } - - if (__kdbsymtabsize < __kdbmaxsymtabsize) { - __ksymtab_t *ksp = &__kdbsymtab[__kdbsymtabsize++]; - - ksp->name = symname; - ksp->value = value; - return 0; - } - - /* - * No room left in kernel symbol table. - */ - { - static int __kdbwarn = 0; - - if (__kdbwarn == 0) { - __kdbwarn++; - printk("kdb: Exceeded symbol table size. Increase CONFIG_KDB_SYMTAB_SIZE in kernel configuration\n"); - } - } - - return 2; -} - -/* - * kdbdelmodsym - * - * Add a symbol to the kernel debugger symbol table. Called when - * a new module is loaded into the kernel. - * - * Parameters: - * symname Character string containing symbol name - * value Value of symbol - * Outputs: - * Returns: - * 0 Successfully added to table. - * 1 Symbol not found - * Locking: - * None. - * Remarks: - */ - -int -kdbdelmodsym(const char *symname) -{ - __ksymtab_t *ksp, *endksp; - - if (symname == NULL) - return 1; - - /* - * Search for the symbol. If found, move - * all successive symbols down one position - * in the symbol table to avoid leaving holes. - */ - endksp = &__kdbsymtab[__kdbsymtabsize]; - for (ksp = __kdbsymtab; ksp < endksp; ksp++) { - if (ksp->name && (strcmp(ksp->name, symname) == 0)) { - endksp--; - for ( ; ksp < endksp; ksp++) { - *ksp = *(ksp + 1); - } - __kdbsymtabsize--; - return 0; - } - } - - return 1; -} - -/* - * kdbnearsym - * - * Return the name of the symbol with the nearest address - * less than 'addr'. - * - * Parameters: - * addr Address to check for symbol near - * Outputs: - * Returns: - * NULL No symbol with address less than 'addr' - * symbol Returns the actual name of the symbol. - * Locking: - * None. - * Remarks: - */ - -char * -kdbnearsym(unsigned long addr) -{ - __ksymtab_t *ksp = __kdbsymtab; - __ksymtab_t *kpp = NULL; - int i; - - for(i=0; i<__kdbsymtabsize; i++, ksp++) { - if (!ksp->name) - continue; - - if (addr == ksp->value) { - kpp = ksp; - break; - } - if (addr > ksp->value) { - if ((kpp == NULL) - || (ksp->value > kpp->value)) { - kpp = ksp; - } - } - } - - /* - * If more than 128k away, don't bother. - */ - if ((kpp == NULL) - || ((addr - kpp->value) > 0x20000)) { - return NULL; - } - - return kpp->name; -} - -/* - * kdbgetregcontents - * - * Return the contents of the register specified by the - * input string argument. Return an error if the string - * does not match a machine register. - * - * The following pseudo register names are supported: - * ®s - Prints address of exception frame - * kesp - Prints kernel stack pointer at time of fault - * sstk - Prints switch stack for ia64 - * % - Uses the value of the registers at the - * last time the user process entered kernel - * mode, instead of the registers at the time - * kdb was entered. - * - * Parameters: - * regname Pointer to string naming register - * regs Pointer to structure containing registers. - * Outputs: - * *contents Pointer to unsigned long to recieve register contents - * Returns: - * 0 Success - * KDB_BADREG Invalid register name - * Locking: - * None. - * Remarks: - * - * Note that this function is really machine independent. The kdb - * register list is not, however. - */ - -static struct kdbregs { - char *reg_name; - size_t reg_offset; -} kdbreglist[] = { - { " psr", offsetof(struct pt_regs, cr_ipsr) }, - { " ifs", offsetof(struct pt_regs, cr_ifs) }, - { " ip", offsetof(struct pt_regs, cr_iip) }, - - { "unat", offsetof(struct pt_regs, ar_unat) }, - { " pfs", offsetof(struct pt_regs, ar_pfs) }, - { " rsc", offsetof(struct pt_regs, ar_rsc) }, - - { "rnat", offsetof(struct pt_regs, ar_rnat) }, - { "bsps", offsetof(struct pt_regs, ar_bspstore) }, - { " pr", offsetof(struct pt_regs, pr) }, - - { "ldrs", offsetof(struct pt_regs, loadrs) }, - { " ccv", offsetof(struct pt_regs, ar_ccv) }, - { "fpsr", offsetof(struct pt_regs, ar_fpsr) }, - - { " b0", offsetof(struct pt_regs, b0) }, - { " b6", offsetof(struct pt_regs, b6) }, - { " b7", offsetof(struct pt_regs, b7) }, - - { " r1",offsetof(struct pt_regs, r1) }, - { " r2",offsetof(struct pt_regs, r2) }, - { " r3",offsetof(struct pt_regs, r3) }, - - { " r8",offsetof(struct pt_regs, r8) }, - { " r9",offsetof(struct pt_regs, r9) }, - { " r10",offsetof(struct pt_regs, r10) }, - - { " r11",offsetof(struct pt_regs, r11) }, - { " r12",offsetof(struct pt_regs, r12) }, - { " r13",offsetof(struct pt_regs, r13) }, - - { " r14",offsetof(struct pt_regs, r14) }, - { " r15",offsetof(struct pt_regs, r15) }, - { " r16",offsetof(struct pt_regs, r16) }, - - { " r17",offsetof(struct pt_regs, r17) }, - { " r18",offsetof(struct pt_regs, r18) }, - { " r19",offsetof(struct pt_regs, r19) }, - - { " r20",offsetof(struct pt_regs, r20) }, - { " r21",offsetof(struct pt_regs, r21) }, - { " r22",offsetof(struct pt_regs, r22) }, - - { " r23",offsetof(struct pt_regs, r23) }, - { " r24",offsetof(struct pt_regs, r24) }, - { " r25",offsetof(struct pt_regs, r25) }, - - { " r26",offsetof(struct pt_regs, r26) }, - { " r27",offsetof(struct pt_regs, r27) }, - { " r28",offsetof(struct pt_regs, r28) }, - - { " r29",offsetof(struct pt_regs, r29) }, - { " r30",offsetof(struct pt_regs, r30) }, - { " r31",offsetof(struct pt_regs, r31) }, - -}; - -static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs); - -int -kdbgetregcontents(const char *regname, - struct pt_regs *regs, - unsigned long *contents) -{ - int i; - - if (strcmp(regname, "®s") == 0) { - *contents = (unsigned long)regs; - return 0; - } - - if (strcmp(regname, "sstk") == 0) { - *contents = (unsigned long)getprsregs(regs) ; - return 0; - } - - if (strcmp(regname, "isr") == 0) { - fault_regs_t fr ; - get_fault_regs(&fr) ; - *contents = fr.isr ; - return 0 ; - } - -#if 0 - /* XXX need to verify this */ - if (strcmp(regname, "kesp") == 0) { - *contents = (unsigned long)regs + sizeof(struct pt_regs); - return 0; - } - - if (regname[0] == '%') { - /* User registers: %%e[a-c]x, etc */ - regname++; - regs = (struct pt_regs *) - (current->thread.ksp - sizeof(struct pt_regs)); - } -#endif - - for (i=0; i - * - * Parameters: - * regname Pointer to string naming register - * regs Pointer to structure containing registers. - * contents Unsigned long containing new register contents - * Outputs: - * Returns: - * 0 Success - * KDB_BADREG Invalid register name - * Locking: - * None. - * Remarks: - */ - -int -kdbsetregcontents(const char *regname, - struct pt_regs *regs, - unsigned long contents) -{ - int i; - - if (regname[0] == '%') { - regname++; - regs = (struct pt_regs *) - (current->thread.ksp - sizeof(struct pt_regs)); - } - - for (i=0; ithread.ksp - sizeof(struct pt_regs)); - } - - if (type == NULL) { - for (i=0; icr_iip + ia64_psr(regs)->ri; -} - -int -kdb_setpc(struct pt_regs *regs, k_machreg_t newpc) -{ - regs->cr_iip = newpc & ~0xf; - ia64_psr(regs)->ri = newpc & 0x3; - return 0; -} - -void -kdb_disableint(kdbintstate_t *state) -{ - int *fp = (int *)state; - int flags; - - __save_flags(flags); - __cli(); - - *fp = flags; -} - -void -kdb_restoreint(kdbintstate_t *state) -{ - int flags = *(int *)state; - __restore_flags(flags); -} - -int -kdb_putword(unsigned long addr, unsigned long contents) -{ - *(unsigned long *)addr = contents; - return 0; -} - -int -kdb_getcurrentframe(struct pt_regs *regs) -{ -#if 0 - regs->xcs = 0; -#if defined(CONFIG_KDB_FRAMEPTR) - asm volatile("movl %%ebp,%0":"=m" (*(int *)®s->ebp)); -#endif - asm volatile("movl %%esp,%0":"=m" (*(int *)®s->esp)); -#endif - return 0; -} - -unsigned long -show_cur_stack_frame(struct pt_regs *regs, int regno, unsigned long *contents) -{ - long sof = regs->cr_ifs & ((1<<7)-1) ; /* size of frame */ - unsigned long i ; - int j; - struct switch_stack *prs_regs = getprsregs(regs) ; - unsigned long *sofptr = (prs_regs? ia64_rse_skip_regs( - (unsigned long *)prs_regs->ar_bspstore, -sof) : NULL) ; - - if (!sofptr) { - printk("Unable to display Current Stack Frame\n") ; - return 0 ; - } - - if (regno < 0) - return 0 ; - - for (i=sof, j=0;i;i--,j++) { - /* remember to skip the nat collection dword */ - if ((((unsigned long)sofptr>>3) & (((1<<6)-1))) - == ((1<<6)-1)) - sofptr++ ; - - /* return the value in the reg if regno is non zero */ - - if (regno) { - if ((j+1) == regno) { - if (contents) - *contents = *sofptr ; - return -1; - } - sofptr++ ; - } else { - printk(" r%d: %016lx ", 32+j, *sofptr++) ; - if (!((j+1)%3)) printk("\n") ; - } - } - - if (regno) { - if (!i) /* bogus rse number */ - return 0 ; - } else - printk("\n") ; - - return 0 ; -} diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kdb/pc_keyb.h linux/arch/ia64/kdb/pc_keyb.h --- v2.3.99-pre5/linux/arch/ia64/kdb/pc_keyb.h Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kdb/pc_keyb.h Wed Dec 31 16:00:00 1969 @@ -1,127 +0,0 @@ -/* - * linux/drivers/char/pc_keyb.h - * - * PC Keyboard And Keyboard Controller - * - * (c) 1997 Martin Mares - */ - -/* - * Configuration Switches - */ - -#undef KBD_REPORT_ERR /* Report keyboard errors */ -#define KBD_REPORT_UNKN /* Report unknown scan codes */ -#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ -#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ -#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ - - - -#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ -#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ -#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */ - -/* - * Internal variables of the driver - */ - -extern unsigned char pckbd_read_mask; -extern unsigned char aux_device_present; - -/* - * Keyboard Controller Registers - */ - -#define KBD_STATUS_REG 0x64 /* Status register (R) */ -#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ -#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ - -/* - * Keyboard Controller Commands - */ - -#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ -#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ -#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ -#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ -#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ -#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ -#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ -#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ -#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ -#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ -#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if - initiated by the auxiliary device */ -#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ - -/* - * Keyboard Commands - */ - -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ -#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ -#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ -#define KBD_CMD_RESET 0xFF /* Reset */ - -/* - * Keyboard Replies - */ - -#define KBD_REPLY_POR 0xAA /* Power on reset */ -#define KBD_REPLY_ACK 0xFA /* Command ACK */ -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ - -/* - * Status Register Bits - */ - -#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ -#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ -#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ -#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ -#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ -#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ -#define KBD_STAT_PERR 0x80 /* Parity error */ - -#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) - -/* - * Controller Mode Register Bits - */ - -#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ -#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ -#define KBD_MODE_SYS 0x04 /* The system flag (?) */ -#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ -#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ -#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ -#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ -#define KBD_MODE_RFU 0x80 - -/* - * Mouse Commands - */ - -#define AUX_SET_RES 0xE8 /* Set resolution */ -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ -#define AUX_SET_STREAM 0xEA /* Set stream mode */ -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ -#define AUX_RESET 0xFF /* Reset aux device */ - -#define AUX_BUF_SIZE 2048 - -struct aux_queue { - unsigned long head; - unsigned long tail; - struct wait_queue *proc_list; - struct fasync_struct *fasync; - unsigned char buf[AUX_BUF_SIZE]; -}; - diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile --- v2.3.99-pre5/linux/arch/ia64/kernel/Makefile Tue Apr 11 15:09:12 2000 +++ linux/arch/ia64/kernel/Makefile Fri Apr 21 15:21:24 2000 @@ -15,13 +15,13 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o -O_OBJS := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_internal.o ivt.o \ - pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o sal_stub.o semaphore.o setup.o signal.o \ - sys_ia64.o traps.o time.o unaligned.o unwind.o +O_OBJS := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \ + pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o sal_stub.o semaphore.o setup.o \ + signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o #O_OBJS := fpreg.o #OX_OBJS := ia64_ksyms.o -ifeq ($(CONFIG_IA64_GENERIC),y) +ifdef CONFIG_IA64_GENERIC O_OBJS += machvec.o endif @@ -30,10 +30,10 @@ endif ifdef CONFIG_SMP -O_OBJS += smp.o irq_lock.o +O_OBJS += smp.o endif -ifeq ($(CONFIG_MCA),y) +ifdef CONFIG_IA64_MCA O_OBJS += mca.o mca_asm.o endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c --- v2.3.99-pre5/linux/arch/ia64/kernel/acpi.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/acpi.c Fri Apr 21 15:21:24 2000 @@ -11,12 +11,12 @@ #include #include -#include #include #include #include #include #include +#include #include #include @@ -27,13 +27,12 @@ #undef ACPI_DEBUG /* Guess what this does? */ #ifdef CONFIG_SMP -extern unsigned long ipi_base_addr; +extern struct smp_boot_data smp; #endif /* These are ugly but will be reclaimed by the kernel */ -int __initdata acpi_cpus = 0; -int __initdata acpi_apic_map[32]; -int __initdata cpu_cnt = 0; +int __initdata available_cpus = 0; +int __initdata total_cpus = 0; void (*pm_idle) (void); @@ -50,7 +49,7 @@ if ((lsapic->flags & LSAPIC_PRESENT) == 0) return; - printk(" CPU %d (%.04x:%.04x): ", cpu_cnt, lsapic->eid, lsapic->id); + printk(" CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id); if ((lsapic->flags & LSAPIC_ENABLED) == 0) { printk("Disabled.\n"); @@ -62,11 +61,17 @@ if (add) { printk("Available.\n"); - acpi_cpus++; - acpi_apic_map[cpu_cnt] = (lsapic->id << 8) | lsapic->eid; + available_cpus++; +#ifdef CONFIG_SMP +# if LARGE_CPU_ID_OK + smp.cpu_map[total_cpus] = (lsapic->id << 8) | lsapic->eid; +# else + smp.cpu_map[total_cpus] = lsapic->id; +# endif +#endif } - cpu_cnt++; + total_cpus++; } /* @@ -174,7 +179,7 @@ break; } -#ifdef ACPI_DEBUG +#if 1/*def ACPI_DEBUG*/ printk("Legacy ISA IRQ %x -> IA64 Vector %x IOSAPIC Pin %x Active %s %s Trigger\n", legacy->isa_irq, vector, iosapic_pin(vector), ((iosapic_polarity(vector) == IO_SAPIC_POL_LOW) ? "Low" : "High"), @@ -204,11 +209,11 @@ { char *p, *end; - memset(&acpi_apic_map, -1, sizeof(acpi_apic_map)); + /* Base address of IPI Message Block */ + ipi_base_addr = (unsigned long) ioremap(msapic->interrupt_block, 0); #ifdef CONFIG_SMP - /* Base address of IPI Message Block */ - ipi_base_addr = ioremap(msapic->interrupt_block, 0); + memset(&smp, -1, sizeof(smp)); #endif p = (char *) (msapic + 1); @@ -238,11 +243,22 @@ } /* Move to next table entry. */ - p += *(p + 1); +#define BAD_ACPI_TABLE +#ifdef BAD_ACPI_TABLE + /* + * Some prototype Lion's have a bad ACPI table + * requiring this fix. Without this fix, those + * machines crash during bootup. + */ + if (p[1] == 0) + p = end; + else +#endif + p += p[1]; } /* Make bootup pretty */ - printk(" %d CPUs available, %d CPUs total\n", acpi_cpus, cpu_cnt); + printk(" %d CPUs available, %d CPUs total\n", available_cpus, total_cpus); } int __init @@ -281,12 +297,15 @@ continue; acpi_parse_msapic((acpi_sapic_t *) hdrp); - } /* while() */ + } - if (acpi_cpus == 0) { +#ifdef CONFIG_SMP + if (available_cpus == 0) { printk("ACPI: Found 0 CPUS; assuming 1\n"); - acpi_cpus = 1; /* We've got at least one of these, no? */ + available_cpus = 1; /* We've got at least one of these, no? */ } + smp.cpu_count = available_cpus; +#endif return 1; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c --- v2.3.99-pre5/linux/arch/ia64/kernel/efi.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/efi.c Fri Apr 21 15:21:24 2000 @@ -24,7 +24,7 @@ #include #include -#define EFI_DEBUG +#define EFI_DEBUG 0 extern efi_status_t efi_call_phys (void *, ...); @@ -210,9 +210,8 @@ void __init efi_init (void) { - void *efi_map_start, *efi_map_end, *p; + void *efi_map_start, *efi_map_end; efi_config_table_t *config_tables; - efi_memory_desc_t *md; efi_char16_t *c16; u64 efi_desc_size; char vendor[100] = "unknown"; @@ -278,13 +277,18 @@ efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; efi_desc_size = ia64_boot_param.efi_memdesc_size; -#ifdef EFI_DEBUG +#if EFI_DEBUG /* print EFI memory map: */ - for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) { - md = p; - printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n", - i, md->type, md->attribute, - md->phys_addr, md->phys_addr + (md->num_pages<<12) - 1, md->num_pages >> 8); + { + efi_memory_desc_t *md = p; + void *p; + + for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) { + md = p; + printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n", + i, md->type, md->attribute, md->phys_addr, + md->phys_addr + (md->num_pages<<12) - 1, md->num_pages >> 8); + } } #endif } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S --- v2.3.99-pre5/linux/arch/ia64/kernel/entry.S Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/entry.S Fri Apr 21 15:21:24 2000 @@ -25,6 +25,7 @@ #include +#include #include #include #include @@ -228,11 +229,11 @@ stf.spill [r2]=f30,32 stf.spill [r3]=f31,24 ;; - st8.spill [r2]=r4,16 - st8.spill [r3]=r5,16 +.mem.offset 0,0; st8.spill [r2]=r4,16 +.mem.offset 8,0; st8.spill [r3]=r5,16 ;; - st8.spill [r2]=r6,16 - st8.spill [r3]=r7,16 +.mem.offset 0,0; st8.spill [r2]=r6,16 +.mem.offset 8,0; st8.spill [r3]=r7,16 ;; st8 [r2]=r21,16 // save b0 st8 [r3]=r22,16 // save b1 @@ -437,8 +438,8 @@ (p6) br.cond.sptk.few strace_error // syscall failed -> ;; // avoid RAW on r10 strace_save_retval: - st8.spill [r2]=r8 // store return value in slot for r8 - st8.spill [r3]=r10 // clear error indication in slot for r10 +.mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 +.mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 ia64_strace_leave_kernel: br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value .ret6: br.cond.sptk.many ia64_leave_kernel @@ -491,7 +492,9 @@ adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10 ;; + .mem.offset 0,0 (p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit + .mem.offset 8,0 (p6) st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit (p7) br.cond.spnt.few handle_syscall_error // handle potential syscall failure @@ -504,7 +507,9 @@ ;; ld4 r2=[r2] ;; - shladd r3=r2,3,r3 + shl r2=r2,SMP_LOG_CACHE_BYTES // can't use shladd here... + ;; + add r3=r2,r3 #else movl r3=softirq_state #endif @@ -550,6 +555,16 @@ 2: // check & deliver pending signals: (p2) br.call.spnt.few rp=handle_signal_delivery +#if defined(CONFIG_SMP) || defined(CONFIG_IA64_SOFTSDV_HACKS) + // Check for lost ticks + mov r2 = ar.itc + mov r3 = cr.itm + ;; + sub r2 = r2, r3 + ;; + cmp.ge p6,p7 = r2, r0 +(p6) br.call.spnt.few rp=invoke_ia64_reset_itm +#endif restore_all: // start restoring the state saved on the kernel stack (struct pt_regs): @@ -735,8 +750,8 @@ (p6) mov r9=r8 (p6) mov r10=0 ;; - st8.spill [r2]=r9 // store errno in pt_regs.r8 and set unat bit - st8.spill [r3]=r10 // store error indication in pt_regs.r10 and set unat bit +.mem.offset 0,0; st8.spill [r2]=r9 // store errno in pt_regs.r8 and set unat bit +.mem.offset 8,0; st8.spill [r3]=r10 // store error indication in pt_regs.r10 and set unat bit br.cond.sptk.many ia64_leave_kernel .endp handle_syscall_error @@ -757,6 +772,19 @@ mov rp=loc1 br.ret.sptk.many rp .endp invoke_schedule_tail + + .proc invoke_ia64_reset_itm +invoke_ia64_reset_itm: + alloc loc0=ar.pfs,8,2,0,0 + mov loc1=rp + ;; + br.call.sptk.many rp=ia64_reset_itm + ;; + mov ar.pfs=loc0 + mov rp=loc1 + br.ret.sptk.many rp + .endp invoke_ia64_reset_itm + #endif /* CONFIG_SMP */ /* @@ -855,26 +883,22 @@ .global sys_rt_sigsuspend sys_rt_sigsuspend: alloc loc0=ar.pfs,2,2,3,0 - mov r9=ar.unat // If the process is being ptraced, the signal may not actually be delivered to // the process. Instead, SIGCHLD will be sent to the parent. We need to // setup a switch_stack so ptrace can inspect the processes state if necessary. - adds r2=IA64_TASK_FLAGS_OFFSET,r13 - ;; - ld8 r2=[r2] + // Also, the process might not ptraced until stopped in sigsuspend, so this + // isn't something that we can do conditionally based upon the value of + // PF_PTRACED_BIT. mov out0=in0 // mask mov out1=in1 // sigsetsize ;; adds out2=16,sp // out1=&pt_regs - tbit.nz p16,p17=r2,PF_PTRACED_BIT -(p16) br.cond.spnt.many sigsuspend_setup_switch_stack + movl r28=back_from_sigsuspend_setup_switch_stack + mov r16=loc0 + br.cond.sptk.many save_switch_stack ;; back_from_sigsuspend_setup_switch_stack: - adds r3=-IA64_SWITCH_STACK_SIZE+IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp -(p17) adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for (dummy) switch_stack - ;; -(p17) st8 [r3]=r9 // save ar.unat in sw->caller_unat mov loc1=rp // save return address br.call.sptk.many rp=ia64_rt_sigsuspend .ret12: @@ -883,32 +907,22 @@ ld8 r9=[r3] // load new unat from sw->caller_unat mov rp=loc1 ;; -(p17) adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch_stack -(p17) mov ar.unat=r9 -(p17) mov ar.pfs=loc0 -(p17) br.ret.sptk.many rp // restore the switch stack (ptrace may have modified it): movl r28=1f br.cond.sptk.many load_switch_stack 1: br.ret.sptk.many rp // NOT REACHED - -sigsuspend_setup_switch_stack: - movl r28=back_from_sigsuspend_setup_switch_stack - mov r16=loc0 - br.cond.sptk.many save_switch_stack - // NOT REACHED - .endp sys_rt_sigsuspend .align 16 .proc sys_rt_sigreturn sys_rt_sigreturn: - alloc loc0=ar.pfs,8,1,1,0 // preserve all eight input regs in case of syscall restart! + .regstk 0,0,3,0 // inherited from gate.s:invoke_sighandler() adds out0=16,sp // out0 = &pt_regs - ;; adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for unat and padding + ;; + cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall... br.call.sptk.few rp=ia64_rt_sigreturn .ret13: adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp @@ -918,8 +932,7 @@ ;; adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch-stack frame mov ar.unat=r9 - mov ar.pfs=loc0 - br.ret.sptk.many rp + br rp .endp sys_rt_sigreturn .align 16 @@ -940,76 +953,6 @@ 2: br.cond.sptk.many rp // goes to ia64_leave_kernel .endp ia64_prepare_handle_unaligned -#ifdef CONFIG_KDB - // - // This gets called from ivt.S with: - // SAVE MIN with cover done - // SAVE REST done - // no parameters - // r15 has return value = ia64_leave_kernel - // - .align 16 - .global ia64_invoke_kdb - .proc ia64_invoke_kdb -ia64_invoke_kdb: - alloc r16=ar.pfs,0,0,4,0 - movl r28=1f // save_switch_stack protocol - ;; // avoid WAW on CFM - br.cond.sptk.many save_switch_stack // to flushrs -1: mov out0=4 // kdb entry reason - mov out1=0 // err number - adds out2=IA64_SWITCH_STACK_SIZE+16,sp // pt_regs - add out3=16,sp // switch_stack - br.call.sptk.few rp=kdb -.ret15: - movl r28=1f // load_switch_stack proto - br.cond.sptk.many load_switch_stack -1: br.ret.sptk.many rp - .endp ia64_invoke_kdb - - // - // When KDB is compiled in, we intercept each fault and give - // kdb a chance to run before calling the normal fault handler. - // - .align 16 - .global ia64_invoke_kdb_fault_handler - .proc ia64_invoke_kdb_fault_handler -ia64_invoke_kdb_fault_handler: - alloc r16=ar.pfs,5,1,5,0 - movl r28=1f - mov loc0=rp // save this - br.cond.sptk.many save_switch_stack // to flushrs - ;; // avoid WAW on CFM -1: mov out0=in0 // vector number - mov out1=in1 // cr.isr - mov out2=in2 // cr.ifa - mov out3=in3 // cr.iim - mov out4=in4 // cr.itir - br.call.sptk.few rp=ia64_kdb_fault_handler -.ret16: - - movl r28=1f - br.cond.sptk.many load_switch_stack -1: cmp.ne p6,p0=r8,r0 // did ia64_kdb_fault_handler return 0? - mov rp=loc0 -(p6) br.ret.spnt.many rp // no, we're done - ;; // avoid WAW on rp - mov out0=in0 // vector number - mov out1=in1 // cr.isr - mov out2=in2 // cr.ifa - mov out3=in3 // cr.iim - mov out4=in4 // cr.itir - mov in0=ar.pfs // preserve ar.pfs returned by load_switch_stack - br.call.sptk.few rp=ia64_fault // yup -> we need to invoke normal fault handler now -.ret17: - mov ar.pfs=in0 - mov rp=loc0 - br.ret.sptk.many rp - - .endp ia64_invoke_kdb_fault_handler - -#endif /* CONFIG_KDB */ - .rodata .align 8 .globl sys_call_table @@ -1198,8 +1141,8 @@ data8 sys_sendmsg // 1205 data8 sys_recvmsg data8 sys_pivot_root - data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_mincore + data8 sys_madvise data8 ia64_ni_syscall // 1210 data8 ia64_ni_syscall data8 ia64_ni_syscall diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S --- v2.3.99-pre5/linux/arch/ia64/kernel/gate.S Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/gate.S Fri Apr 21 15:21:24 2000 @@ -80,8 +80,6 @@ ia64_sigtramp: ld8 r10=[r3],8 // get signal handler entry point br.call.sptk.many rp=invoke_sighandler -.ret0: mov r15=__NR_rt_sigreturn - break __BREAK_SYSCALL .endp ia64_sigtramp .proc invoke_sighandler @@ -90,10 +88,9 @@ mov b6=r10 cover // push args in interrupted frame onto backing store ;; - alloc r8=ar.pfs,0,1,3,0 // get CFM0, EC0, and CPL0 into r8 - mov r17=ar.bsp // fetch ar.bsp - mov loc0=rp // save return pointer + alloc r8=ar.pfs,0,0,3,0 // get CFM0, EC0, and CPL0 into r8 ;; + mov r17=ar.bsp // fetch ar.bsp cmp.ne p8,p0=r15,r0 // do we need to switch the rbs? mov out0=r2 // signal number (p8) br.cond.spnt.few setup_rbs // yup -> (clobbers r14 and r16) @@ -101,10 +98,11 @@ adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp ;; st8 [base0]=r17,(CFM_OFF-BSP_OFF) // save sc_ar_bsp + dep r8=0,r8,38,26 // clear EC0, CPL0 and reserved bits adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp ;; - st8 [base0]=r8 // save CFM0, EC0, and CPL0 + st8 [base0]=r8 // save CFM0 adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp ;; stf.spill [base0]=f6,32 @@ -124,7 +122,8 @@ stf.spill [base0]=f14,32 stf.spill [base1]=f15,32 br.call.sptk.few rp=b6 // call the signal handler -.ret2: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp +.ret2: + adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp ;; ld8 r15=[base0],(CFM_OFF-BSP_OFF) // fetch sc_ar_bsp and advance to CFM_OFF mov r14=ar.bsp @@ -134,23 +133,11 @@ (p8) br.cond.spnt.few restore_rbs // yup -> (clobbers r14 and r16) ;; back_from_restore_rbs: - { - and r9=0x7f,r8 // r9 <- CFM0.sof - extr.u r10=r8,7,7 // r10 <- CFM0.sol - mov r11=ip - } - ;; adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp - adds r11=(cont-back_from_restore_rbs),r11 - sub r9=r9,r10 // r9 <- CFM0.sof - CFM0.sol == CFM0.nout - ;; adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp - dep r9=r9,r9,7,7 // r9.sol = r9.sof - mov b6=r11 ;; ldf.fill f6=[base0],32 ldf.fill f7=[base1],32 - mov rp=loc0 // copy return pointer out of stacked register ;; ldf.fill f8=[base0],32 ldf.fill f9=[base1],32 @@ -160,26 +147,23 @@ ;; ldf.fill f12=[base0],32 ldf.fill f13=[base1],32 - mov ar.pfs=r9 ;; ldf.fill f14=[base0],32 ldf.fill f15=[base1],32 - br.ret.sptk.few b6 -cont: mov ar.pfs=r8 // ar.pfs = CFM0 - br.ret.sptk.few rp // re-establish CFM0 + mov r15=__NR_rt_sigreturn + break __BREAK_SYSCALL .endp invoke_sighandler .proc setup_rbs setup_rbs: flushrs // must be first in insn - ;; mov ar.rsc=r0 // put RSE into enforced lazy mode adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp - mov r14=ar.rnat // get rnat as updated by flushrs ;; + mov r14=ar.rnat // get rnat as updated by flushrs mov ar.bspstore=r15 // set new register backing store area - st8 [r16]=r14 // save sc_ar_rnat ;; + st8 [r16]=r14 // save sc_ar_rnat mov ar.rsc=0xf // set RSE into eager mode, pl 3 invala // invalidate ALAT br.cond.sptk.many back_from_setup_rbs diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c --- v2.3.99-pre5/linux/arch/ia64/kernel/irq.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/irq.c Fri Apr 21 15:21:24 2000 @@ -66,7 +66,7 @@ * Controller mappings for all interrupt sources: */ irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; + { [0 ... NR_IRQS-1] = { IRQ_DISABLED, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; static void register_irq_proc (unsigned int irq); @@ -164,7 +164,7 @@ p += sprintf(p, "%10u ", atomic_read(&nmi_counter(cpu_logical_map(j)))); p += sprintf(p, "\n"); -#if CONFIG_SMP +#if defined(CONFIG_SMP) && defined(__i386__) p += sprintf(p, "LOC: "); for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10u ", @@ -182,8 +182,8 @@ */ #ifdef CONFIG_SMP -unsigned char global_irq_holder = NO_PROC_ID; -unsigned volatile int global_irq_lock; +unsigned int global_irq_holder = NO_PROC_ID; +volatile unsigned int global_irq_lock; extern void show_stack(unsigned long* esp); @@ -201,6 +201,10 @@ printk(" %d",local_bh_count(i)); printk(" ]\nStack dumps:"); +#ifdef __ia64__ + printk(" ]\nStack dumps: "); + /* for now we don't have stack dumping support... */ +#elif __i386__ for(i=0;i< smp_num_cpus;i++) { unsigned long esp; if(i==cpu) @@ -219,8 +223,13 @@ esp += sizeof(struct task_struct); show_stack((void*)esp); } +#else + You lose... +#endif printk("\nCPU %d:",cpu); +#ifdef __i386__ show_stack(NULL); +#endif printk("\n"); } @@ -250,7 +259,11 @@ /* * We have to allow irqs to arrive between __sti and __cli */ -# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") +# ifdef __ia64__ +# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop 0") +# else +# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") +# endif #endif static inline void wait_on_irq(int cpu) @@ -311,7 +324,7 @@ { if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ - if ((unsigned char) cpu == global_irq_holder) + if (cpu == global_irq_holder) return; /* Uhhuh.. Somebody else got it. Wait.. */ do { @@ -349,6 +362,15 @@ { unsigned int flags; +#ifdef __ia64__ + __save_flags(flags); + if (flags & IA64_PSR_I) { + int cpu = smp_processor_id(); + __cli(); + if (!local_irq_count(cpu)) + get_irqlock(cpu); + } +#else __save_flags(flags); if (flags & (1 << EFLAGS_IF_SHIFT)) { int cpu = smp_processor_id(); @@ -356,6 +378,7 @@ if (!local_irq_count(cpu)) get_irqlock(cpu); } +#endif } void __global_sti(void) @@ -382,7 +405,11 @@ int cpu = smp_processor_id(); __save_flags(flags); +#ifdef __ia64__ + local_enabled = (flags & IA64_PSR_I) != 0; +#else local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; +#endif /* default to local */ retval = 2 + local_enabled; @@ -479,11 +506,13 @@ { disable_irq_nosync(irq); +#ifdef CONFIG_SMP if (!local_irq_count(smp_processor_id())) { do { barrier(); } while (irq_desc[irq].status & IRQ_INPROGRESS); } +#endif } void enable_irq(unsigned int irq) @@ -559,15 +588,12 @@ /* * If there is no IRQ handler or it was disabled, exit early. - Since we set PENDING, if another processor is handling - a different instance of this same irq, the other processor - will take care of it. + * Since we set PENDING, if another processor is handling + * a different instance of this same irq, the other processor + * will take care of it. */ if (!action) -{ - desc->status = status & ~IRQ_INPROGRESS; goto out; -} /* * Edge triggered interrupts need to remember @@ -597,15 +623,6 @@ desc->handler->end(irq); spin_unlock(&desc->lock); -#if 0 - /* - * let kernel exit path take care of this; we want to do the - * CPU EOI before doing softirq() so a new interrupt can come - * through - */ - if (softirq_state[cpu].active & softirq_state[cpu].mask) - do_softirq(); -#endif return 1; } @@ -1019,7 +1036,7 @@ irq_dir[irq] = proc_mkdir(name, root_irq_dir); /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); entry->nlink = 1; entry->data = (void *)(long)irq; @@ -1040,7 +1057,7 @@ root_irq_dir = proc_mkdir("irq", 0); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir); + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); entry->nlink = 1; entry->data = (void *)&prof_cpu_mask; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/irq_ia64.c linux/arch/ia64/kernel/irq_ia64.c --- v2.3.99-pre5/linux/arch/ia64/kernel/irq_ia64.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/irq_ia64.c Fri Apr 21 15:21:24 2000 @@ -25,10 +25,6 @@ #include #include -#ifdef CONFIG_KDB -# include -#endif - #include #include #include @@ -41,13 +37,15 @@ spinlock_t ivr_read_lock; #endif +unsigned long ipi_base_addr = IPI_DEFAULT_BASE_ADDR; /* default base addr of IPI table */ + /* * Legacy IRQ to IA-64 vector translation table. Any vector not in * this table maps to itself (ie: irq 0x30 => IA64 vector 0x30) */ -__u8 isa_irq_to_vector_map[IA64_MIN_VECTORED_IRQ] = { +__u8 isa_irq_to_vector_map[16] = { /* 8259 IRQ translation, first 16 entries */ - 0x60, 0x50, 0x0f, 0x51, 0x52, 0x53, 0x43, 0x54, + 0x60, 0x50, 0x10, 0x51, 0x52, 0x53, 0x43, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x40, 0x41 }; @@ -80,8 +78,8 @@ #ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC # ifndef CONFIG_SMP static unsigned int max_prio = 0; -# endif unsigned int prev_prio; +# endif unsigned long eoi_ptr; # ifdef CONFIG_USB @@ -95,21 +93,25 @@ * Stop IPIs by getting the ivr_read_lock */ spin_lock(&ivr_read_lock); + { + unsigned int tmp; - /* - * Disable PCI writes - */ - outl(0x80ff81c0, 0xcf8); - outl(0x73002188, 0xcfc); - eoi_ptr = inl(0xcfc); - - vector = ia64_get_ivr(); - - /* - * Enable PCI writes - */ - outl(0x73182188, 0xcfc); - + /* + * Disable PCI writes + */ + outl(0x80ff81c0, 0xcf8); + tmp = inl(0xcfc); + outl(tmp | 0x400, 0xcfc); + + eoi_ptr = inl(0xcfc); + + vector = ia64_get_ivr(); + + /* + * Enable PCI writes + */ + outl(tmp, 0xcfc); + } spin_unlock(&ivr_read_lock); # ifdef CONFIG_USB @@ -152,9 +154,6 @@ printk("ia64_handle_irq: DANGER: less than 1KB of free stack space!!\n" "(bsp=0x%lx, sp=%lx)\n", bsp, sp); } -#ifdef CONFIG_KDB - kdb(KDB_REASON_PANIC, 0, regs); -#endif } /* @@ -175,9 +174,6 @@ if (!pEOI) { printk("Yikes: ia64_handle_irq() without pEOI!!\n"); asm volatile ("cmp.eq p1,p0=r0,r0" : "=r"(pEOI)); -# ifdef CONFIG_KDB - kdb(KDB_REASON_PANIC, 0, regs); -# endif } } @@ -195,13 +191,13 @@ #ifdef CONFIG_SMP -void __init -init_IRQ_SMP (void) -{ - if (request_irq(IPI_IRQ, handle_IPI, 0, "IPI", NULL)) - panic("Could not allocate IPI Interrupt Handler!"); -} +extern void handle_IPI (int irq, void *dev_id, struct pt_regs *regs); +static struct irqaction ipi_irqaction = { + handler: handle_IPI, + flags: SA_INTERRUPT, + name: "IPI" +}; #endif void __init @@ -214,13 +210,14 @@ ia64_set_lrr0(0, 1); ia64_set_lrr1(0, 1); - irq_desc[TIMER_IRQ].handler = &irq_type_ia64_internal; + irq_desc[TIMER_IRQ].handler = &irq_type_ia64_sapic; + irq_desc[IA64_SPURIOUS_INT].handler = &irq_type_ia64_sapic; #ifdef CONFIG_SMP /* * Configure the IPI vector and handler */ - irq_desc[IPI_IRQ].handler = &irq_type_ia64_internal; - init_IRQ_SMP(); + irq_desc[IPI_IRQ].handler = &irq_type_ia64_sapic; + setup_irq(IPI_IRQ, &ipi_irqaction); #endif ia64_set_pmv(1 << 16); @@ -232,16 +229,26 @@ ia64_set_tpr(0); } -/* TBD: - * Certain IA64 platforms can have inter-processor interrupt support. - * This interface is supposed to default to the IA64 IPI block-based - * mechanism if the platform doesn't provide a separate mechanism - * for IPIs. - * Choices : (1) Extend hw_interrupt_type interfaces - * (2) Use machine vector mechanism - * For now defining the following interface as a place holder. - */ void -ipi_send (int cpu, int vector, int delivery_mode) +ipi_send (int cpu, int vector, int delivery_mode, int redirect) { + unsigned long ipi_addr; + unsigned long ipi_data; +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + unsigned long flags; +#endif +# define EID 0 + + ipi_data = (delivery_mode << 8) | (vector & 0xff); + ipi_addr = ipi_base_addr | ((cpu << 8 | EID) << 4) | ((redirect & 1) << 3); + +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + spin_lock_irqsave(&ivr_read_lock, flags); +#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ + + writeq(ipi_data, ipi_addr); + +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + spin_unlock_irqrestore(&ivr_read_lock, flags); +#endif } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/irq_internal.c linux/arch/ia64/kernel/irq_internal.c --- v2.3.99-pre5/linux/arch/ia64/kernel/irq_internal.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/irq_internal.c Wed Dec 31 16:00:00 1969 @@ -1,36 +0,0 @@ -/* - * Internal Interrupt Vectors - * - * This takes care of interrupts that are generated by the CPU - * internally, such as the ITC and IPI interrupts. - * - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999 Walt Drummond - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 David Mosberger-Tang - */ - -#include - -static unsigned int -internal_noop_startup (unsigned int irq) -{ - return 0; -} - -static void -internal_noop (unsigned int irq) -{ - /* nuthing to do... */ -} - -struct hw_interrupt_type irq_type_ia64_internal = { - typename: "IA64-internal", - startup: internal_noop_startup, - shutdown: internal_noop, - enable: internal_noop, - disable: internal_noop, - ack: internal_noop, - end: internal_noop, - set_affinity: (void (*)(unsigned int, unsigned long)) internal_noop -}; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/irq_lock.c linux/arch/ia64/kernel/irq_lock.c --- v2.3.99-pre5/linux/arch/ia64/kernel/irq_lock.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/irq_lock.c Wed Dec 31 16:00:00 1969 @@ -1,287 +0,0 @@ -/* - * SMP IRQ Lock support - * - * Global interrupt locks for SMP. Allow interrupts to come in on any - * CPU, yet make cli/sti act globally to protect critical regions.. - * These function usually appear in irq.c, but I think it's cleaner this way. - * - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999 Walt Drummond - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -int global_irq_holder = NO_PROC_ID; -spinlock_t global_irq_lock; -atomic_t global_irq_count; -atomic_t global_bh_count; -spinlock_t global_bh_lock; - -#define INIT_STUCK (1<<26) - -void -irq_enter(int cpu, int irq) -{ - int stuck = INIT_STUCK; - - hardirq_enter(cpu, irq); - barrier(); - while (global_irq_lock.lock) { - if (cpu == global_irq_holder) { - break; - } - - if (!--stuck) { - printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n", - irq, cpu,global_irq_holder); - stuck = INIT_STUCK; - } - barrier(); - } -} - -void -irq_exit(int cpu, int irq) -{ - hardirq_exit(cpu, irq); - release_irqlock(cpu); -} - -static void -show(char * str) -{ - int i; - unsigned long *stack; - int cpu = smp_processor_id(); - - printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [%d %d]\n", - atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]); - printk("bh: %d [%d %d]\n", - atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]); - - stack = (unsigned long *) &stack; - for (i = 40; i ; i--) { - unsigned long x = *++stack; - if (x > (unsigned long) &get_options && x < (unsigned long) &vsprintf) { - printk("<[%08lx]> ", x); - } - } -} - -#define MAXCOUNT 100000000 - -static inline void -wait_on_bh(void) -{ - int count = MAXCOUNT; - do { - if (!--count) { - show("wait_on_bh"); - count = ~0; - } - /* nothing .. wait for the other bh's to go away */ - } while (atomic_read(&global_bh_count) != 0); -} - -static inline void -wait_on_irq(int cpu) -{ - int count = MAXCOUNT; - - for (;;) { - - /* - * Wait until all interrupts are gone. Wait - * for bottom half handlers unless we're - * already executing in one.. - */ - if (!atomic_read(&global_irq_count)) { - if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) - break; - } - - /* Duh, we have to loop. Release the lock to avoid deadlocks */ - spin_unlock(&global_irq_lock); - mb(); - - for (;;) { - if (!--count) { - show("wait_on_irq"); - count = ~0; - } - __sti(); - udelay(cpu + 1); - __cli(); - if (atomic_read(&global_irq_count)) - continue; - if (global_irq_lock.lock) - continue; - if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) - continue; - if (spin_trylock(&global_irq_lock)) - break; - } - } -} - -/* - * This is called when we want to synchronize with - * bottom half handlers. We need to wait until - * no other CPU is executing any bottom half handler. - * - * Don't wait if we're already running in an interrupt - * context or are inside a bh handler. - */ -void -synchronize_bh(void) -{ - if (atomic_read(&global_bh_count)) { - int cpu = smp_processor_id(); - if (!local_irq_count[cpu] && !local_bh_count[cpu]) { - wait_on_bh(); - } - } -} - - -/* - * This is called when we want to synchronize with - * interrupts. We may for example tell a device to - * stop sending interrupts: but to make sure there - * are no interrupts that are executing on another - * CPU we need to call this function. - */ -void -synchronize_irq(void) -{ - int cpu = smp_processor_id(); - int local_count; - int global_count; - - mb(); - do { - local_count = local_irq_count[cpu]; - global_count = atomic_read(&global_irq_count); - } while (global_count != local_count); -} - -static inline void -get_irqlock(int cpu) -{ - if (!spin_trylock(&global_irq_lock)) { - /* do we already hold the lock? */ - if ((unsigned char) cpu == global_irq_holder) - return; - /* Uhhuh.. Somebody else got it. Wait.. */ - spin_lock(&global_irq_lock); - } - /* - * We also to make sure that nobody else is running - * in an interrupt context. - */ - wait_on_irq(cpu); - - /* - * Ok, finally.. - */ - global_irq_holder = cpu; -} - -/* - * A global "cli()" while in an interrupt context - * turns into just a local cli(). Interrupts - * should use spinlocks for the (very unlikely) - * case that they ever want to protect against - * each other. - * - * If we already have local interrupts disabled, - * this will not turn a local disable into a - * global one (problems with spinlocks: this makes - * save_flags+cli+sti usable inside a spinlock). - */ -void -__global_cli(void) -{ - unsigned long flags; - - __save_flags(flags); - if (flags & IA64_PSR_I) { - int cpu = smp_processor_id(); - __cli(); - if (!local_irq_count[cpu]) - get_irqlock(cpu); - } -} - -void -__global_sti(void) -{ - int cpu = smp_processor_id(); - - if (!local_irq_count[cpu]) - release_irqlock(cpu); - __sti(); -} - -/* - * SMP flags value to restore to: - * 0 - global cli - * 1 - global sti - * 2 - local cli - * 3 - local sti - */ -unsigned long -__global_save_flags(void) -{ - int retval; - int local_enabled; - unsigned long flags; - - __save_flags(flags); - local_enabled = flags & IA64_PSR_I; - /* default to local */ - retval = 2 + local_enabled; - - /* check for global flags if we're not in an interrupt */ - if (!local_irq_count[smp_processor_id()]) { - if (local_enabled) - retval = 1; - if (global_irq_holder == (unsigned char) smp_processor_id()) - retval = 0; - } - return retval; -} - -void -__global_restore_flags(unsigned long flags) -{ - switch (flags) { - case 0: - __global_cli(); - break; - case 1: - __global_sti(); - break; - case 2: - __cli(); - break; - case 3: - __sti(); - break; - default: - printk("global_restore_flags: %08lx (%08lx) from %p\n", - flags, (&flags)[-1], __builtin_return_address(0)); - } -} diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/irq_sapic.c linux/arch/ia64/kernel/irq_sapic.c --- v2.3.99-pre5/linux/arch/ia64/kernel/irq_sapic.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/irq_sapic.c Fri Apr 21 15:21:24 2000 @@ -0,0 +1,38 @@ +/* + * SAPIC Interrupt Controller + * + * This takes care of interrupts that are generated by the CPU's + * internal Streamlined Advanced Programmable Interrupt Controller + * (SAPIC), such as the ITC and IPI interrupts. + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 2000 Hewlett-Packard Co + * Copyright (C) 2000 David Mosberger-Tang + */ + +#include +#include + +static unsigned int +sapic_noop_startup (unsigned int irq) +{ + return 0; +} + +static void +sapic_noop (unsigned int irq) +{ + /* nuthing to do... */ +} + +struct hw_interrupt_type irq_type_ia64_sapic = { + typename: "SAPIC", + startup: sapic_noop_startup, + shutdown: sapic_noop, + enable: sapic_noop, + disable: sapic_noop, + ack: sapic_noop, + end: sapic_noop, + set_affinity: (void (*)(unsigned int, unsigned long)) sapic_noop +}; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S --- v2.3.99-pre5/linux/arch/ia64/kernel/ivt.S Sat Feb 26 22:31:39 2000 +++ linux/arch/ia64/kernel/ivt.S Fri Apr 21 15:21:24 2000 @@ -5,213 +5,6 @@ * Copyright (C) 1998, 1999 Stephane Eranian * Copyright (C) 1998-2000 David Mosberger */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "entry.h" - -/* - * A couple of convenience macros that make writing and reading - * SAVE_MIN and SAVE_REST easier. - */ -#define rARPR r31 -#define rCRIFS r30 -#define rCRIPSR r29 -#define rCRIIP r28 -#define rARRSC r27 -#define rARPFS r26 -#define rARUNAT r25 -#define rARRNAT r24 -#define rARBSPSTORE r23 -#define rKRBS r22 -#define rB6 r21 -#define rR1 r20 - -/* - * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves - * the minimum state necessary that allows us to turn psr.ic back - * on. - * - * Assumed state upon entry: - * psr.ic: off - * psr.dt: off - * r31: contains saved predicates (pr) - * - * Upon exit, the state is as follows: - * psr.ic: off - * psr.dt: off - * r2 = points to &pt_regs.r16 - * r12 = kernel sp (kernel virtual address) - * r13 = points to current task_struct (kernel virtual address) - * p15 = TRUE if psr.i is set in cr.ipsr - * predicate registers (other than p6, p7, and p15), b6, r3, r8, r9, r10, r11, r14, r15: - * preserved - * - * Note that psr.ic is NOT turned on by this macro. This is so that - * we can pass interruption state as arguments to a handler. - */ -#define DO_SAVE_MIN(COVER,EXTRA) \ - mov rARRSC=ar.rsc; \ - mov rARPFS=ar.pfs; \ - mov rR1=r1; \ - mov rARUNAT=ar.unat; \ - mov rCRIPSR=cr.ipsr; \ - mov rB6=b6; /* rB6 = branch reg 6 */ \ - mov rCRIIP=cr.iip; \ - mov r1=ar.k6; /* r1 = current */ \ - ;; \ - invala; \ - extr.u r16=rCRIPSR,32,2; /* extract psr.cpl */ \ - ;; \ - cmp.eq pKern,p7=r0,r16; /* are we in kernel mode already? (psr.cpl==0) */ \ - /* switch from user to kernel RBS: */ \ - COVER; \ - ;; \ -(p7) mov ar.rsc=r0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ -(p7) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ - ;; \ -(p7) mov rARRNAT=ar.rnat; \ -(pKern) dep r1=0,sp,61,3; /* compute physical addr of sp */ \ -(p7) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(p7) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ -(p7) dep rKRBS=-1,rKRBS,61,3; /* compute kernel virtual addr of RBS */ \ - ;; \ -(pKern) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ -(p7) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ - ;; \ -(p7) mov r18=ar.bsp; \ -(p7) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ - \ - mov r16=r1; /* initialize first base pointer */ \ - adds r17=8,r1; /* initialize second base pointer */ \ - ;; \ - st8 [r16]=rCRIPSR,16; /* save cr.ipsr */ \ - st8 [r17]=rCRIIP,16; /* save cr.iip */ \ -(pKern) mov r18=r0; /* make sure r18 isn't NaT */ \ - ;; \ - st8 [r16]=rCRIFS,16; /* save cr.ifs */ \ - st8 [r17]=rARUNAT,16; /* save ar.unat */ \ -(p7) sub r18=r18,rKRBS; /* r18=RSE.ndirty*8 */ \ - ;; \ - st8 [r16]=rARPFS,16; /* save ar.pfs */ \ - st8 [r17]=rARRSC,16; /* save ar.rsc */ \ - tbit.nz p15,p0=rCRIPSR,IA64_PSR_I_BIT \ - ;; /* avoid RAW on r16 & r17 */ \ -(pKern) adds r16=16,r16; /* skip over ar_rnat field */ \ -(pKern) adds r17=16,r17; /* skip over ar_bspstore field */ \ -(p7) st8 [r16]=rARRNAT,16; /* save ar.rnat */ \ -(p7) st8 [r17]=rARBSPSTORE,16; /* save ar.bspstore */ \ - ;; \ - st8 [r16]=rARPR,16; /* save predicates */ \ - st8 [r17]=rB6,16; /* save b6 */ \ - shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ - ;; \ - st8 [r16]=r18,16; /* save ar.rsc value for "loadrs" */ \ - st8.spill [r17]=rR1,16; /* save original r1 */ \ - cmp.ne pEOI,p0=r0,r0 /* clear pEOI by default */ \ - ;; \ - st8.spill [r16]=r2,16; \ - st8.spill [r17]=r3,16; \ - adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ - ;; \ - st8.spill [r16]=r12,16; \ - st8.spill [r17]=r13,16; \ - cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \ - ;; \ - st8.spill [r16]=r14,16; \ - st8.spill [r17]=r15,16; \ - dep r14=-1,r0,61,3; \ - ;; \ - st8.spill [r16]=r8,16; \ - st8.spill [r17]=r9,16; \ - adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ - ;; \ - st8.spill [r16]=r10,16; \ - st8.spill [r17]=r11,16; \ - mov r13=ar.k6; /* establish `current' */ \ - ;; \ - or r2=r2,r14; /* make first base a kernel virtual address */ \ - EXTRA; \ - movl r1=__gp; /* establish kernel global pointer */ \ - ;; \ - or r12=r12,r14; /* make sp a kernel virtual address */ \ - or r13=r13,r14; /* make `current' a kernel virtual address */ \ - bsw.1;; /* switch back to bank 1 (must be last in insn group) */ - -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC -# define STOPS nop.i 0x0;; nop.i 0x0;; nop.i 0x0;; -#else -# define STOPS -#endif - -#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS -#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS -#define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS - -/* - * SAVE_REST saves the remainder of pt_regs (with psr.ic on). This - * macro guarantees to preserve all predicate registers, r8, r9, r10, - * r11, r14, and r15. - * - * Assumed state upon entry: - * psr.ic: on - * psr.dt: on - * r2: points to &pt_regs.r16 - * r3: points to &pt_regs.r17 - */ -#define SAVE_REST \ - st8.spill [r2]=r16,16; \ - st8.spill [r3]=r17,16; \ - ;; \ - st8.spill [r2]=r18,16; \ - st8.spill [r3]=r19,16; \ - ;; \ - mov r16=ar.ccv; /* M-unit */ \ - movl r18=FPSR_DEFAULT /* L-unit */ \ - ;; \ - mov r17=ar.fpsr; /* M-unit */ \ - mov ar.fpsr=r18; /* M-unit */ \ - ;; \ - st8.spill [r2]=r20,16; \ - st8.spill [r3]=r21,16; \ - mov r18=b0; \ - ;; \ - st8.spill [r2]=r22,16; \ - st8.spill [r3]=r23,16; \ - mov r19=b7; \ - ;; \ - st8.spill [r2]=r24,16; \ - st8.spill [r3]=r25,16; \ - ;; \ - st8.spill [r2]=r26,16; \ - st8.spill [r3]=r27,16; \ - ;; \ - st8.spill [r2]=r28,16; \ - st8.spill [r3]=r29,16; \ - ;; \ - st8.spill [r2]=r30,16; \ - st8.spill [r3]=r31,16; \ - ;; \ - st8 [r2]=r16,16; /* ar.ccv */ \ - st8 [r3]=r17,16; /* ar.fpsr */ \ - ;; \ - st8 [r2]=r18,16; /* b0 */ \ - st8 [r3]=r19,16+8; /* b7 */ \ - ;; \ - stf.spill [r2]=f6,32; \ - stf.spill [r3]=f7,32; \ - ;; \ - stf.spill [r2]=f8,32; \ - stf.spill [r3]=f9,32 - /* * This file defines the interrupt vector table used by the CPU. * It does not include one entry per possible cause of interruption. @@ -236,9 +29,29 @@ * The table is 32KB in size and must be aligned on 32KB boundary. * (The CPU ignores the 15 lower bits of the address) * - * Table is based upon EAS2.4 (June 1998) + * Table is based upon EAS2.6 (Oct 1999) */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MINSTATE_START_SAVE_MIN /* no special action needed */ +#define MINSTATE_END_SAVE_MIN \ + or r2=r2,r14; /* make first base a kernel virtual address */ \ + or r12=r12,r14; /* make sp a kernel virtual address */ \ + or r13=r13,r14; /* make `current' a kernel virtual address */ \ + bsw.1; /* switch back to bank 1 (must be last in insn group) */ \ + ;; + +#include "minstate.h" + #define FAULT(n) \ rsm psr.dt; /* avoid nested faults due to TLB misses... */ \ ;; \ @@ -336,8 +149,8 @@ (p7) tbit.nz.unc p10,p11=r19,32 // is it an instruction TLB miss? dep r17=0,r17,0,PAGE_SHIFT // clear low bits to get page address ;; -(p10) itc.i r18;; // insert the instruction TLB entry (EAS2.6: must be last in insn group!) -(p11) itc.d r18;; // insert the data TLB entry (EAS2.6: must be last in insn group!) +(p10) itc.i r18 // insert the instruction TLB entry +(p11) itc.d r18 // insert the data TLB entry (p6) br.spnt.few page_fault // handle bad address/page not present (page fault) mov cr.ifa=r21 @@ -346,9 +159,9 @@ // the exception deferral bit. adds r16=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r17 ;; -(p7) itc.d r16;; // EAS2.6: must be last in insn group! +(p7) itc.d r16 mov pr=r31,-1 // restore predicate registers - rfi;; // must be last insn in an insn group + rfi .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// @@ -395,11 +208,11 @@ ;; (p7) tbit.z p6,p7=r18,0 // page present bit cleared? ;; -(p7) itc.i r18;; // insert the instruction TLB entry (EAS2.6: must be last in insn group!) +(p7) itc.i r18 // insert the instruction TLB entry (p6) br.spnt.few page_fault // handle bad address/page not present (page fault) ;; mov pr=r31,-1 // restore predicate registers - rfi;; // must be last insn in an insn group + rfi .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// @@ -446,11 +259,11 @@ ;; (p7) tbit.z p6,p7=r18,0 // page present bit cleared? ;; -(p7) itc.d r18;; // insert the instruction TLB entry (EAS2.6: must be last in insn group!) +(p7) itc.d r18 // insert the instruction TLB entry (p6) br.spnt.few page_fault // handle bad address/page not present (page fault) ;; mov pr=r31,-1 // restore predicate registers - rfi;; // must be last insn in an insn group + rfi //----------------------------------------------------------------------------------- // call do_page_fault (predicates are in r31, psr.dt is off, r16 is faulting address) @@ -468,10 +281,9 @@ ;; ssm psr.ic | psr.dt ;; - srlz.d // guarantee that interrupt collection is enabled -(p15) ssm psr.i // restore psr.i + srlz.i // guarantee that interrupt collection is enabled ;; - srlz.i // must precede "alloc"! (srlz.i implies srlz.d) +(p15) ssm psr.i // restore psr.i movl r14=ia64_leave_kernel ;; alloc r15=ar.pfs,0,0,3,0 // must be first in insn group @@ -491,15 +303,15 @@ movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX ;; shr.u r18=r16,57 // move address bit 61 to bit 4 - dep r16=0,r16,52,12 // clear top 12 bits of address + dep r16=0,r16,IA64_PHYS_BITS,(64-IA64_PHYS_BITS) // clear ed, resvd, and unimpl. phys bits ;; andcm r18=0x10,r18 // bit 4=~address-bit(61) dep r16=r17,r16,0,12 // insert PTE control bits into r16 ;; or r16=r16,r18 // set bit 4 (uncached) if the access was to region 6 ;; - itc.i r16;; // insert the TLB entry(EAS2.6: must be last in insn group!) - rfi;; // must be last insn in an insn group + itc.i r16 // insert the TLB entry + rfi .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// @@ -508,15 +320,15 @@ movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW ;; shr.u r18=r16,57 // move address bit 61 to bit 4 - dep r16=0,r16,52,12 // clear top 12 bits of address + dep r16=0,r16,IA64_PHYS_BITS,(64-IA64_PHYS_BITS) // clear ed, resvd, and unimpl. phys bits ;; andcm r18=0x10,r18 // bit 4=~address-bit(61) dep r16=r17,r16,0,12 // insert PTE control bits into r16 ;; or r16=r16,r18 // set bit 4 (uncached) if the access was to region 6 ;; - itc.d r16;; // insert the TLB entry (EAS2.6: must be last in insn group!) - rfi;; // must be last insn in an insn group + itc.d r16 // insert the TLB entry + rfi .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// @@ -609,27 +421,31 @@ mov b0=r29 // restore b0 ;; st8 [r17]=r18 // store back updated PTE - itc.d r18;; // install updated PTE (EAS2.6: must be last in insn group!) - rfi;; // must be last insn in an insn group + itc.d r18 // install updated PTE + rfi .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// // 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) // Like Entry 8, except for instruction access mov r16=cr.ifa // get the address that caused the fault -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +#ifdef CONFIG_ITANIUM + /* + * Erratum 10 (IFA may contain incorrect address) now has + * "NoFix" status. There are no plans for fixing this. + */ + mov r17=cr.ipsr mov r31=pr // save predicates - mov r30=cr.ipsr ;; - extr.u r17=r30,IA64_PSR_IS_BIT,1 // get instruction arch. indicator + mov r18=cr.iip + tbit.z p6,p0=r17,IA64_PSR_IS_BIT // IA64 instruction set? ;; - cmp.eq p6,p0 = r17,r0 // check if IA64 instruction set +(p6) mov r16=r18 // if so, use cr.iip instead of cr.ifa +#if 0 ;; -(p6) mov r16=cr.iip // get real faulting address - ;; -(p6) mov cr.ifa=r16 // reset IFA +#endif mov pr=r31,-1 -#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ +#endif /* CONFIG_ITANIUM */ movl r30=1f // load continuation point in case of nested fault ;; thash r17=r16 // compute virtual address of L3 PTE @@ -641,8 +457,8 @@ mov b0=r29 // restore b0 ;; st8 [r17]=r18 // store back updated PTE - itc.i r18;; // install updated PTE (EAS2.6: must be last in insn group!) - rfi;; // must be last insn in an insn group + itc.i r18 // install updated PTE + rfi .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// @@ -660,8 +476,8 @@ mov b0=r29 // restore b0 ;; st8 [r17]=r18 // store back updated PTE - itc.d r18;; // install updated PTE (EAS2.6: must be last in insn group!) - rfi;; // must be last insn in an insn group + itc.d r18 // install updated PTE + rfi .align 1024 ///////////////////////////////////////////////////////////////////////////////////////// @@ -689,12 +505,11 @@ // turn interrupt collection and data translation back on: ssm psr.ic | psr.dt - srlz.d // guarantee that interrupt collection is enabled + ;; + srlz.i // guarantee that interrupt collection is enabled cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 ;; (p15) ssm psr.i // restore psr.i - ;; - srlz.i // ensure everybody knows psr.ic and psr.dt are back on adds r8=(IA64_PT_REGS_R8_OFFSET-IA64_PT_REGS_R16_OFFSET),r2 ;; stf8 [r8]=f1 // ensure pt_regs.r8 != 0 (see handle_syscall_error) @@ -813,11 +628,10 @@ ;; mov r14=cr.isr ssm psr.ic | psr.dt - srlz.d // guarantee that interrupt collection is enabled ;; -(p15) ssm psr.i + srlz.i // guarantee that interrupt collection is enabled ;; - srlz.d +(p15) ssm psr.i adds r3=8,r2 // Base pointer for SAVE_REST ;; SAVE_REST @@ -858,12 +672,13 @@ ld8 r16=[r16] tbit.z p8,p0=r2,5 // (current->flags & PF_TRACESYS) == 0? ;; - movl r15=ia32_ret_from_syscall mov b6=r16 + movl r15=ia32_ret_from_syscall ;; mov rp=r15 -(p8) br.call.sptk.few b6=b6 - br.call.sptk.few rp=ia32_trace_syscall // rp will be overwritten (ignored) +(p8) br.call.sptk.many b6=b6 + ;; + br.call.sptk.many rp=ia32_trace_syscall // rp will be overwritten (ignored) non_ia32_syscall: alloc r15=ar.pfs,0,0,2,0 @@ -885,13 +700,6 @@ FAULT(17) non_syscall: - -#ifdef CONFIG_KDB - mov r17=__IA64_BREAK_KDB - ;; - cmp.eq p8,p0=r16,r17 // is this a kernel breakpoint? -#endif - SAVE_MIN_WITH_COVER // There is no particular reason for this code to be here, other than that @@ -904,11 +712,10 @@ // turn interrupt collection and data translation back on: ssm psr.ic | psr.dt - srlz.d // guarantee that interrupt collection is enabled ;; -(p15) ssm psr.i // restore psr.i + srlz.i // guarantee that interrupt collection is enabled ;; - srlz.i // ensure everybody knows psr.ic and psr.dt are back on +(p15) ssm psr.i // restore psr.i movl r15=ia64_leave_kernel ;; alloc r14=ar.pfs,0,0,2,0 @@ -918,9 +725,6 @@ SAVE_REST mov rp=r15 ;; -#ifdef CONFIG_KDB -(p8) br.call.sptk.few b6=ia64_invoke_kdb -#endif br.call.sptk.few b6=ia64_bad_break // avoid WAW on CFM and ignore return addr .align 1024 @@ -945,11 +749,10 @@ // mov r15=cr.ifa ssm psr.ic | psr.dt - srlz.d // guarantee that interrupt collection is enabled ;; -(p15) ssm psr.i // restore psr.i + srlz.i // guarantee that interrupt collection is enabled ;; - srlz.i +(p15) ssm psr.i // restore psr.i adds r3=8,r2 // set up second base pointer ;; SAVE_REST @@ -994,13 +797,12 @@ mov r11=cr.itir ;; ssm psr.ic | psr.dt - srlz.d // guarantee that interrupt collection is enabled + ;; + srlz.i // guarantee that interrupt collection is enabled ;; (p15) ssm psr.i // restore psr.i adds r3=8,r2 // set up second base pointer for SAVE_REST ;; - srlz.i // must precede "alloc"! - ;; alloc r14=ar.pfs,0,0,5,0 // must be first in insn group mov out0=r15 mov out1=r8 @@ -1012,11 +814,7 @@ movl r14=ia64_leave_kernel ;; mov rp=r14 -#ifdef CONFIG_KDB - br.call.sptk.few b6=ia64_invoke_kdb_fault_handler -#else br.call.sptk.few b6=ia64_fault -#endif // // --- End of long entries, Beginning of short entries // @@ -1121,7 +919,7 @@ mov cr.ipsr=r16 ;; - rfi;; // and go back (must be last insn in group) + rfi // and go back .align 256 ///////////////////////////////////////////////////////////////////////////////////////// @@ -1142,11 +940,7 @@ ;; srlz.d // ensure everyone knows psr.dt is off mov r19=30 // error vector for fault_handler (when kernel) - extr.u r16=r16,32,2 // extract psr.cpl - ;; - cmp.eq p6,p7=r0,r16 // if kernel cpl then fault else emulate -(p7) br.cond.sptk.many dispatch_unaligned_handler -(p6) br.cond.sptk.many dispatch_to_fault_handler + br.cond.sptk.many dispatch_unaligned_handler .align 256 ///////////////////////////////////////////////////////////////////////////////////////// @@ -1226,6 +1020,31 @@ .align 256 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71) +#ifdef CONFIG_IA32_SUPPORT + rsm psr.dt + ;; + srlz.d + mov r31=pr + mov r16=cr.isr + ;; + extr.u r17=r16,16,8 // get ISR.code + mov r18=ar.eflag + mov r19=cr.iim // old eflag value + ;; + cmp.ne p2,p0=2,r17 +(p2) br.cond.spnt 1f // not a system flag fault + xor r16=r18,r19 + ;; + extr.u r17=r16,18,1 // get the eflags.ac bit + ;; + cmp.eq p2,p0=0,r17 +(p2) br.cond.spnt 1f // eflags.ac bit didn't change + ;; + mov pr=r31,-1 // restore predicate registers + rfi + +1: +#endif // CONFIG_IA32_SUPPORT FAULT(46) .align 256 diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/mca.c linux/arch/ia64/kernel/mca.c --- v2.3.99-pre5/linux/arch/ia64/kernel/mca.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/mca.c Fri Apr 21 16:37:25 2000 @@ -2,21 +2,37 @@ * File: mca.c * Purpose: Generic MCA handling layer * + * Updated for latest kernel + * Copyright (C) 2000 Intel + * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com) + * * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) + * + * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, + * added min save state dump, added INIT handler. */ #include #include #include +#include +#include +#include + #include #include #include #include #include -#include + #include #include + +typedef struct ia64_fptr { + unsigned long fp; + unsigned long gp; +} ia64_fptr_t; ia64_mc_info_t ia64_mc_info; ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; @@ -25,6 +41,11 @@ u64 ia64_mca_stack[1024]; u64 ia64_mca_stackframe[32]; u64 ia64_mca_bspstore[1024]; +u64 ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16))); + +#if defined(SAL_MPINIT_WORKAROUND) && !defined(CONFIG_SMP) +int bootstrap_processor = -1; +#endif static void ia64_mca_cmc_vector_setup(int enable, int_vector_t cmc_vector); @@ -34,8 +55,99 @@ static void ia64_log_init(int,int); static void ia64_log_get(int,int, prfunc_t); static void ia64_log_clear(int,int,int, prfunc_t); +extern void ia64_monarch_init_handler (void); +extern void ia64_slave_init_handler (void); + +/* + * hack for now, add platform dependent handlers + * here + */ +#ifndef PLATFORM_MCA_HANDLERS +void +mca_handler_platform (void) +{ + +} + +void +cmci_handler_platform (int cmc_irq, void *arg, struct pt_regs *ptregs) +{ + +} +/* + * This routine will be used to deal with platform specific handling + * of the init, i.e. drop into the kernel debugger on server machine, + * or if the processor is part of some parallel machine without a + * console, then we would call the appropriate debug hooks here. + */ +void +init_handler_platform (struct pt_regs *regs) +{ + /* if a kernel debugger is available call it here else just dump the registers */ + show_regs(regs); /* dump the state info */ +} + +void +log_print_platform ( void *cur_buff_ptr, prfunc_t prfunc) +{ +} + +void +ia64_mca_init_platform (void) +{ +} + +#endif /* PLATFORM_MCA_HANDLERS */ + +static char *min_state_labels[] = { + "nat", + "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", + "r9", "r10","r11", "r12","r13","r14", "r15", + "b0r16","b0r17", "b0r18", "b0r19", "b0r20", + "b0r21", "b0r22","b0r23", "b0r24", "b0r25", + "b0r26", "b0r27", "b0r28","b0r29", "b0r30", "b0r31", + "r16", "r17", "r18","r19", "r20", "r21","r22", + "r23", "r24","r25", "r26", "r27","r28", "r29", "r30","r31", + "preds", "br0", "rsc", + "iip", "ipsr", "ifs", + "xip", "xpsr", "xfs" +}; + +int ia64_pmss_dump_bank0=0; /* dump bank 0 ? */ /* + * routine to process and prepare to dump min_state_save + * information for debugging purposes. + * + */ +void +ia64_process_min_state_save (pal_min_state_area_t *pmss, struct pt_regs *ptregs) +{ + int i, max=57; + u64 *tpmss_ptr=(u64 *)pmss; + + /* dump out the min_state_area information */ + + for (i=0;ifp); ia64_mc_info.imi_monarch_init_handler_size = IA64_INIT_HANDLER_SIZE; - ia64_mc_info.imi_slave_init_handler = __pa(ia64_slave_init_handler); + ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); ia64_mc_info.imi_slave_init_handler_size = IA64_INIT_HANDLER_SIZE; + + 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 (ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, ia64_mc_info.imi_monarch_init_handler, @@ -173,7 +297,7 @@ return; - MCA_DEBUG("mca_init : registered os init handler with SAL\n"); + IA64_MCA_DEBUG("ia64_mca_init : registered os init handler with SAL\n"); /* Initialize the areas set aside by the OS to buffer the * platform/processor error states for MCA/INIT/CMC @@ -186,9 +310,9 @@ ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR); ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM); - mca_init_platform(); + ia64_mca_init_platform(); - MCA_DEBUG("mca_init : platform-specific mca handling setup done\n"); + IA64_MCA_DEBUG("ia64_mca_init : platform-specific mca handling setup done\n"); #if defined(MCA_TEST) mca_test(); @@ -244,7 +368,7 @@ void ia64_mca_wakeup(int cpu) { - ipi_send(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT); + ipi_send(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT, 0); ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; } @@ -396,25 +520,6 @@ ia64_return_to_sal_check(); } -/* - * SAL to OS entry point for INIT on the monarch processor - * This has been defined for registration purposes with SAL - * as a part of mca_init. - */ -void -ia64_monarch_init_handler() -{ -} -/* - * SAL to OS entry point for INIT on the slave processor - * This has been defined for registration purposes with SAL - * as a part of mca_init. - */ - -void -ia64_slave_init_handler() -{ -} /* * ia64_mca_cmc_int_handler * This is correctable machine check interrupt handler. @@ -450,10 +555,9 @@ #define IA64_MAX_LOG_SUBTYPES 2 /* Processor, Platform */ typedef struct ia64_state_log_s { - spinlock_t isl_lock; - int isl_index; - sal_log_header_t isl_log[IA64_MAX_LOGS]; - + spinlock_t isl_lock; + int isl_index; + ia64_psilog_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][IA64_MAX_LOG_SUBTYPES]; @@ -472,6 +576,53 @@ #define IA64_LOG_CURR_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)])) /* + * C portion of the OS INIT handler + * + * Called from ia64__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 retrun to interrupted context using PAL_MC_RESUME + * + */ + +void +ia64_init_handler (struct pt_regs *regs) +{ + sal_log_processor_info_t *proc_ptr; + ia64_psilog_t *plog_ptr; + + printk("Entered OS INIT handler\n"); + + /* Get the INIT processor log */ + ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); + /* Get the INIT platform log */ + ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); + +#ifdef IA64_DUMP_ALL_PROC_INFO + ia64_log_print(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); +#endif + + /* + * get pointer to min state save area + * + */ + plog_ptr=(ia64_psilog_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT, + SAL_SUB_INFO_TYPE_PROCESSOR); + proc_ptr = &plog_ptr->devlog.proclog; + + ia64_process_min_state_save(&proc_ptr->slpi_min_state_area,regs); + + init_handler_platform(regs); /* call platform specific routines */ + + /* Clear the INIT SAL logs now that they have been saved in the OS buffer */ + ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR); + ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM); +} + +/* * ia64_log_init * Reset the OS ia64 log buffer * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) @@ -484,7 +635,7 @@ IA64_LOG_LOCK_INIT(sal_info_type, sal_sub_info_type); IA64_LOG_NEXT_INDEX(sal_info_type, sal_sub_info_type) = 0; memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0, - sizeof(sal_log_header_t) * IA64_MAX_LOGS); + sizeof(ia64_psilog_t) * IA64_MAX_LOGS); } /* @@ -499,7 +650,7 @@ ia64_log_get(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc) { sal_log_header_t *log_buffer; - int s; + int s,total_len=0; IA64_LOG_LOCK(sal_info_type, sal_sub_info_type); @@ -507,9 +658,11 @@ /* Get the process state information */ log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type); - if (ia64_sal_get_state_info(sal_info_type, sal_sub_info_type ,(u64 *)log_buffer)) + if (!(total_len=ia64_sal_get_state_info(sal_info_type, sal_sub_info_type ,(u64 *)log_buffer))) prfunc("ia64_mca_log_get : Getting processor log failed\n"); + IA64_MCA_DEBUG("ia64_log_get: retrieved %d bytes of error information\n",total_len); + IA64_LOG_INDEX_INC(sal_info_type, sal_sub_info_type); IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type); @@ -542,7 +695,7 @@ /* Get the process state information */ log_buffer = IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type); - memset(log_buffer, 0, sizeof(sal_log_header_t)); + memset(log_buffer, 0, sizeof(ia64_psilog_t)); IA64_LOG_INDEX_DEC(sal_info_type, sal_sub_info_type); @@ -731,11 +884,7 @@ if (lh->slh_log_type != SAL_SUB_INFO_TYPE_PROCESSOR) return; -#if defined(MCA_TEST) - slpi = &slpi_buf; -#else - slpi = (sal_log_processor_info_t *)lh->slh_log_dev_spec_info; -#endif /#if defined(MCA_TEST) */ + slpi = (sal_log_processor_info_t *)((char *)lh+sizeof(sal_log_header_t)); /* point to proc info */ if (!slpi) { prfunc("No Processor Error Log found\n"); @@ -761,14 +910,6 @@ /* Print floating-point register contents if valid */ if (slpi->slpi_valid.slpi_fr) ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr", - prfunc); - - /* Print bank1-gr NAT register contents if valid */ - ia64_log_processor_regs_print(&slpi->slpi_bank1_nat_bits, 1, "NAT", "nat", prfunc); - - /* Print bank 1 register contents if valid */ - if (slpi->slpi_valid.slpi_bank1_gr) - ia64_log_processor_regs_print(slpi->slpi_bank1_gr, 16, "Bank1-General", "gr", prfunc); /* Print the cache check information if any*/ diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/mca_asm.S linux/arch/ia64/kernel/mca_asm.S --- v2.3.99-pre5/linux/arch/ia64/kernel/mca_asm.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/mca_asm.S Fri Apr 21 15:21:24 2000 @@ -1,7 +1,31 @@ +// +// assembly portion of the IA64 MCA handling +// +// Mods by cfleck to integrate into kernel build +// 00/03/15 davidm Added various stop bits to get a clean compile +// 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp kstack, +// switch modes, jump to C INIT handler +// +#include +#include #include -#include -#include +#include #include + +/* + * When we get an machine check, the kernel stack pointer is no longer + * valid, so we need to set a new stack pointer. + */ +#define MINSTATE_START_SAVE_MIN \ +(pKern) movl sp=ia64_init_stack+IA64_STK_OFFSET-IA64_PT_REGS_SIZE; \ + ;; + +#define MINSTATE_END_SAVE_MIN \ + or r12=r12,r14; /* make sp a kernel virtual address */ \ + or r13=r13,r14; /* make `current' a kernel virtual address */ \ + ;; + +#include "minstate.h" .psr abi64 .psr lsb @@ -54,7 +78,9 @@ 100: (p) mov temp=ip; \ ;; \ (p) adds temp=to_label-100b,temp;\ + ;; \ (p) adds temp=adjust,temp; \ + ;; \ (p) mov b1=temp ; \ (p) br b1 @@ -68,6 +94,7 @@ .global ia64_mca_stack .global ia64_mca_stackframe .global ia64_mca_bspstore + .global ia64_init_stack .text .align 16 @@ -341,6 +368,7 @@ mov r3=ar16 // ar.rsc mov ar16=r0 // put RSE in enforced lazy mode mov r5=ar17 // ar.bsp + ;; mov r7=ar18;; // ar.bspstore st8 [r2]=r3,3*8 st8 [r4]=r5,3*8 @@ -575,6 +603,7 @@ // mov ar16=r3 // ar.rsc // mov ar17=r5 // ar.bsp is read only mov ar16=r0 // make sure that RSE is in enforced lazy mode + ;; mov ar18=r7;; // ar.bspstore ld8 r9=[r2],8*13;; @@ -619,3 +648,146 @@ BRANCH(ia64_os_mca_done_restore, r2, p0, -0x20) ;; //EndStub////////////////////////////////////////////////////////////////////// + +// ok, the issue here is that we need to save state information so +// it can be useable by the kernel debugger and show regs routines. +// In order to do this, our best bet is save the current state (plus +// the state information obtain from the MIN_STATE_AREA) into a pt_regs +// format. This way we can pass it on in a useable format. +// + +// +// SAL to OS entry point for INIT on the monarch processor +// This has been defined for registration purposes with SAL +// as a part of ia64_mca_init. +// +// When we get here, the follow registers have been +// set by the SAL for our use +// +// 1. GR1 = OS INIT GP +// 2. GR8 = PAL_PROC physical address +// 3. GR9 = SAL_PROC physical address +// 4. GR10 = SAL GP (physical) +// 5. GR11 = Init Reason +// 0 = Received INIT for event other than crash dump switch +// 1 = Received wakeup at the end of an OS_MCA corrected machine check +// 2 = Received INIT dude to CrashDump switch assertion +// +// 6. GR12 = Return address to location within SAL_INIT procedure + + + .text + .align 16 +.global ia64_monarch_init_handler +.proc ia64_monarch_init_handler +ia64_monarch_init_handler: + +#if defined(SAL_MPINIT_WORKAROUND) + // + // work around SAL bug that sends all processors to monarch entry + // + .global bootstrap_processor + + movl r21=24 + movl r20=16 + mov r17=cr.lid + movl r18=bootstrap_processor + ;; + dep r18=0,r18,61,3 // convert bsp to physical address + ;; + shr r19=r17,r20 + shr r22=r17,r21 + ld4 r18=[r18] // get the BSP ID + ;; + and r19=0xf, r19 + and r22=0xf, r22 + ;; + shl r19=r19,8 // get them in the right order + ;; + or r22=r22,r19 // combine EID and LID + ;; + cmp.eq p6,p7=r22,r18 // Am I the BSP ? +(p7) br.cond.spnt slave_init_spin_me + ;; +#endif + + +// +// ok, the first thing we do is stash the information +// the SAL passed to os +// +_tmp = r2 + movl _tmp=ia64_sal_to_os_handoff_state + ;; + dep _tmp=0,_tmp, 61, 3 // get physical address + ;; + st8 [_tmp]=r1,0x08;; + st8 [_tmp]=r8,0x08;; + st8 [_tmp]=r9,0x08;; + st8 [_tmp]=r10,0x08;; + st8 [_tmp]=r11,0x08;; + st8 [_tmp]=r12,0x08;; + +// now we want to save information so we can dump registers + SAVE_MIN_WITH_COVER + ;; + mov r8=cr.ifa + mov r9=cr.isr + adds r3=8,r2 // set up second base pointer + ;; + SAVE_REST + +// ok, enough should be saved at this point to be dangerous, and supply +// information for a dump +// We need to switch to Virtual mode before hitting the C functions. +// +// +// + movl r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN + mov r3=psr // get the current psr, minimum enabled at this point + ;; + or r2=r2,r3 + ;; + movl r3=IVirtual_Switch + ;; + mov cr.iip=r3 // short return to set the appropriate bits + mov cr.ipsr=r2 // need to do an rfi to set appropriate bits + ;; + rfi + ;; +IVirtual_Switch: + // + // We should now be running virtual + // + // Lets call the C handler to get the rest of the state info + // + alloc r14=ar.pfs,0,0,1,0 // now it's safe (must be first in insn group!) + ;; // + adds out0=16,sp // out0 = pointer to pt_regs + ;; + + br.call.sptk.few rp=ia64_init_handler + ;; + +return_from_init: + br.sptk return_from_init + + .endp + +// +// SAL to OS entry point for INIT on the slave processor +// This has been defined for registration purposes with SAL +// as a part of ia64_mca_init. +// + + .text + .align 16 +.global ia64_slave_init_handler +.proc ia64_slave_init_handler +ia64_slave_init_handler: + + +slave_init_spin_me: + br.sptk slave_init_spin_me + ;; + .endp diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/minstate.h linux/arch/ia64/kernel/minstate.h --- v2.3.99-pre5/linux/arch/ia64/kernel/minstate.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/minstate.h Fri Apr 21 15:21:24 2000 @@ -0,0 +1,205 @@ +#include + +#include "entry.h" + +/* + * A couple of convenience macros that make writing and reading + * SAVE_MIN and SAVE_REST easier. + */ +#define rARPR r31 +#define rCRIFS r30 +#define rCRIPSR r29 +#define rCRIIP r28 +#define rARRSC r27 +#define rARPFS r26 +#define rARUNAT r25 +#define rARRNAT r24 +#define rARBSPSTORE r23 +#define rKRBS r22 +#define rB6 r21 +#define rR1 r20 + +/* + * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves + * the minimum state necessary that allows us to turn psr.ic back + * on. + * + * Assumed state upon entry: + * psr.ic: off + * psr.dt: off + * r31: contains saved predicates (pr) + * + * Upon exit, the state is as follows: + * psr.ic: off + * psr.dt: off + * r2 = points to &pt_regs.r16 + * r12 = kernel sp (kernel virtual address) + * r13 = points to current task_struct (kernel virtual address) + * p15 = TRUE if psr.i is set in cr.ipsr + * predicate registers (other than p6, p7, and p15), b6, r3, r8, r9, r10, r11, r14, r15: + * preserved + * + * Note that psr.ic is NOT turned on by this macro. This is so that + * we can pass interruption state as arguments to a handler. + */ +#define DO_SAVE_MIN(COVER,EXTRA) \ + mov rARRSC=ar.rsc; \ + mov rARPFS=ar.pfs; \ + mov rR1=r1; \ + mov rARUNAT=ar.unat; \ + mov rCRIPSR=cr.ipsr; \ + mov rB6=b6; /* rB6 = branch reg 6 */ \ + mov rCRIIP=cr.iip; \ + mov r1=ar.k6; /* r1 = current */ \ + ;; \ + invala; \ + extr.u r16=rCRIPSR,32,2; /* extract psr.cpl */ \ + ;; \ + cmp.eq pKern,p7=r0,r16; /* are we in kernel mode already? (psr.cpl==0) */ \ + /* switch from user to kernel RBS: */ \ + COVER; \ + ;; \ + MINSTATE_START_SAVE_MIN \ +(p7) mov ar.rsc=r0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ +(p7) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ + ;; \ +(p7) mov rARRNAT=ar.rnat; \ +(pKern) dep r1=0,sp,61,3; /* compute physical addr of sp */ \ +(p7) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ +(p7) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ +(p7) dep rKRBS=-1,rKRBS,61,3; /* compute kernel virtual addr of RBS */ \ + ;; \ +(pKern) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ +(p7) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ + ;; \ +(p7) mov r18=ar.bsp; \ +(p7) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ + \ + mov r16=r1; /* initialize first base pointer */ \ + adds r17=8,r1; /* initialize second base pointer */ \ + ;; \ + st8 [r16]=rCRIPSR,16; /* save cr.ipsr */ \ + st8 [r17]=rCRIIP,16; /* save cr.iip */ \ +(pKern) mov r18=r0; /* make sure r18 isn't NaT */ \ + ;; \ + st8 [r16]=rCRIFS,16; /* save cr.ifs */ \ + st8 [r17]=rARUNAT,16; /* save ar.unat */ \ +(p7) sub r18=r18,rKRBS; /* r18=RSE.ndirty*8 */ \ + ;; \ + st8 [r16]=rARPFS,16; /* save ar.pfs */ \ + st8 [r17]=rARRSC,16; /* save ar.rsc */ \ + tbit.nz p15,p0=rCRIPSR,IA64_PSR_I_BIT \ + ;; /* avoid RAW on r16 & r17 */ \ +(pKern) adds r16=16,r16; /* skip over ar_rnat field */ \ +(pKern) adds r17=16,r17; /* skip over ar_bspstore field */ \ +(p7) st8 [r16]=rARRNAT,16; /* save ar.rnat */ \ +(p7) st8 [r17]=rARBSPSTORE,16; /* save ar.bspstore */ \ + ;; \ + st8 [r16]=rARPR,16; /* save predicates */ \ + st8 [r17]=rB6,16; /* save b6 */ \ + shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ + ;; \ + st8 [r16]=r18,16; /* save ar.rsc value for "loadrs" */ \ + st8.spill [r17]=rR1,16; /* save original r1 */ \ + cmp.ne pEOI,p0=r0,r0 /* clear pEOI by default */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r2,16; \ +.mem.offset 8,0; st8.spill [r17]=r3,16; \ + adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r12,16; \ +.mem.offset 8,0; st8.spill [r17]=r13,16; \ + cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r14,16; \ +.mem.offset 8,0; st8.spill [r17]=r15,16; \ + dep r14=-1,r0,61,3; \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r8,16; \ +.mem.offset 8,0; st8.spill [r17]=r9,16; \ + adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r10,16; \ +.mem.offset 8,0; st8.spill [r17]=r11,16; \ + mov r13=ar.k6; /* establish `current' */ \ + ;; \ + EXTRA; \ + movl r1=__gp; /* establish kernel global pointer */ \ + ;; \ + MINSTATE_END_SAVE_MIN + +/* + * SAVE_REST saves the remainder of pt_regs (with psr.ic on). This + * macro guarantees to preserve all predicate registers, r8, r9, r10, + * r11, r14, and r15. + * + * Assumed state upon entry: + * psr.ic: on + * psr.dt: on + * r2: points to &pt_regs.r16 + * r3: points to &pt_regs.r17 + */ +#define SAVE_REST \ +.mem.offset 0,0; st8.spill [r2]=r16,16; \ +.mem.offset 8,0; st8.spill [r3]=r17,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r18,16; \ +.mem.offset 8,0; st8.spill [r3]=r19,16; \ + ;; \ + mov r16=ar.ccv; /* M-unit */ \ + movl r18=FPSR_DEFAULT /* L-unit */ \ + ;; \ + mov r17=ar.fpsr; /* M-unit */ \ + mov ar.fpsr=r18; /* M-unit */ \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r20,16; \ +.mem.offset 8,0; st8.spill [r3]=r21,16; \ + mov r18=b0; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r22,16; \ +.mem.offset 8,0; st8.spill [r3]=r23,16; \ + mov r19=b7; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r24,16; \ +.mem.offset 8,0; st8.spill [r3]=r25,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r26,16; \ +.mem.offset 8,0; st8.spill [r3]=r27,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r28,16; \ +.mem.offset 8,0; st8.spill [r3]=r29,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r30,16; \ +.mem.offset 8,0; st8.spill [r3]=r31,16; \ + ;; \ + st8 [r2]=r16,16; /* ar.ccv */ \ + st8 [r3]=r17,16; /* ar.fpsr */ \ + ;; \ + st8 [r2]=r18,16; /* b0 */ \ + st8 [r3]=r19,16+8; /* b7 */ \ + ;; \ + stf.spill [r2]=f6,32; \ + stf.spill [r3]=f7,32; \ + ;; \ + stf.spill [r2]=f8,32; \ + stf.spill [r3]=f9,32 + +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +# define STOPS nop.i 0x0;; nop.i 0x0;; nop.i 0x0;; +#else +# define STOPS +#endif + +#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS +#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS +#define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS + +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +# define STOPS nop.i 0x0;; nop.i 0x0;; nop.i 0x0;; +#else +# define STOPS +#endif + +#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS +#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS +#define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c --- v2.3.99-pre5/linux/arch/ia64/kernel/ptrace.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/ptrace.c Fri Apr 21 15:21:24 2000 @@ -23,6 +23,16 @@ #include /* + * Bits in the PSR that we allow ptrace() to change: + * be, up, ac, mfl, mfh (the user mask; five bits total) + * db (debug breakpoint fault; one bit) + * id (instruction debug fault disable; one bit) + * dd (data debug fault disable; one bit) + * ri (restart instruction; two bits) + */ +#define CR_IPSR_CHANGE_MASK 0x06a00100003eUL + +/* * Collect the NaT bits for r1-r31 from sw->caller_unat and * sw->ar_unat and return a NaT bitset where bit i is set iff the NaT * bit of register i is set. @@ -352,6 +362,94 @@ } /* + * Synchronize (i.e, write) the RSE backing store living in kernel + * space to the VM of the indicated child process. + * + * If new_bsp is non-zero, the bsp will (effectively) be updated to + * the new value upon resumption of the child process. This is + * accomplished by setting the loadrs value to zero and the bspstore + * value to the new bsp value. + * + * When new_bsp and force_loadrs_to_zero are both 0, the register + * backing store in kernel space is written to user space and the + * loadrs and bspstore values are left alone. + * + * When new_bsp is zero and force_loadrs_to_zero is 1 (non-zero), + * loadrs is set to 0, and the bspstore value is set to the old bsp + * value. This will cause the stacked registers (r32 and up) to be + * obtained entirely from the the child's memory space rather than + * from the kernel. (This makes it easier to write code for + * modifying the stacked registers in multi-threaded programs.) + * + * Note: I had originally written this function without the + * force_loadrs_to_zero parameter; it was written so that loadrs would + * always be set to zero. But I had problems with certain system + * calls apparently causing a portion of the RBS to be zeroed. (I + * still don't understand why this was happening.) Anyway, it'd + * definitely less intrusive to leave loadrs and bspstore alone if + * possible. + */ +static long +sync_kernel_register_backing_store (struct task_struct *child, + long new_bsp, + int force_loadrs_to_zero) +{ + unsigned long *krbs, bspstore, bsp, krbs_num_regs, rbs_end, addr, val; + long ndirty, ret; + struct pt_regs *child_regs; + struct switch_stack *child_stack; + + ret = 0; + child_regs = ia64_task_regs(child); + child_stack = (struct switch_stack *) child_regs - 1; + + krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; + ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19)); + bspstore = child_regs->ar_bspstore; + bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty); + krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore); + rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, krbs_num_regs); + + /* Return early if nothing to do */ + if (bsp == new_bsp) + return 0; + + /* Write portion of backing store living on kernel stack to the child's VM. */ + for (addr = bspstore; addr < rbs_end; addr += 8) { + ret = ia64_peek(child_regs, child, addr, &val); + if (ret != 0) + return ret; + if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val)) + return -EIO; + } + + if (new_bsp != 0) { + force_loadrs_to_zero = 1; + bsp = new_bsp; + } + + if (force_loadrs_to_zero) { + child_regs->loadrs = 0; + child_regs->ar_bspstore = bsp; + } + + return ret; +} + +static void +sync_thread_rbs (struct task_struct *child, int make_writable) +{ + struct task_struct *p; + read_lock(&tasklist_lock); + for_each_task(p) { + if (p->mm == child->mm && p->state != TASK_RUNNING) + sync_kernel_register_backing_store(p, 0, make_writable); + } + read_unlock(&tasklist_lock); + child->thread.flags |= IA64_THREAD_KRBS_SYNCED; +} + +/* * Ensure the state in child->thread.fph is up-to-date. */ static void @@ -375,8 +473,8 @@ struct switch_stack *child_stack; struct pt_regs *child_regs; struct task_struct *child; - unsigned long flags, *base; - long ret, regnum; + unsigned long flags, regnum, *base; + long ret; lock_kernel(); ret = -EPERM; @@ -441,6 +539,9 @@ switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr */ + if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED) + && atomic_read(&child->mm->mm_users) > 1) + sync_thread_rbs(child, 0); ret = ia64_peek(regs, child, addr, &data); if (ret == 0) { ret = data; @@ -450,6 +551,9 @@ case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ + if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED) + && atomic_read(&child->mm->mm_users) > 1) + sync_thread_rbs(child, 1); ret = ia64_poke(regs, child, addr, data); goto out; @@ -477,8 +581,35 @@ bspstore = (unsigned long *) child_regs->ar_bspstore; ndirty = ia64_rse_num_regs(rbs, rbs + (ret >> 19)); ret = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); + + /* + * If we're in a system call, no ``cover'' was done. So + * to make things uniform, we'll add the appropriate + * displacement onto bsp if we're in a system call. + * + * Note: It may be better to leave the system call case + * alone and subtract the amount of the cover for the + * non-syscall case. That way the reported bsp value + * would actually be the correct bsp for the child + * process. + */ + if (!(child_regs->cr_ifs & (1UL << 63))) { + ret = (unsigned long) + ia64_rse_skip_regs((unsigned long *) ret, + child_stack->ar_pfs & 0x7f); + } + } else if (addr == PT_CFM) { + /* ret currently contains pt_regs.cr_ifs */ + if ((ret & (1UL << 63)) == 0) + ret = child_stack->ar_pfs; + ret &= 0x3fffffffffUL; /* return only the CFM */ } } else { + if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { + child->thread.flags |= IA64_THREAD_DBG_VALID; + memset(child->thread.dbr, 0, sizeof child->thread.dbr); + memset(child->thread.ibr, 0, sizeof child->thread.ibr); + } if (addr >= PT_IBR) { regnum = (addr - PT_IBR) >> 3; base = &child->thread.ibr[0]; @@ -488,7 +619,7 @@ } if (regnum >= 8) goto out; - data = base[regnum]; + ret = base[regnum]; } regs->r8 = 0; /* ensure "ret" is not mistaken as an error code */ goto out; @@ -503,29 +634,47 @@ sync_fph(child); addr += (unsigned long) &child->thread.fph; *(unsigned long *) addr = data; - if (ret < 0) - goto out; + } else if (addr == PT_AR_BSPSTORE || addr == PT_CALLER_UNAT + || addr == PT_KERNEL_FPSR || addr == PT_K_B0 || addr == PT_K_AR_PFS + || (PT_K_AR_UNAT <= addr && addr <= PT_K_PR)) { + /* + * Don't permit changes to certain registers. + * + * We don't allow bspstore to be modified because doing + * so would mess up any modifications to bsp. (See + * sync_kernel_register_backing_store for the details.) + */ + goto out; + } else if (addr == PT_AR_BSP) { + /* FIXME? Account for lack of ``cover'' in the syscall case */ + ret = sync_kernel_register_backing_store(child, data, 1); + goto out; + } else if (addr == PT_CFM) { + child_regs = ia64_task_regs(child); + child_stack = (struct switch_stack *) child_regs - 1; + + if (child_regs->cr_ifs & (1UL << 63)) { + child_regs->cr_ifs = (child_regs->cr_ifs & ~0x3fffffffffUL) + | (data & 0x3fffffffffUL); + } else { + child_stack->ar_pfs = (child_stack->ar_pfs & ~0x3fffffffffUL) + | (data & 0x3fffffffffUL); + } } else if (addr < PT_F9+16) { /* accessing switch_stack or pt_regs */ child_regs = ia64_task_regs(child); child_stack = (struct switch_stack *) child_regs - 1; - if (addr == PT_AR_BSP) { - /* compute the loadrs value based on bsp and bspstore: */ - unsigned long *rbs, *bspstore, ndirty, *kbsp; - - bspstore = (unsigned long *) child_regs->ar_bspstore; - ndirty = ia64_rse_num_regs(bspstore, (unsigned long *) data); - rbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - kbsp = ia64_rse_skip_regs(rbs, ndirty); - data = (kbsp - rbs) << 19; - } + if (addr == PT_CR_IPSR) + data = (data & CR_IPSR_CHANGE_MASK) + | (child_regs->cr_ipsr & ~CR_IPSR_CHANGE_MASK); + *(unsigned long *) ((long) child_stack + addr - PT_CALLER_UNAT) = data; } else { if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { child->thread.flags |= IA64_THREAD_DBG_VALID; - memset(current->thread.dbr, 0, sizeof current->thread.dbr); - memset(current->thread.ibr, 0, sizeof current->thread.ibr); + memset(child->thread.dbr, 0, sizeof child->thread.dbr); + memset(child->thread.ibr, 0, sizeof child->thread.ibr); } if (addr >= PT_IBR) { @@ -538,7 +687,7 @@ if (regnum >= 8) goto out; if (regnum & 1) { - /* force breakpoint to be effective a most for user-level: */ + /* force breakpoint to be effective only for user-level: */ data &= ~(0x7UL << 56); } base[regnum] = data; @@ -546,6 +695,23 @@ ret = 0; goto out; + case PTRACE_GETSIGINFO: + ret = -EIO; + if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t)) + || child->thread.siginfo == 0) + goto out; + copy_to_user((siginfo_t *) data, child->thread.siginfo, sizeof (siginfo_t)); + ret = 0; + goto out; + break; + case PTRACE_SETSIGINFO: + ret = -EIO; + if (!access_ok(VERIFY_READ, data, sizeof (siginfo_t)) + || child->thread.siginfo == 0) + goto out; + copy_from_user(child->thread.siginfo, (siginfo_t *) data, sizeof (siginfo_t)); + ret = 0; + goto out; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; @@ -561,6 +727,9 @@ ia64_psr(ia64_task_regs(child))->ss = 0; ia64_psr(ia64_task_regs(child))->tb = 0; + /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ + child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; + wake_up_process(child); ret = 0; goto out; @@ -579,6 +748,9 @@ ia64_psr(ia64_task_regs(child))->ss = 0; ia64_psr(ia64_task_regs(child))->tb = 0; + /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ + child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; + wake_up_process(child); ret = 0; goto out; @@ -597,6 +769,9 @@ } child->exit_code = data; + /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ + child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; + /* give it a chance to run. */ wake_up_process(child); ret = 0; @@ -618,6 +793,9 @@ /* make sure the single step/take-branch tra bits are not set: */ ia64_psr(ia64_task_regs(child))->ss = 0; ia64_psr(ia64_task_regs(child))->tb = 0; + + /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ + child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; wake_up_process(child); ret = 0; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/sal.c linux/arch/ia64/kernel/sal.c --- v2.3.99-pre5/linux/arch/ia64/kernel/sal.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/sal.c Fri Apr 21 15:21:24 2000 @@ -139,7 +139,7 @@ case IA64_SAL_AP_EXTERNAL_INT: ap_wakeup_vector = ap->vector; # ifdef SAL_DEBUG - printk("SAL: AP wakeup using external interrupt; " + printk("SAL: AP wakeup using external interrupt " "vector 0x%lx\n", ap_wakeup_vector); # endif break; @@ -151,6 +151,36 @@ break; } #endif + case SAL_DESC_PLATFORM_FEATURE: + { + struct ia64_sal_desc_platform_feature *pf = (void *) p; + printk("SAL: Platform features "); + + if (pf->feature_mask & (1 << 0)) + printk("BusLock "); + + if (pf->feature_mask & (1 << 1)) { + printk("IRQ_Redirection "); +#ifdef CONFIG_SMP + if (no_int_routing) + smp_int_redirect &= ~SMP_IRQ_REDIRECTION; + else + smp_int_redirect |= SMP_IRQ_REDIRECTION; +#endif + } + if (pf->feature_mask & (1 << 2)) { + printk("IPI_Redirection "); +#ifdef CONFIG_SMP + if (no_int_routing) + smp_int_redirect &= ~SMP_IPI_REDIRECTION; + else + smp_int_redirect |= SMP_IPI_REDIRECTION; +#endif + } + printk("\n"); + break; + } + } p += SAL_DESC_SIZE(*p); } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/sal_stub.S linux/arch/ia64/kernel/sal_stub.S --- v2.3.99-pre5/linux/arch/ia64/kernel/sal_stub.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/sal_stub.S Fri Apr 21 15:21:24 2000 @@ -1,17 +1,19 @@ /* - * gcc currently does not conform to the ia-64 calling convention as far - * as returning function values are concerned. Instead of returning - * values up to 32 bytes in size in r8-r11, gcc returns any value - * bigger than a doubleword via a structure that's allocated by the - * caller and whose address is passed into the function. Since - * SAL_PROC returns values according to the calling convention, this - * stub takes care of copying r8-r11 to the place where gcc expects - * them. - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang */ #ifndef __GCC_MULTIREG_RETVALS__ + /* + * gcc currently does not conform to the ia-64 calling + * convention as far as returning function values are + * concerned. Instead of returning values up to 32 bytes in + * size in r8-r11, gcc returns any value bigger than a + * doubleword via a structure that's allocated by the caller + * and whose address is passed into the function. Since + * SAL_PROC returns values according to the calling + * convention, this stub takes care of copying r8-r11 to the + * place where gcc expects them. + */ .text .psr abi64 .psr lsb diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/semaphore.c linux/arch/ia64/kernel/semaphore.c --- v2.3.99-pre5/linux/arch/ia64/kernel/semaphore.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/semaphore.c Fri Apr 21 15:21:24 2000 @@ -310,7 +310,7 @@ do { old_count = sem->count; count = old_count - RW_LOCK_BIAS; - } while (cmpxchg(&sem->count, old_count, count) != old_count); + } while (cmpxchg_acq(&sem->count, old_count, count) != old_count); if (count == 0) return; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/setup.c linux/arch/ia64/kernel/setup.c --- v2.3.99-pre5/linux/arch/ia64/kernel/setup.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/setup.c Fri Apr 21 15:21:24 2000 @@ -8,10 +8,12 @@ * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond * - * 02/04/00 D.Mosberger some more get_cpuinfo fixes... - * 02/01/00 R.Seth fixed get_cpuinfo for SMP - * 01/07/99 S.Eranian added the support for command line argument - * 06/24/99 W.Drummond added boot_cpu_data. + * 04/04/00 D.Mosberger renamed cpu_initialized to cpu_online_map + * 03/31/00 R.Seth cpu_initialized and current->processor fixes + * 02/04/00 D.Mosberger some more get_cpuinfo fixes... + * 02/01/00 R.Seth fixed get_cpuinfo for SMP + * 01/07/99 S.Eranian added the support for command line argument + * 06/24/99 W.Drummond added boot_cpu_data. */ #include #include @@ -32,6 +34,7 @@ #include #include #include +#include extern char _end; @@ -41,10 +44,13 @@ unsigned long ia64_cycles_per_usec; struct ia64_boot_param ia64_boot_param; struct screen_info screen_info; -unsigned long cpu_initialized = 0; /* This tells _start which CPU is booting. */ int cpu_now_booting = 0; +#ifdef CONFIG_SMP +volatile unsigned long cpu_online_map; +#endif + #define COMMAND_LINE_SIZE 512 char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */ @@ -101,7 +107,6 @@ setup_arch (char **cmdline_p) { unsigned long max_pfn, bootmap_start, bootmap_size; - u64 progress; /* * The secondary bootstrap loader passes us the boot @@ -147,7 +152,10 @@ printk("args to kernel: %s\n", *cmdline_p); -#ifndef CONFIG_SMP +#ifdef CONFIG_SMP + bootstrap_processor = hard_smp_processor_id(); + current->processor = bootstrap_processor; +#else cpu_init(); identify_cpu(&cpu_data[0]); #endif @@ -168,6 +176,11 @@ conswitchp = &dummy_con; # endif #endif + +#ifdef CONFIG_IA64_MCA + /* enable IA-64 Machine Check Abort Handling */ + ia64_mca_init(); +#endif paging_init(); platform_setup(cmdline_p); } @@ -183,8 +196,10 @@ unsigned long mask; for (c = cpu_data; c < cpu_data + NR_CPUS; ++c) { - if (!(cpu_initialized & (1UL << (c - cpu_data)))) +#ifdef CONFIG_SMP + if (!(cpu_online_map & (1UL << (c - cpu_data)))) continue; +#endif mask = c->features; @@ -209,7 +224,7 @@ if (mask) sprintf(cp, " 0x%lx", mask); - p += sprintf(buffer, + p += sprintf(p, "CPU# %lu\n" "\tvendor : %s\n" "\tfamily : %s\n" @@ -303,8 +318,6 @@ void cpu_init (void) { - int nr = smp_processor_id(); - /* Clear the stack memory reserved for pt_regs: */ memset(ia64_task_regs(current), 0, sizeof(struct pt_regs)); @@ -318,11 +331,6 @@ */ ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_PP); ia64_set_fpu_owner(0); /* initialize ar.k5 */ - - if (test_and_set_bit(nr, &cpu_initialized)) { - printk("CPU#%d already initialized!\n", nr); - machine_halt(); - } atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c --- v2.3.99-pre5/linux/arch/ia64/kernel/signal.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/signal.c Fri Apr 21 15:21:24 2000 @@ -94,7 +94,7 @@ restore_sigcontext (struct sigcontext *sc, struct pt_regs *pt) { struct switch_stack *sw = (struct switch_stack *) pt - 1; - unsigned long ip, flags, nat, um; + unsigned long ip, flags, nat, um, cfm; long err; /* restore scratch that always needs gets updated during signal delivery: */ @@ -102,20 +102,24 @@ err |= __get_user(nat, &sc->sc_nat); err |= __get_user(ip, &sc->sc_ip); /* instruction pointer */ - err |= __get_user(pt->ar_fpsr, &sc->sc_ar_fpsr); - err |= __get_user(pt->ar_pfs, &sc->sc_ar_pfs); + err |= __get_user(cfm, &sc->sc_cfm); err |= __get_user(um, &sc->sc_um); /* user mask */ err |= __get_user(pt->ar_rsc, &sc->sc_ar_rsc); err |= __get_user(pt->ar_ccv, &sc->sc_ar_ccv); err |= __get_user(pt->ar_unat, &sc->sc_ar_unat); + err |= __get_user(pt->ar_fpsr, &sc->sc_ar_fpsr); + err |= __get_user(pt->ar_pfs, &sc->sc_ar_pfs); err |= __get_user(pt->pr, &sc->sc_pr); /* predicates */ err |= __get_user(pt->b0, &sc->sc_br[0]); /* b0 (rp) */ - err |= __get_user(pt->b6, &sc->sc_br[6]); + err |= __get_user(pt->b6, &sc->sc_br[6]); /* b6 */ + err |= __get_user(pt->b7, &sc->sc_br[7]); /* b7 */ err |= __copy_from_user(&pt->r1, &sc->sc_gr[1], 3*8); /* r1-r3 */ err |= __copy_from_user(&pt->r8, &sc->sc_gr[8], 4*8); /* r8-r11 */ err |= __copy_from_user(&pt->r12, &sc->sc_gr[12], 4*8); /* r12-r15 */ err |= __copy_from_user(&pt->r16, &sc->sc_gr[16], 16*8); /* r16-r31 */ + pt->cr_ifs = cfm | (1UL << 63); + /* establish new instruction pointer: */ pt->cr_iip = ip & ~0x3UL; ia64_psr(pt)->ri = ip & 0x3; @@ -240,6 +244,7 @@ nat = ia64_get_nat_bits(pt, sw); err = __put_user(flags, &sc->sc_flags); + err |= __put_user(nat, &sc->sc_nat); err |= PUT_SIGSET(mask, &sc->sc_mask); err |= __put_user(pt->cr_ipsr & IA64_PSR_UM, &sc->sc_um); @@ -255,8 +260,8 @@ err |= __copy_to_user(&sc->sc_gr[1], &pt->r1, 3*8); /* r1-r3 */ err |= __copy_to_user(&sc->sc_gr[8], &pt->r8, 4*8); /* r8-r11 */ - err |= __copy_to_user(&sc->sc_gr[12], &pt->r12, 4*8); /* r12-r15 */ - err |= __copy_to_user(&sc->sc_gr[16], &pt->r16, 16*8); /* r16-r31 */ + err |= __copy_to_user(&sc->sc_gr[12], &pt->r12, 4*8); /* r12-r15 */ + err |= __copy_to_user(&sc->sc_gr[16], &pt->r16, 16*8); /* r16-r31 */ err |= __put_user(pt->cr_iip + ia64_psr(pt)->ri, &sc->sc_ip); err |= __put_user(pt->r12, &sc->sc_gr[12]); /* r12 */ @@ -415,10 +420,12 @@ if ((current->flags & PF_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; + current->thread.siginfo = &info; set_current_state(TASK_STOPPED); notify_parent(current, SIGCHLD); schedule(); signr = current->exit_code; + current->thread.siginfo = 0; /* We're back. Did the debugger cancel the sig? */ if (!signr) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c --- v2.3.99-pre5/linux/arch/ia64/kernel/smp.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ia64/kernel/smp.c Fri Apr 21 15:21:24 2000 @@ -6,6 +6,8 @@ * * Lots of stuff stolen from arch/alpha/kernel/smp.c * + * 00/03/31 Rohit Seth Fixes for Bootstrap Processor & cpu_online_map + * now gets done here (instead of setup.c) * 99/10/05 davidm Update to bring it in sync with new command-line processing scheme. */ #define __KERNEL_SYSCALLS__ @@ -24,15 +26,6 @@ #include #include #include - -#ifdef CONFIG_KDB -#include -void smp_kdb_interrupt (struct pt_regs* regs); -void kdb_global(int cpuid); -extern unsigned long smp_kdb_wait; -extern int kdb_new_cpu; -#endif - #include #include #include @@ -47,25 +40,24 @@ extern int cpu_idle(void * unused); extern void _start(void); -extern int cpu_now_booting; /* Used by head.S to find idle task */ -extern unsigned long cpu_initialized; /* Bitmap of available cpu's */ -extern struct cpuinfo_ia64 cpu_data[NR_CPUS]; /* Duh... */ +extern int cpu_now_booting; /* Used by head.S to find idle task */ +extern volatile unsigned long cpu_online_map; /* Bitmap of available cpu's */ +extern struct cpuinfo_ia64 cpu_data[NR_CPUS]; /* Duh... */ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; -#ifdef CONFIG_KDB -unsigned long cpu_online_map = 1; -#endif +struct smp_boot_data __initdata smp; +char __initdata no_int_routing = 0; +unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ volatile int __cpu_number_map[NR_CPUS] = { -1, }; /* SAPIC ID -> Logical ID */ volatile int __cpu_logical_map[NR_CPUS] = { -1, }; /* logical ID -> SAPIC ID */ int smp_num_cpus = 1; -int bootstrap_processor = -1; /* SAPIC ID of BSP */ -int smp_threads_ready = 0; /* Set when the idlers are all forked */ -unsigned long ipi_base_addr = IPI_DEFAULT_BASE_ADDR; /* Base addr of IPI table */ +int bootstrap_processor = -1; /* SAPIC ID of BSP */ +int smp_threads_ready = 0; /* Set when the idlers are all forked */ cycles_t cacheflush_time = 0; -unsigned long ap_wakeup_vector = -1; /* External Int to use to wakeup AP's */ -static int max_cpus = -1; /* Command line */ +unsigned long ap_wakeup_vector = -1; /* External Int to use to wakeup AP's */ +static int max_cpus = -1; /* Command line */ static unsigned long ipi_op[NR_CPUS]; struct smp_call_struct { void (*func) (void *info); @@ -76,20 +68,13 @@ }; static struct smp_call_struct *smp_call_function_data; -#ifdef CONFIG_KDB -unsigned long smp_kdb_wait = 0; /* Bitmask of waiters */ -#endif - #ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC extern spinlock_t ivr_read_lock; #endif -int use_xtp = 0; /* XXX */ - #define IPI_RESCHEDULE 0 #define IPI_CALL_FUNC 1 #define IPI_CPU_STOP 2 -#define IPI_KDB_INTERRUPT 4 /* * Setup routine for controlling SMP activation @@ -118,13 +103,22 @@ __setup("maxcpus=", maxcpus); +static int __init +nointroute(char *str) +{ + no_int_routing = 1; + return 1; +} + +__setup("nointroute", nointroute); + /* * Yoink this CPU from the runnable list... */ void halt_processor(void) { - clear_bit(smp_processor_id(), &cpu_initialized); + clear_bit(smp_processor_id(), &cpu_online_map); max_xtp(); __cli(); for (;;) @@ -188,12 +182,6 @@ halt_processor(); break; -#ifdef CONFIG_KDB - case IPI_KDB_INTERRUPT: - smp_kdb_interrupt(regs); - break; -#endif - default: printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); break; @@ -205,32 +193,6 @@ } static inline void -send_IPI(int dest_cpu, unsigned char vector) -{ - unsigned long ipi_addr; - unsigned long ipi_data; -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC - unsigned long flags; -#endif - - ipi_data = vector; - ipi_addr = ipi_base_addr | ((dest_cpu << 8) << 4); /* 16-bit SAPIC ID's; assume CPU bus 0 */ - mb(); - -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC - /* - * Disable IVR reads - */ - spin_lock_irqsave(&ivr_read_lock, flags); - writeq(ipi_data, ipi_addr); - spin_unlock_irqrestore(&ivr_read_lock, flags); -#else - writeq(ipi_data, ipi_addr); -#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ - -} - -static inline void send_IPI_single(int dest_cpu, int op) { @@ -238,7 +200,7 @@ return; ipi_op[dest_cpu] |= (1 << op); - send_IPI(dest_cpu, IPI_IRQ); + ipi_send(dest_cpu, IPI_IRQ, IA64_IPI_DM_INT, 0); } static inline void @@ -452,9 +414,11 @@ ia64_clear_ic(flags); ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2)); ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2)); + ia64_srlz_d(); ia64_itr(0x3, 1, PAGE_OFFSET, pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), _PAGE_SIZE_256M); + ia64_srlz_i(); flags = (IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | IA64_PSR_BN); @@ -492,6 +456,10 @@ smp_store_cpu_info(smp_processor_id()); smp_setup_percpu_timer(smp_processor_id()); + if (test_and_set_bit(smp_processor_id(), &cpu_online_map)) { + printk("CPU#%d already initialized!\n", smp_processor_id()); + machine_halt(); + } while (!smp_threads_ready) mb(); @@ -505,6 +473,9 @@ ia64_set_lrr1(0, 1); __sti(); /* Interrupts have been off till now. */ + + printk("SMP: CPU %d starting idle loop\n", smp_processor_id()); + cpu_idle(NULL); } @@ -565,7 +536,7 @@ cpu_now_booting = cpunum; /* Kick the AP in the butt */ - send_IPI(cpuid, ap_wakeup_vector); + ipi_send(cpuid, ap_wakeup_vector, IA64_IPI_DM_INT, 0); ia64_srlz_i(); mb(); @@ -575,24 +546,20 @@ * is waiting for smp_threads_ready to be 1 and we can move on. */ for (timeout = 0; timeout < 100000; timeout++) { - if (test_bit(cpuid, &cpu_initialized)) + if (test_bit(cpuid, &cpu_online_map)) goto alive; - udelay(10); + udelay(100); barrier(); } printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid); - return -1; + return 0; alive: /* Remember the AP data */ __cpu_number_map[cpuid] = cpunum; -#ifdef CONFIG_KDB - cpu_online_map |= (1< 1) { + if (max_cpus != -1) + printk("Limiting CPUs to %d\n", max_cpus); + + if (smp.cpu_count > 1) { printk(KERN_INFO "SMP: starting up secondaries.\n"); for (i = 0; i < NR_CPUS; i++) { - if (acpi_apic_map[i] == -1 || - acpi_apic_map[i] == bootstrap_processor << 8) /* XXX Fix me Walt */ + if (smp.cpu_map[i] == -1 || + smp.cpu_map[i] == bootstrap_processor) continue; - /* - * IA64 SAPIC ID's are 16-bits. See asm/smp.h for more info - */ - sapic_id = acpi_apic_map[i] >> 8; - if (smp_boot_one_cpu(sapic_id, cpu_count)) + if (smp_boot_one_cpu(smp.cpu_map[i], cpu_count) == 0) continue; cpu_count++; /* Count good CPUs only... */ + /* + * Bail if we've started as many CPUS as we've been told to. + */ + if (cpu_count == max_cpus) + break; } } if (cpu_count == 1) { printk(KERN_ERR "SMP: Bootstrap processor only.\n"); - return; } bogosum = 0; for (i = 0; i < NR_CPUS; i++) { - if (cpu_initialized & (1L << i)) + if (cpu_online_map & (1L << i)) bogosum += cpu_data[i].loops_per_sec; } @@ -733,45 +704,8 @@ if (sal_ret < 0) { printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret)); printk(" Forcing UP mode\n"); + max_cpus = 0; smp_num_cpus = 1; } } - -#ifdef CONFIG_KDB -void smp_kdb_stop (int all, struct pt_regs* regs) -{ - if (all) - { - printk ("Sending IPI to all on CPU %i\n", smp_processor_id ()); - smp_kdb_wait = 0xffffffff; - clear_bit (smp_processor_id(), &smp_kdb_wait); - send_IPI_allbutself (IPI_KDB_INTERRUPT); - } - else - { - printk ("Sending IPI to self on CPU %i\n", - smp_processor_id ()); - set_bit (smp_processor_id(), &smp_kdb_wait); - clear_bit (__cpu_logical_map[kdb_new_cpu], &smp_kdb_wait); - smp_kdb_interrupt (regs); - } -} - -void smp_kdb_interrupt (struct pt_regs* regs) -{ - printk ("kdb: IPI on CPU %i with mask 0x%08x\n", - smp_processor_id (), smp_kdb_wait); - - /* All CPUs spin here forever */ - while (test_bit (smp_processor_id(), &smp_kdb_wait)); - - /* Enter KDB on CPU selected by KDB on the last CPU */ - if (__cpu_logical_map[kdb_new_cpu] == smp_processor_id ()) - { - kdb (KDB_REASON_SWITCH, 0, regs); - } -} - -#endif - diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/smpboot.c linux/arch/ia64/kernel/smpboot.c --- v2.3.99-pre5/linux/arch/ia64/kernel/smpboot.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/smpboot.c Fri Apr 21 15:21:24 2000 @@ -0,0 +1,2 @@ +unsigned long cpu_online_map; + diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c --- v2.3.99-pre5/linux/arch/ia64/kernel/time.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/time.c Fri Apr 21 15:21:24 2000 @@ -9,11 +9,12 @@ * Copyright (C) 1999-2000 Walt Drummond */ #include + #include -#include #include #include #include +#include #include #include @@ -136,6 +137,7 @@ static unsigned long last_time; static unsigned char count; int cpu = smp_processor_id(); + int printed = 0; /* * Here we are in the timer irq handler. We have irqs locally @@ -145,9 +147,14 @@ */ write_lock(&xtime_lock); while (1) { - /* do kernel PC profiling here. */ + /* + * Do kernel PC profiling here. We multiply the + * instruction number by four so that we can use a + * prof_shift of 2 to get instruction-level instead of + * just bundle-level accuracy. + */ if (!user_mode(regs)) - do_profile(regs->cr_iip); + do_profile(regs->cr_iip + 4*ia64_psr(regs)->ri); #ifdef CONFIG_SMP smp_do_timer(regs); @@ -172,15 +179,18 @@ #if !(defined(CONFIG_IA64_SOFTSDV_HACKS) && defined(CONFIG_SMP)) /* - * SoftSDV in SMP mode is _slow_, so we do "loose" ticks, + * SoftSDV in SMP mode is _slow_, so we do "lose" ticks, * but it's really OK... */ if (count > 0 && jiffies - last_time > 5*HZ) count = 0; if (count++ == 0) { last_time = jiffies; - printk("Lost clock tick on CPU %d (now=%lx, next=%lx)!!\n", - cpu, ia64_get_itc(), itm.next[cpu]); + if (!printed) { + printk("Lost clock tick on CPU %d (now=%lx, next=%lx)!!\n", + cpu, ia64_get_itc(), itm.next[cpu]); + printed = 1; + } # ifdef CONFIG_IA64_DEBUG_IRQ printk("last_cli_ip=%lx\n", last_cli_ip); # endif @@ -303,8 +313,6 @@ time_init (void) { /* we can't do request_irq() here because the kmalloc() would fail... */ - irq_desc[TIMER_IRQ].status = IRQ_DISABLED; - irq_desc[TIMER_IRQ].handler = &irq_type_ia64_internal; setup_irq(TIMER_IRQ, &timer_irqaction); efi_gettimeofday(&xtime); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c --- v2.3.99-pre5/linux/arch/ia64/kernel/traps.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/traps.c Fri Apr 21 15:21:24 2000 @@ -32,10 +32,7 @@ #include #include -#ifdef CONFIG_KDB -# include -#endif - +#include #include #include @@ -88,13 +85,6 @@ printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err); -#ifdef CONFIG_KDB - while (1) { - kdb(KDB_REASON_PANIC, 0, regs); - printk("Cant go anywhere from Panic!\n"); - } -#endif - show_regs(regs); if (current->thread.flags & IA64_KERNEL_DEATH) { @@ -440,7 +430,18 @@ case 35: /* Taken Branch Trap */ case 36: /* Single Step Trap */ switch (vector) { - case 29: siginfo.si_code = TRAP_BRKPT; break; + case 29: + siginfo.si_code = TRAP_HWBKPT; +#ifdef CONFIG_ITANIUM + /* + * Erratum 10 (IFA may contain incorrect address) now has + * "NoFix" status. There are no plans for fixing this. + */ + if (ia64_psr(regs)->is == 0) + ifa = regs->cr_iip; +#endif + siginfo.si_addr = (void *) ifa; + break; case 35: siginfo.si_code = TRAP_BRANCH; break; case 36: siginfo.si_code = TRAP_TRACE; break; } @@ -479,12 +480,18 @@ break; case 45: - printk("Unexpected IA-32 exception\n"); +#ifdef CONFIG_IA32_SUPPORT + if (ia32_exception(regs, isr) == 0) + return; +#endif + printk("Unexpected IA-32 exception (Trap 45)\n"); + printk(" iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", regs->cr_iip, ifa, isr); force_sig(SIGSEGV, current); - return; + break; case 46: - printk("Unexpected IA-32 intercept trap\n"); + printk("Unexpected IA-32 intercept trap (Trap 46)\n"); + printk(" iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", regs->cr_iip, ifa, isr); force_sig(SIGSEGV, current); return; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/kernel/unaligned.c linux/arch/ia64/kernel/unaligned.c --- v2.3.99-pre5/linux/arch/ia64/kernel/unaligned.c Sat Feb 26 22:31:39 2000 +++ linux/arch/ia64/kernel/unaligned.c Fri Apr 21 15:21:24 2000 @@ -305,7 +305,7 @@ DPRINT(("rnat @%p = 0x%lx nat=%d rnatval=%lx\n", addr, rnats, nat, rnats &ia64_rse_slot_num(slot))); - if ( nat ) { + if (nat) { rnats |= __IA64_UL(1) << ia64_rse_slot_num(slot); } else { rnats &= ~(__IA64_UL(1) << ia64_rse_slot_num(slot)); @@ -385,7 +385,8 @@ ia64_peek(regs, current, (unsigned long)addr, &rnats); DPRINT(("rnat @%p = 0x%lx\n", addr, rnats)); - if ( nat ) *nat = rnats >> ia64_rse_slot_num(slot) & 0x1; + if (nat) + *nat = rnats >> ia64_rse_slot_num(slot) & 0x1; } @@ -401,7 +402,7 @@ /* * First takes care of stacked registers */ - if ( regnum >= IA64_FIRST_STACKED_GR ) { + if (regnum >= IA64_FIRST_STACKED_GR) { set_rse_reg(regs, regnum, val, nat); return; } @@ -414,7 +415,7 @@ /* * Now look at registers in [0-31] range and init correct UNAT */ - if ( GR_IN_SW(regnum) ) { + if (GR_IN_SW(regnum)) { addr = (unsigned long)sw; unat = &sw->ar_unat; } else { @@ -437,7 +438,7 @@ */ bitmask = __IA64_UL(1) << (addr >> 3 & 0x3f); DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, unat, *unat)); - if ( nat ) { + if (nat) { *unat |= bitmask; } else { *unat &= ~bitmask; @@ -465,7 +466,7 @@ * fly to store to the right register. * For now, we are using the (slow) save/restore way. */ - if ( regnum >= IA64_FIRST_ROTATING_FR ) { + if (regnum >= IA64_FIRST_ROTATING_FR) { /* * force a save of [32-127] to tss * we use the __() form to avoid fiddling with the dfh bit @@ -489,7 +490,7 @@ /* * pt_regs or switch_stack ? */ - if ( FR_IN_SW(regnum) ) { + if (FR_IN_SW(regnum)) { addr = (unsigned long)sw; } else { addr = (unsigned long)regs; @@ -542,7 +543,7 @@ * we need to force a save to the tss to get access to it. * See discussion in setfpreg() for reasons and other ways of doing this. */ - if ( regnum >= IA64_FIRST_ROTATING_FR ) { + if (regnum >= IA64_FIRST_ROTATING_FR) { /* * force a save of [32-127] to tss @@ -587,7 +588,7 @@ struct switch_stack *sw = (struct switch_stack *)regs -1; unsigned long addr, *unat; - if ( regnum >= IA64_FIRST_STACKED_GR ) { + if (regnum >= IA64_FIRST_STACKED_GR) { get_rse_reg(regs, regnum, val, nat); return; } @@ -595,7 +596,7 @@ /* * take care of r0 (read-only always evaluate to 0) */ - if ( regnum == 0 ) { + if (regnum == 0) { *val = 0; *nat = 0; return; @@ -604,7 +605,7 @@ /* * Now look at registers in [0-31] range and init correct UNAT */ - if ( GR_IN_SW(regnum) ) { + if (GR_IN_SW(regnum)) { addr = (unsigned long)sw; unat = &sw->ar_unat; } else { @@ -621,7 +622,8 @@ /* * do it only when requested */ - if ( nat ) *nat = (*unat >> (addr >> 3 & 0x3f)) & 0x1UL; + if (nat) + *nat = (*unat >> (addr >> 3 & 0x3f)) & 0x1UL; } static void @@ -633,7 +635,7 @@ * not get to this point in the code but we keep this sanity check, * just in case. */ - if ( ld->x6_op == 1 || ld->x6_op == 3 ) { + if (ld->x6_op == 1 || ld->x6_op == 3) { printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n"); die_if_kernel("unaligned reference on specualtive load with register update\n", regs, 30); @@ -644,7 +646,7 @@ * at this point, we know that the base register to update is valid i.e., * it's not r0 */ - if ( type == UPD_IMMEDIATE ) { + if (type == UPD_IMMEDIATE) { unsigned long imm; /* @@ -670,7 +672,7 @@ DPRINT(("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld->x, ld->m, imm, ifa)); - } else if ( ld->m ) { + } else if (ld->m) { unsigned long r2; int nat_r2; @@ -719,7 +721,7 @@ * * Note: the first argument is ignored */ - if ( access_ok(VERIFY_READ, (void *)ifa, len) < 0 ) { + if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) { DPRINT(("verify area failed on %lx\n", ifa)); return -1; } @@ -737,7 +739,7 @@ * invalidate the ALAT entry. * See comment below for explanation on how we handle ldX.a */ - if ( ld->x6_op != 0x2 ) { + if (ld->x6_op != 0x2) { /* * we rely on the macros in unaligned.h for now i.e., * we let the compiler figure out how to read memory gracefully. @@ -767,9 +769,8 @@ /* * check for updates on any kind of loads */ - if ( ld->op == 0x5 || ld->m ) - emulate_load_updates(ld->op == 0x5 ? UPD_IMMEDIATE: UPD_REG, - ld, regs, ifa); + if (ld->op == 0x5 || ld->m) + emulate_load_updates(ld->op == 0x5 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); /* * handling of various loads (based on EAS2.4): @@ -882,7 +883,7 @@ * * Note: the first argument is ignored */ - if ( access_ok(VERIFY_WRITE, (void *)ifa, len) < 0 ) { + if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) { DPRINT(("verify area failed on %lx\n",ifa)); return -1; } @@ -926,7 +927,7 @@ * ld->r3 can never be r0, because r0 would not generate an * unaligned access. */ - if ( ld->op == 0x5 ) { + if (ld->op == 0x5) { unsigned long imm; /* @@ -936,7 +937,7 @@ /* * sign extend (8bits) if m set */ - if ( ld->m ) imm |= SIGN_EXT9; + if (ld->m) imm |= SIGN_EXT9; /* * ifa == r3 (NaT is necessarily cleared) */ @@ -955,7 +956,8 @@ /* * stX.rel: use fence instead of release */ - if ( ld->x6_op == 0xd ) mb(); + if (ld->x6_op == 0xd) + mb(); return 0; } @@ -1033,7 +1035,7 @@ struct ia64_fpreg fpr_final[2]; unsigned long len = float_fsz[ld->x6_sz]; - if ( access_ok(VERIFY_READ, (void *)ifa, len<<1) < 0 ) { + if (access_ok(VERIFY_READ, (void *)ifa, len<<1) < 0) { DPRINT(("verify area failed on %lx\n", ifa)); return -1; } @@ -1055,7 +1057,7 @@ * ldfpX.a: we don't try to emulate anything but we must * invalidate the ALAT entry and execute updates, if any. */ - if ( ld->x6_op != 0x2 ) { + if (ld->x6_op != 0x2) { /* * does the unaligned access */ @@ -1118,7 +1120,7 @@ * Check for updates: only immediate updates are available for this * instruction. */ - if ( ld->m ) { + if (ld->m) { /* * the immediate is implicit given the ldsz of the operation: @@ -1132,8 +1134,9 @@ * as long as we don't come here with a ldfpX.s. * For this reason we keep this sanity check */ - if ( ld->x6_op == 1 || ld->x6_op == 3 ) { - printk(KERN_ERR "%s: register update on speculative load pair, error\n", __FUNCTION__); + if (ld->x6_op == 1 || ld->x6_op == 3) { + printk(KERN_ERR "%s: register update on speculative load pair, error\n", + __FUNCTION__); } @@ -1143,7 +1146,7 @@ /* * Invalidate ALAT entries, if any, for both registers. */ - if ( ld->x6_op == 0x2 ) { + if (ld->x6_op == 0x2) { invala_fr(ld->r1); invala_fr(ld->imm); } @@ -1160,10 +1163,10 @@ /* * check for load pair because our masking scheme is not fine grain enough - if ( ld->x == 1 ) return emulate_load_floatpair(ifa,ld,regs); + if (ld->x == 1) return emulate_load_floatpair(ifa,ld,regs); */ - if ( access_ok(VERIFY_READ, (void *)ifa, len) < 0 ) { + if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) { DPRINT(("verify area failed on %lx\n", ifa)); return -1; } @@ -1187,7 +1190,7 @@ * invalidate the ALAT entry. * See comments in ldX for descriptions on how the various loads are handled. */ - if ( ld->x6_op != 0x2 ) { + if (ld->x6_op != 0x2) { /* * does the unaligned access @@ -1243,7 +1246,7 @@ /* * check for updates on any loads */ - if ( ld->op == 0x7 || ld->m ) + if (ld->op == 0x7 || ld->m) emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa); @@ -1274,7 +1277,7 @@ * * Note: the first argument is ignored */ - if ( access_ok(VERIFY_WRITE, (void *)ifa, len) < 0 ) { + if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) { DPRINT(("verify area failed on %lx\n",ifa)); return -1; } @@ -1342,7 +1345,7 @@ * ld->r3 can never be r0, because r0 would not generate an * unaligned access. */ - if ( ld->op == 0x7 ) { + if (ld->op == 0x7) { unsigned long imm; /* @@ -1352,7 +1355,8 @@ /* * sign extend (8bits) if m set */ - if ( ld->m ) imm |= SIGN_EXT9; + if (ld->m) + imm |= SIGN_EXT9; /* * ifa == r3 (NaT is necessarily cleared) */ @@ -1384,6 +1388,28 @@ load_store_t *insn; int ret = -1; + /* + * Unaligned references in the kernel could come from unaligned + * arguments to system calls. We fault the user process in + * these cases and panic the kernel otherwise (the kernel should + * be fixed to not make unaligned accesses). + */ + if (!user_mode(regs)) { + const struct exception_table_entry *fix; + + fix = search_exception_table(regs->cr_iip); + if (fix) { + regs->r8 = -EFAULT; + if (fix->skip & 1) { + regs->r9 = 0; + } + regs->cr_iip += ((long) fix->skip) & ~15; + regs->cr_ipsr &= ~IA64_PSR_RI; /* clear exception slot number */ + return; + } + die_if_kernel("Unaligned reference while in kernel\n", regs, 30); + /* NOT_REACHED */ + } if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) { struct siginfo si; @@ -1539,7 +1565,7 @@ } DPRINT(("ret=%d\n", ret)); - if ( ret ) { + if (ret) { lock_kernel(); force_sig(SIGSEGV, current); unlock_kernel(); @@ -1549,7 +1575,8 @@ * because a memory access instruction (M) can never be in the * last slot of a bundle. But let's keep it for now. */ - if ( ipsr->ri == 2 ) regs->cr_iip += 16; + if (ipsr->ri == 2) + regs->cr_iip += 16; ipsr->ri = ++ipsr->ri & 3; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/lib/clear_user.S linux/arch/ia64/lib/clear_user.S --- v2.3.99-pre5/linux/arch/ia64/lib/clear_user.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/clear_user.S Fri Apr 21 15:21:24 2000 @@ -210,6 +210,7 @@ // if p7 -> coming from st4 or st1 : len3 contains what's left // We must restore lc/pr even though might not have been used. .Lexit2: + .pred.rel "mutex", p6, p7 (p6) mov len=len2 (p7) mov len=len3 ;; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/lib/strlen.S linux/arch/ia64/lib/strlen.S --- v2.3.99-pre5/linux/arch/ia64/lib/strlen.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/strlen.S Fri Apr 21 15:21:24 2000 @@ -186,6 +186,7 @@ ;; cmp.eq p6,p0=8,val1 // val1==8 ? (p6) br.wtop.dptk.few 2b // loop until p6 == 0 + ;; // (avoid WAW on p63) sub ret0=base,orig // distance from base sub tmp=8,val1 mov pr=saved_pr,0xffffffffffff0000 diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/mm/fault.c linux/arch/ia64/mm/fault.c --- v2.3.99-pre5/linux/arch/ia64/mm/fault.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/mm/fault.c Mon Apr 24 15:52:23 2000 @@ -94,7 +94,7 @@ * sure we exit gracefully rather than endlessly redo the * fault. */ - if (!handle_mm_fault(current, vma, address, (isr & IA64_ISR_W) != 0)) { + if (!handle_mm_fault(mm, vma, address, (isr & IA64_ISR_W) != 0)) { /* * We ran out of memory, or some other thing happened * to us that made us unable to handle the page fault diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c --- v2.3.99-pre5/linux/arch/ia64/mm/init.c Fri Mar 10 16:40:40 2000 +++ linux/arch/ia64/mm/init.c Fri Apr 21 15:21:24 2000 @@ -237,6 +237,7 @@ if (!PageReserved(page)) printk("put_gate_page: gate page at 0x%lx not in reserved memory\n", page_address(page)); + pgd = pgd_offset_k(address); /* note: this is NOT pgd_offset()! */ pmd = pmd_alloc(pgd, address); if (!pmd) { diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c --- v2.3.99-pre5/linux/arch/ia64/mm/tlb.c Fri Mar 10 16:40:40 2000 +++ linux/arch/ia64/mm/tlb.c Fri Apr 21 15:21:24 2000 @@ -138,7 +138,7 @@ */ ++nbits; if (((1UL << nbits) & SUPPORTED_PGBITS) == 0) - panic("flush_tlb_range: BUG: nbits=%lu\n", nbits); + panic("flush_tlb_range: BUG: nbits=%lu\n", nbits); } start &= ~((1UL << nbits) - 1); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/tools/Makefile linux/arch/ia64/tools/Makefile --- v2.3.99-pre5/linux/arch/ia64/tools/Makefile Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/tools/Makefile Fri Apr 21 15:21:24 2000 @@ -8,6 +8,8 @@ all: +mrproper: + clean: rm -f print_offsets.s print_offsets offsets.h diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c --- v2.3.99-pre5/linux/arch/ia64/tools/print_offsets.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ia64/tools/print_offsets.c Fri Apr 21 15:21:24 2000 @@ -12,6 +12,8 @@ * file, be sure to verify that the awk procedure still works (see * prin_offsets.awk). */ +#include + #include #include @@ -50,6 +52,9 @@ { "IA64_TASK_PROCESSOR_OFFSET", offsetof (struct task_struct, processor) }, { "IA64_TASK_THREAD_OFFSET", offsetof (struct task_struct, thread) }, { "IA64_TASK_THREAD_KSP_OFFSET", offsetof (struct task_struct, thread.ksp) }, +#ifdef CONFIG_IA32_SUPPORT + { "IA64_TASK_THREAD_SIGMASK_OFFSET",offsetof (struct task_struct, thread.un.sigmask) }, +#endif { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, { "IA64_TASK_MM_OFFSET", offsetof (struct task_struct, mm) }, { "IA64_PT_REGS_CR_IPSR_OFFSET", offsetof (struct pt_regs, cr_ipsr) }, @@ -63,6 +68,8 @@ { "IA64_SIGCONTEXT_FLAGS_OFFSET", offsetof (struct sigcontext, sc_flags) }, { "IA64_SIGCONTEXT_CFM_OFFSET", offsetof (struct sigcontext, sc_cfm) }, { "IA64_SIGCONTEXT_FR6_OFFSET", offsetof (struct sigcontext, sc_fr[6]) }, + { "IA64_CLONE_VFORK", CLONE_VFORK }, + { "IA64_CLONE_VM", CLONE_VM }, }; static const char *tabs = "\t\t\t\t\t\t\t\t\t\t"; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S --- v2.3.99-pre5/linux/arch/ia64/vmlinux.lds.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/vmlinux.lds.S Fri Apr 21 15:21:24 2000 @@ -8,7 +8,7 @@ ENTRY(_start) SECTIONS { - v = PAGE_OFFSET; /* this symbol is here to make debugging with kdb easier... */ + v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */ . = KERNEL_START; @@ -38,21 +38,6 @@ __ex_table : AT(ADDR(__ex_table) - PAGE_OFFSET) { *(__ex_table) } __stop___ex_table = .; - -#if defined(CONFIG_KDB) - /* Kernel symbols and strings for kdb */ -# define KDB_MEAN_SYMBOL_SIZE 48 -# define KDB_SPACE (CONFIG_KDB_STBSIZE * KDB_MEAN_SYMBOL_SIZE) - . = ALIGN(8); - _skdb = .; - .kdb : AT(ADDR(.kdb) - PAGE_OFFSET) - { - *(kdbsymtab) - *(kdbstrings) - } - _ekdb = .; - . = _skdb + KDB_SPACE; -#endif /* Kernel symbol names for modules: */ .kstrtab : AT(ADDR(.kstrtab) - PAGE_OFFSET) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c --- v2.3.99-pre5/linux/arch/m68k/mm/fault.c Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/mm/fault.c Mon Apr 24 15:51:29 2000 @@ -99,7 +99,7 @@ * make sure we exit gracefully rather than endlessly redo * the fault. */ - fault = handle_mm_fault(current, vma, address, write); + fault = handle_mm_fault(mm, vma, address, write); if (fault < 0) goto out_of_memory; if (!fault) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/mips/baget/vacserial.c linux/arch/mips/baget/vacserial.c --- v2.3.99-pre5/linux/arch/mips/baget/vacserial.c Sat Feb 26 22:31:39 2000 +++ linux/arch/mips/baget/vacserial.c Fri Apr 21 15:17:57 2000 @@ -2168,7 +2168,7 @@ done: if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c --- v2.3.99-pre5/linux/arch/mips/kernel/irixelf.c Mon Mar 27 08:08:22 2000 +++ linux/arch/mips/kernel/irixelf.c Thu Apr 13 08:11:48 2000 @@ -717,16 +717,8 @@ set_fs(old_fs); kfree(elf_phdata); - current->personality = PER_IRIX32; - - put_exec_domain(current->exec_domain); - if (current->binfmt && current->binfmt->module) - __MOD_DEC_USE_COUNT(current->binfmt->module); - current->exec_domain = lookup_exec_domain(current->personality); - current->binfmt = &irix_format; - if (current->binfmt && current->binfmt->module) - __MOD_INC_USE_COUNT(current->binfmt->module); - + set_personality(PER_IRIX32); + set_binfmt(&irix_format); compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; bprm->p = (unsigned long) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c --- v2.3.99-pre5/linux/arch/mips/kernel/sysirix.c Tue Apr 11 15:09:13 2000 +++ linux/arch/mips/kernel/sysirix.c Wed Apr 26 09:25:17 2000 @@ -533,7 +533,7 @@ int ret; lock_kernel(); - if (brk < current->mm->end_code) { + if (brk < mm->end_code) { ret = -ENOMEM; goto out; } @@ -549,9 +549,9 @@ /* * Always allow shrinking brk */ - if (brk <= current->mm->brk) { + if (brk <= mm->brk) { mm->brk = brk; - do_munmap(newbrk, oldbrk-newbrk); + do_munmap(mm, newbrk, oldbrk-newbrk); ret = 0; goto out; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c --- v2.3.99-pre5/linux/arch/mips/mm/fault.c Sat Feb 26 22:31:41 2000 +++ linux/arch/mips/mm/fault.c Mon Apr 24 15:50:04 2000 @@ -91,7 +91,7 @@ * the fault. */ { - int fault = handle_mm_fault(tsk, vma, address, write); + int fault = handle_mm_fault(mm, vma, address, write); if (fault < 0) goto out_of_memory; if (!fault) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/mips64/mm/fault.c linux/arch/mips64/mm/fault.c --- v2.3.99-pre5/linux/arch/mips64/mm/fault.c Sat Feb 26 22:31:41 2000 +++ linux/arch/mips64/mm/fault.c Mon Apr 24 15:52:34 2000 @@ -94,7 +94,7 @@ * the fault. */ { - int fault = handle_mm_fault(tsk, vma, address, write); + int fault = handle_mm_fault(mm, vma, address, write); if (fault < 0) goto out_of_memory; if (!fault) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c --- v2.3.99-pre5/linux/arch/ppc/8xx_io/uart.c Tue Apr 11 15:09:13 2000 +++ linux/arch/ppc/8xx_io/uart.c Fri Apr 21 15:17:57 2000 @@ -2063,7 +2063,7 @@ done: if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.3.99-pre5/linux/arch/ppc/defconfig Tue Apr 11 15:09:13 2000 +++ linux/arch/ppc/defconfig Thu Apr 13 22:54:26 2000 @@ -184,8 +184,8 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC6210 is not set -# CONFIG_AEC6210_TUNING 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_AMD7409 is not set diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c --- v2.3.99-pre5/linux/arch/ppc/kernel/apus_setup.c Sat Feb 26 22:31:41 2000 +++ linux/arch/ppc/kernel/apus_setup.c Tue Apr 25 17:58:46 2000 @@ -108,18 +108,6 @@ #ifdef CONFIG_HEARTBEAT void (*mach_heartbeat) (int) __apusdata = NULL; extern void apus_heartbeat (void); -static int heartbeat_enabled = 1; - -void enable_heartbeat(void) -{ - heartbeat_enabled = 1; -} - -void disable_heartbeat(void) -{ - heartbeat_enabled = 0; - mach_heartbeat(0); -} #endif extern unsigned long amiga_model; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.3.99-pre5/linux/arch/ppc/kernel/chrp_setup.c Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/kernel/chrp_setup.c Mon Apr 24 13:39:36 2000 @@ -422,10 +422,10 @@ request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI), xmon_irq, 0, "NMI", 0); #endif /* CONFIG_XMON */ -#ifdef __SMP__ +#ifdef CONFIG_SMP request_irq(openpic_to_irq(OPENPIC_VEC_IPI), openpic_ipi_action, 0, "IPI0", 0); -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ } void __init diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/gemini_prom.S linux/arch/ppc/kernel/gemini_prom.S --- v2.3.99-pre5/linux/arch/ppc/kernel/gemini_prom.S Tue Dec 7 09:32:41 1999 +++ linux/arch/ppc/kernel/gemini_prom.S Mon Apr 24 13:39:36 2000 @@ -10,6 +10,7 @@ #include "ppc_asm.tmpl" #include "ppc_defs.h" +#include #include #include #include @@ -25,7 +26,7 @@ _GLOBAL(prom_init) _GLOBAL(gemini_prom_init) -#ifdef __SMP__ +#ifdef CONFIG_SMP /* Since the MMU's on, get stuff in rom space that we'll need */ lis r4,GEMINI_CPUSTAT@h ori r4,r4,GEMINI_CPUSTAT@l @@ -74,14 +75,14 @@ addi r3,r3,1 bdnz 3b -#ifdef __SMP__ +#ifdef CONFIG_SMP /* The 750 book (and Mot/IBM support) says that this will "assist" snooping when in SMP. Not sure yet whether this should stay or leave... */ mfspr r4,HID0 ori r4,r4,HID0_ABE mtspr HID0,r4 sync -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ blr /* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c --- v2.3.99-pre5/linux/arch/ppc/kernel/gemini_setup.c Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/kernel/gemini_setup.c Mon Apr 24 13:39:36 2000 @@ -303,7 +303,7 @@ /* standard stuff */ cache |= ((1<need_resched && htab_reclaim_on ) htab_reclaim(); if ( !current->need_resched ) power_save(); -#ifdef __SMP__ +#ifdef CONFIG_SMP if (current->need_resched) #endif schedule(); @@ -162,11 +162,11 @@ : "=&r" (tmp), "=&r" (page), "+m" (zero_cache) : "r" (&zero_quicklist) : "cc" ); -#ifdef __SMP__ +#ifdef CONFIG_SMP /* if another cpu beat us above this can happen -- Cort */ if ( page == 0 ) return 0; -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ /* we can update zerocount after the fact since it is not * used for anything but control of a loop which doesn't * matter since it won't affect anything if it zeros one @@ -253,7 +253,7 @@ /* atomically add this page to the list */ asm ( "101:lwarx %0,0,%2\n" /* reserve zero_cache */ " stw %0,0(%3)\n" /* update *pageptr */ -#ifdef __SMP__ +#ifdef CONFIG_SMP " sync\n" /* let store settle */ #endif " stwcx. %3,0,%2\n" /* update zero_cache in mem */ diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.3.99-pre5/linux/arch/ppc/kernel/irq.c Fri Mar 10 16:40:40 2000 +++ linux/arch/ppc/kernel/irq.c Mon Apr 24 13:39:36 2000 @@ -237,13 +237,13 @@ if ( !action || !action->handler ) continue; len += sprintf(buf+len, "%3d: ", i); -#ifdef __SMP__ +#ifdef CONFIG_SMP for (j = 0; j < smp_num_cpus; j++) len += sprintf(buf+len, "%10u ", kstat.irqs[cpu_logical_map(j)][i]); #else len += sprintf(buf+len, "%10u ", kstat_irqs(i)); -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ if ( irq_desc[i].handler ) len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename ); else @@ -254,7 +254,7 @@ } len += sprintf(buf+len, "\n"); } -#ifdef __SMP__ +#ifdef CONFIG_SMP /* should this be per processor send/receive? */ len += sprintf(buf+len, "IPI: %10lu\n", ipi_count); #endif @@ -343,7 +343,7 @@ ppc_md.init_IRQ(); } -#ifdef __SMP__ +#ifdef CONFIG_SMP unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile int global_irq_lock; atomic_t global_irq_count; @@ -611,7 +611,7 @@ } } } -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ static struct proc_dir_entry * root_irq_dir; static struct proc_dir_entry * irq_dir [NR_IRQS]; @@ -733,7 +733,7 @@ irq_dir[irq] = proc_mkdir(name, root_irq_dir); /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); entry->nlink = 1; entry->data = (void *)irq; @@ -754,7 +754,7 @@ root_irq_dir = proc_mkdir("irq", 0); /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir); + entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); entry->nlink = 1; entry->data = (void *)&prof_cpu_mask; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.3.99-pre5/linux/arch/ppc/kernel/misc.S Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/misc.S Mon Apr 24 13:39:36 2000 @@ -142,7 +142,7 @@ sync tlbia sync -#ifdef __SMP__ +#ifdef CONFIG_SMP tlbsync sync #endif @@ -154,7 +154,7 @@ _GLOBAL(_tlbie) tlbie r3 sync -#ifdef __SMP__ +#ifdef CONFIG_SMP tlbsync sync #endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c --- v2.3.99-pre5/linux/arch/ppc/kernel/open_pic.c Fri Mar 10 16:40:40 2000 +++ linux/arch/ppc/kernel/open_pic.c Mon Apr 24 13:39:36 2000 @@ -101,12 +101,12 @@ { } -#ifdef __SMP__ +#ifdef CONFIG_SMP void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) { smp_message_recv(cpl-OPENPIC_VEC_IPI); } -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ #ifdef __i386__ static inline u_int in_le32(volatile u_int *addr) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.3.99-pre5/linux/arch/ppc/kernel/pmac_pic.c Tue Mar 7 14:32:25 2000 +++ linux/arch/ppc/kernel/pmac_pic.c Mon Apr 24 13:39:36 2000 @@ -183,7 +183,7 @@ int irq; unsigned long bits = 0; -#ifdef __SMP__ +#ifdef CONFIG_SMP void pmac_smp_message_recv(void); /* IPI's are a hack on the powersurge -- Cort */ @@ -197,7 +197,7 @@ pmac_smp_message_recv(); return -2; /* ignore, already handled */ } -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ /* Yeah, I know, this could be a separate get_irq function */ if (has_openpic) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.3.99-pre5/linux/arch/ppc/kernel/ppc_ksyms.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/ppc_ksyms.c Mon Apr 24 13:39:36 2000 @@ -35,9 +35,9 @@ #include #include #include -#ifdef __SMP__ +#ifdef CONFIG_SMP #include -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ #include "time.h" /* Tell string.h we don't want memcpy etc. as cpp defines */ @@ -76,9 +76,9 @@ EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(local_bh_count); -#ifdef __SMP__ +#ifdef CONFIG_SMP EXPORT_SYMBOL(kernel_flag); -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) EXPORT_SYMBOL(isa_io_base); @@ -189,7 +189,7 @@ EXPORT_SYMBOL(enable_kernel_fp); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(xchg_u32); -#ifdef __SMP__ +#ifdef CONFIG_SMP EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.3.99-pre5/linux/arch/ppc/kernel/prep_setup.c Wed Dec 29 13:13:13 1999 +++ linux/arch/ppc/kernel/prep_setup.c Mon Apr 24 13:39:36 2000 @@ -118,7 +118,7 @@ extern char *Motherboard_map_name; int len, i; -#ifdef __SMP__ +#ifdef CONFIG_SMP #define CD(X) (cpu_data[n].X) #else #define CD(X) (X) @@ -624,10 +624,10 @@ for ( i = 0 ; i < 16 ; i++ ) irq_desc[i].handler = &i8259_pic; i8259_init(); -#ifdef __SMP__ +#ifdef CONFIG_SMP request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action, 0, "IPI0", 0); -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.3.99-pre5/linux/arch/ppc/kernel/process.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/process.c Mon Apr 24 13:39:36 2000 @@ -154,7 +154,7 @@ void enable_kernel_altivec(void) { -#ifdef __SMP__ +#ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) giveup_altivec(current); else @@ -169,14 +169,14 @@ void enable_kernel_fp(void) { -#ifdef __SMP__ +#ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) giveup_fpu(current); else giveup_fpu(NULL); /* just enables FP for kernel */ #else giveup_fpu(last_task_used_math); -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ } int @@ -208,7 +208,7 @@ new->comm,new->pid,new->thread.regs->nip,new->processor, new->fs->root,prev->fs->root); #endif -#ifdef __SMP__ +#ifdef CONFIG_SMP /* avoid complexity of lazy save/restore of fpu * by just saving it every time we switch out if * this task used the fpu during the last quantum. @@ -236,7 +236,7 @@ #endif /* CONFIG_ALTIVEC */ prev->last_processor = prev->processor; current_set[smp_processor_id()] = new; -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ /* Avoid the trap. On smp this this never happens since * we don't set last_task_used_altivec -- Cort */ @@ -265,9 +265,9 @@ printk("\nlast math %p last altivec %p", last_task_used_math, last_task_used_altivec); -#ifdef __SMP__ +#ifdef CONFIG_SMP printk(" CPU: %d last CPU: %d", current->processor,current->last_processor); -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ printk("\n"); for (i = 0; i < 32; i++) @@ -319,7 +319,7 @@ { unsigned long msr; struct pt_regs * childregs, *kregs; -#ifdef __SMP__ +#ifdef CONFIG_SMP extern void ret_from_smpfork(void); #else extern void ret_from_except(void); @@ -336,7 +336,7 @@ p->thread.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD; p->thread.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD; kregs = (struct pt_regs *)(p->thread.ksp + STACK_FRAME_OVERHEAD); -#ifdef __SMP__ +#ifdef CONFIG_SMP kregs->nip = (unsigned long)ret_from_smpfork; #else kregs->nip = (unsigned long)ret_from_except; @@ -378,9 +378,9 @@ childregs->msr &= ~MSR_VEC; #endif /* CONFIG_ALTIVEC */ -#ifdef __SMP__ +#ifdef CONFIG_SMP p->last_processor = NO_PROC_ID; -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ return 0; } @@ -447,14 +447,14 @@ int res; lock_kernel(); res = do_fork(clone_flags, regs->gpr[1], regs); -#ifdef __SMP__ +#ifdef CONFIG_SMP /* When we clone the idle task we keep the same pid but * the return value of 0 for both causes problems. * -- Cort */ if ((current->pid == 0) && (current == &init_task)) res = 1; -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ unlock_kernel(); return res; } @@ -466,14 +466,14 @@ int res; res = do_fork(SIGCHLD, regs->gpr[1], regs); -#ifdef __SMP__ +#ifdef CONFIG_SMP /* When we clone the idle task we keep the same pid but * the return value of 0 for both causes problems. * -- Cort */ if ((current->pid == 0) && (current == &init_task)) res = 1; -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ return res; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c --- v2.3.99-pre5/linux/arch/ppc/kernel/ptrace.c Tue Aug 31 17:29:13 1999 +++ linux/arch/ppc/kernel/ptrace.c Mon Apr 24 15:50:54 2000 @@ -100,7 +100,7 @@ repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 0); + handle_mm_fault(tsk->mm, vma, addr, 0); goto repeat; } if (pgd_bad(*pgdir)) { @@ -110,7 +110,7 @@ } pgmiddle = pmd_offset(pgdir,addr); if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 0); + handle_mm_fault(tsk->mm, vma, addr, 0); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -120,7 +120,7 @@ } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 0); + handle_mm_fault(tsk->mm, vma, addr, 0); goto repeat; } page = pte_page(*pgtable); @@ -151,7 +151,7 @@ repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (!pgd_present(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 1); + handle_mm_fault(tsk->mm, vma, addr, 1); goto repeat; } if (pgd_bad(*pgdir)) { @@ -161,7 +161,7 @@ } pgmiddle = pmd_offset(pgdir,addr); if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 1); + handle_mm_fault(tsk->mm, vma, addr, 1); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -171,12 +171,12 @@ } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); + handle_mm_fault(tsk->mm, vma, addr, 1); goto repeat; } page = pte_page(*pgtable); if (!pte_write(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); + handle_mm_fault(tsk->mm, vma, addr, 1); goto repeat; } /* this is a hack for non-kernel-mapped video buffers and similar */ @@ -198,7 +198,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr, unsigned long * result) { - struct vm_area_struct * vma = find_extend_vma(tsk, addr); + struct vm_area_struct * vma = find_extend_vma(tsk->mm, addr); if (!vma) return -EIO; @@ -240,7 +240,7 @@ static int write_long(struct task_struct * tsk, unsigned long addr, unsigned long data) { - struct vm_area_struct * vma = find_extend_vma(tsk, addr); + struct vm_area_struct * vma = find_extend_vma(tsk->mm, addr); if (!vma) return -EIO; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.3.99-pre5/linux/arch/ppc/kernel/setup.c Sun Mar 19 18:35:30 2000 +++ linux/arch/ppc/kernel/setup.c Mon Apr 24 13:39:36 2000 @@ -204,7 +204,7 @@ unsigned int pvr; unsigned short maj, min; -#ifdef __SMP__ +#ifdef CONFIG_SMP #define CPU_PRESENT(x) (cpu_callin_map[(x)]) #define GET_PVR ((long int)(cpu_data[i].pvr)) #define CD(x) (cpu_data[i].x) @@ -355,13 +355,13 @@ bogosum += CD(loops_per_sec); } -#ifdef __SMP__ +#ifdef CONFIG_SMP if ( i ) len += sprintf(buffer+len, "\n"); len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n", (bogosum+2500)/500000, (bogosum+2500)/5000 % 100); -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ /* * Ooh's and aah's info about zero'd pages in idle task diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.3.99-pre5/linux/arch/ppc/kernel/time.c Tue Jan 11 22:31:38 2000 +++ linux/arch/ppc/kernel/time.c Mon Apr 24 13:39:36 2000 @@ -74,7 +74,7 @@ unsigned long cpu = smp_processor_id(); hardirq_enter(cpu); -#ifdef __SMP__ +#ifdef CONFIG_SMP { unsigned int loops = 100000000; while (test_bit(0, &global_irq_lock)) { @@ -93,7 +93,7 @@ } } } -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ dval = get_dec(); /* @@ -133,7 +133,7 @@ last_rtc_update = xtime.tv_sec; } } -#ifdef __SMP__ +#ifdef CONFIG_SMP smp_local_timer_interrupt(regs); #endif @@ -155,7 +155,7 @@ cli(); *tv = xtime; /* XXX we don't seem to have the decrementers synced properly yet */ -#ifndef __SMP__ +#ifndef CONFIG_SMP tv->tv_usec += (decrementer_count - get_dec()) * count_period_num / count_period_den; if (tv->tv_usec >= 1000000) { diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c --- v2.3.99-pre5/linux/arch/ppc/mm/fault.c Tue Apr 11 15:09:13 2000 +++ linux/arch/ppc/mm/fault.c Mon Apr 24 15:50:18 2000 @@ -135,7 +135,7 @@ if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - if (!handle_mm_fault(current, vma, address, is_write)) + if (!handle_mm_fault(mm, vma, address, is_write)) goto bad_area; up(&mm->mmap_sem); /* diff -u --recursive --new-file v2.3.99-pre5/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.3.99-pre5/linux/arch/ppc/mm/init.c Tue Mar 7 14:32:25 2000 +++ linux/arch/ppc/mm/init.c Mon Apr 24 13:39:36 2000 @@ -87,7 +87,7 @@ extern int num_memory; extern struct mem_info memory[]; extern boot_infos_t *boot_infos; -#ifndef __SMP__ +#ifndef CONFIG_SMP struct pgtable_cache_struct quicklists; #endif @@ -278,9 +278,9 @@ show_buffers(); printk("%-8s %3s %8s %8s %8s %9s %8s", "Process", "Pid", "Ctx", "Ctx<<4", "Last Sys", "pc", "task"); -#ifdef __SMP__ +#ifdef CONFIG_SMP printk(" %3s", "CPU"); -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ printk("\n"); for_each_task(p) { @@ -294,7 +294,7 @@ (ulong)p); { int iscur = 0; -#ifdef __SMP__ +#ifdef CONFIG_SMP printk("%3d ", p->processor); if ( (p->processor != NO_PROC_ID) && (p == current_set[p->processor]) ) @@ -315,7 +315,7 @@ printk(","); printk("last math"); } -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ printk("\n"); } } @@ -495,7 +495,7 @@ { __clear_user(Hash, Hash_size); _tlbia(); -#ifdef __SMP__ +#ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif } @@ -511,7 +511,7 @@ mm->context = NO_CONTEXT; if (mm == current->mm) activate_mm(mm, mm); -#ifdef __SMP__ +#ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif } @@ -523,7 +523,7 @@ flush_hash_page(vma->vm_mm->context, vmaddr); else flush_hash_page(0, vmaddr); -#ifdef __SMP__ +#ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif } @@ -551,7 +551,7 @@ { flush_hash_page(mm->context, start); } -#ifdef __SMP__ +#ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif } @@ -575,7 +575,7 @@ } read_unlock(&tasklist_lock); flush_hash_segments(0x10, 0xffffff); -#ifdef __SMP__ +#ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif atomic_set(&next_mmu_context, 0); @@ -663,7 +663,7 @@ } #define IO_PAGE (_PAGE_NO_CACHE | _PAGE_GUARDED | _PAGE_RW) -#ifdef __SMP__ +#ifdef CONFIG_SMP #define RAM_PAGE (_PAGE_RW|_PAGE_COHERENT) #else #define RAM_PAGE (_PAGE_RW) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/defconfig linux/arch/sh/defconfig --- v2.3.99-pre5/linux/arch/sh/defconfig Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/defconfig Mon Apr 24 13:54:17 2000 @@ -54,12 +54,17 @@ # 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_DEV_DAC960 is not set # # Additional Block Devices # # CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_STRIPED is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y @@ -122,6 +127,7 @@ # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS 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_BFS_FS is not set @@ -135,17 +141,23 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_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_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_SYSV_FS_WRITE 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_NCPFS_NLS is not set # # Partition Types diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile --- v2.3.99-pre5/linux/arch/sh/kernel/Makefile Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/kernel/Makefile Mon Apr 24 13:54:17 2000 @@ -29,7 +29,6 @@ entry.o: entry.S head.o: head.S - $(CC) $(AFLAGS) -traditional -c $*.S -o $*.o clean: diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S --- v2.3.99-pre5/linux/arch/sh/kernel/entry.S Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/kernel/entry.S Mon Apr 24 13:54:17 2000 @@ -14,6 +14,8 @@ #include #include +#define COMPAT_OLD_SYSCALL_ABI 1 + ! NOTE: ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address ! to be jumped is too far, but it causes illegal slot exception. @@ -31,26 +33,24 @@ * if the order here is changed, it needs to be * updated in ptrace.c and ptrace.h * - * syscall # - * ssr - * r0 + * $r0 * ... - * r15 = stack pointer - * gbr - * mach - * macl - * pr - * spc + * $r15 = stack pointer + * $spc + * $pr + * $ssr + * $gbr + * $mach + * $macl + * syscall # * */ /* * These are offsets into the task-struct. */ -state = 0 flags = 4 sigpending = 8 -addr_limit = 12 need_resched = 20 PF_TRACESYS = 0x00000020 @@ -75,30 +75,35 @@ #endif /* Offsets to the stack */ -SYSCALL_NR = 0 -SR = 4 -R0 = 8 -SP = (8+15*4) +R0 = 0 /* Return value */ +SP = (15*4) +SR = (16*4+8) +SYSCALL_NR = (16*4+6*4) + #define k0 r0 #define k1 r1 #define k2 r2 #define k3 r3 +#define k4 r4 -#define kernel_sp r4 /* r4_bank1 */ -#define ksp r4_bank /* r4_bank1 */ +#define current r7 /* r7_bank1 */ +#define g_imask r6 /* r6_bank1 */ +#define k_current r7_bank /* r7_bank1 */ +#define k_g_imask r6_bank /* r6_bank1 */ #define k_ex_code r2_bank /* r2_bank1 */ -/* Kernel mode register usage: - k0 scratch - k1 scratch - k2 scratch (Exception code) - k3 scratch (Return address) - k4 Stack base = current+8192 - k5 Global Interrupt Mask (0--15) - k6 reserved - k7 reserved -*/ +/* + * Kernel mode register usage: + * k0 scratch + * k1 scratch + * k2 scratch (Exception code) + * k3 scratch (Return address) + * k4 scratch + * k5 reserved + * k6 Global Interrupt Mask (0--15 << 4) + * k7 CURRENT (pointer to current task) + */ ! ! TLB Miss / Initial Page write exception handling @@ -114,42 +119,60 @@ ! this first version depends *much* on C implementation. ! -#define RESTORE_FLAGS() \ - mov.l @(SR,$r15), $r0; \ - and #0xf0, $r0; \ - shlr8 $r0; \ - cmp/eq #0x0f, $r0; \ - bt 9f; \ - mov.l __INV_IMASK, $r1; \ - stc $sr, $r0; \ - and $r1, $r0; \ - stc $r5_bank, $r1; \ - or $r1, $r0; \ - ldc $r0, $sr +#define STI() \ + mov.l __INV_IMASK, $r11; \ + stc $sr, $r10; \ + and $r11, $r10; \ + stc $k_g_imask, $r11; \ + or $r11, $r10; \ + ldc $r10, $sr .balign 4 -tlb_protection_violation_load: tlb_miss_load: - mov #-1, $r0 - mov.l $r0, @$r15 ! syscall nr = -1 mov.l 2f, $r0 mov.l @$r0, $r6 - RESTORE_FLAGS() -9: mov $r15, $r4 + STI() + mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 mov #0, $r5 .balign 4 -tlb_protection_violation_store: tlb_miss_store: + mov.l 2f, $r0 + mov.l @$r0, $r6 + STI() + mov $r15, $r4 + mov.l 1f, $r0 + jmp @$r0 + mov #1, $r5 + + .balign 4 initial_page_write: - mov #-1, $r0 - mov.l $r0, @$r15 ! syscall nr = -1 mov.l 2f, $r0 mov.l @$r0, $r6 - RESTORE_FLAGS() -9: mov $r15, $r4 + STI() + mov $r15, $r4 + mov.l 1f, $r0 + jmp @$r0 + mov #1, $r5 + + .balign 4 +tlb_protection_violation_load: + mov.l 2f, $r0 + mov.l @$r0, $r6 + STI() + mov $r15, $r4 + mov.l 1f, $r0 + jmp @$r0 + mov #0, $r5 + + .balign 4 +tlb_protection_violation_store: + mov.l 2f, $r0 + mov.l @$r0, $r6 + STI() + mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 mov #1, $r5 @@ -162,8 +185,6 @@ .balign 4 /* Unwind the stack and jmp to the debug entry */ debug: - add #4, $r15 ! skip syscall number - mov.l @$r15+, $r11 ! SSR mov.l @$r15+, $r0 mov.l @$r15+, $r1 mov.l @$r15+, $r2 @@ -172,11 +193,10 @@ mov.l @$r15+, $r5 mov.l @$r15+, $r6 mov.l @$r15+, $r7 - stc $sr, $r14 - mov.l 1f, $r9 ! BL =1, RB=1 - or $r9, $r14 - ldc $r14, $sr ! here, change the register bank - mov $r11, $k1 + stc $sr, $r8 + mov.l 1f, $r9 ! BL =1, RB=1, IMASK=0x0F + or $r9, $r8 + ldc $r8, $sr ! here, change the register bank mov.l @$r15+, $r8 mov.l @$r15+, $r9 mov.l @$r15+, $r10 @@ -185,11 +205,12 @@ mov.l @$r15+, $r13 mov.l @$r15+, $r14 mov.l @$r15+, $k0 + ldc.l @$r15+, $spc + lds.l @$r15+, $pr + mov.l @$r15+, $k1 ldc.l @$r15+, $gbr lds.l @$r15+, $mach lds.l @$r15+, $macl - lds.l @$r15+, $pr - ldc.l @$r15+, $spc mov $k0, $r15 ! mov.l 2f, $k0 @@ -203,11 +224,10 @@ .balign 4 error: ! - RESTORE_FLAGS() -9: mov.l 1f, $r1 - mov #-1, $r0 - jmp @$r1 - mov.l $r0, @$r15 ! syscall nr = -1 + STI() + mov.l 1f, $r0 + jmp @$r0 + nop .balign 4 1: .long SYMBOL_NAME(do_exception_error) @@ -222,76 +242,106 @@ bra SYMBOL_NAME(ret_from_syscall) add #4, $r15 ! pop down bogus r0 (see switch_to MACRO) -! -! The immediate value of "trapa" indicates the number of arguments -! placed on the stack. -! -! Note that TRA register contains the value = Imm x 4. -! +/* + * Old syscall interface: + * + * Syscall #: R0 + * Arguments #0 to #3: R4--R7 + * more arguments: On the stack + * TRA: (number of arguments on the stack) x 4 + * + * New syscall interface: + * + * Syscall #: R3 + * Arguments #0 to #3: R4--R7 + * Arguments #4 to #6: R0, R1, R2 + * TRA: (number of arguments + 0x10) x 4 + * + */ + system_call: - mov.l 1f, $r2 - mov.l @$r2, $r8 - ! - ! DEBUG DEBUG - ! mov.l led, $r1 - ! mov $r0, $r2 - ! mov.b $r2, @$r1 + mov.l 1f, $r9 + mov.l @$r9, $r8 ! #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB - mov #0x20, $r1 - extu.b $r1, $r1 - shll2 $r1 - cmp/hs $r1, $r8 + mov #0x20, $r9 + extu.b $r9, $r9 + shll2 $r9 + cmp/hs $r9, $r8 bt debug #endif ! - mov $r0, $r2 - RESTORE_FLAGS() -9: mov.l __n_sys, $r1 - cmp/hs $r1, $r2 + mov #SYSCALL_NR, $r14 + add $r15, $r14 + ! + mov #0x40, $r9 +#ifdef COMPAT_OLD_SYSCALL_ABI + cmp/hs $r9, $r8 + mov $r0, $r10 + bf/s 0f + mov $r0, $r9 +#endif + ! New Syscall ABI + sub $r9, $r8 + shlr2 $r8 + shll8 $r8 + shll8 $r8 + mov $r3, $r10 + or $r8, $r10 ! Encode syscall # and # of arguments + ! + mov $r3, $r9 + mov #0, $r8 +0: + mov.l $r10, @$r14 ! set syscall_nr + STI() + mov.l __n_sys, $r10 + cmp/hs $r10, $r9 bt badsys ! - stc $ksp, $r1 - mov.l __tsk_flags, $r0 - add $r0, $r1 ! - mov.l @$r1, $r0 ! Is it trace? - tst #PF_TRACESYS, $r0 +#ifdef COMPAT_OLD_SYSCALL_ABI + ! Build the stack frame if TRA > 0 + mov $r8, $r10 + cmp/pl $r10 + bf 0f + mov.l @(SP,$r15), $r0 ! get original stack +7: add #-4, $r10 +4: mov.l @($r0,$r10), $r1 ! May cause address error exception.. + mov.l $r1, @-$r15 + cmp/pl $r10 + bt 7b +#endif +0: stc $k_current, $r11 + mov.l @(flags,$r11), $r10 ! Is it trace? + mov #PF_TRACESYS, $r11 + tst $r11, $r10 bt 5f ! Trace system call - mov #-ENOSYS, $r1 - mov.l $r1, @(R0,$r15) - mov.l 3f, $r1 - jsr @$r1 + mov #-ENOSYS, $r11 + mov.l $r11, @(R0,$r15) + mov.l 2f, $r11 + jsr @$r11 nop - mova 3f, $r0 + mov.l __syscall_ret_trace, $r10 bra 6f - lds $r0, $pr + lds $r10, $pr ! -5: mova syscall_ret, $r0 - lds $r0, $pr - ! Build the stack frame if TRA > 0 -6: mov $r2, $r3 - mov $r8, $r2 - cmp/pl $r8 - bf 0f - mov #SP, $r0 - mov.l @($r0,$r15), $r0 ! get original stack -7: add #-4, $r8 -4: mov.l @($r0,$r8), $r1 ! May cause address error exception.. - mov.l $r1, @-$r15 - cmp/pl $r8 - bt 7b +5: mov.l __syscall_ret, $r10 + lds $r10, $pr ! -0: mov $r3, $r0 - shll2 $r0 ! x4 - mov.l __sct, $r1 - add $r1, $r0 - mov.l @$r0, $r1 - jmp @$r1 - mov $r2, $r8 +6: mov $r9, $r10 + shll2 $r10 ! x4 + mov.l __sct, $r11 + add $r11, $r10 + mov.l @$r10, $r11 + jmp @$r11 + nop + ! In case of trace .balign 4 -3: add $r8, $r15 ! pop off the arguments +3: +#ifdef COMPAT_OLD_SYSCALL_ABI + add $r8, $r15 ! pop off the arguments +#endif mov.l $r0, @(R0,$r15) ! save the return value mov.l 2f, $r1 mova SYMBOL_NAME(ret_from_syscall), $r0 @@ -302,9 +352,12 @@ 2: .long SYMBOL_NAME(syscall_trace) __n_sys: .long NR_syscalls __sct: .long SYMBOL_NAME(sys_call_table) -__tsk_flags: .long flags-8192 ! offset from stackbase to tsk->flags -led: .long 0xa8000000 ! For my board -- gN +__syscall_ret_trace: + .long 3b +__syscall_ret: + .long SYMBOL_NAME(syscall_ret) +#ifdef COMPAT_OLD_SYSCALL_ABI .section .fixup,"ax" fixup_syscall_argerr: rts @@ -316,6 +369,7 @@ .balign 4 .long 4b,fixup_syscall_argerr .previous +#endif .balign 4 reschedule: @@ -327,23 +381,25 @@ 1: .long SYMBOL_NAME(schedule) ENTRY(ret_from_irq) - mov.l @(SR,$r15), $r0 ! get status register + mov #SR, $r0 + mov.l @($r0,$r15), $r0 ! get status register shll $r0 shll $r0 ! kernel space? bt restore_all ! Yes, it's from kernel, go back soon ! - RESTORE_FLAGS() -9: bra ret_with_reschedule + STI() + bra ret_with_reschedule nop ENTRY(ret_from_exception) - mov.l @(SR,$r15), $r0 ! get status register + mov #SR, $r0 + mov.l @($r0,$r15), $r0 ! get status register shll $r0 shll $r0 ! kernel space? bt restore_all ! Yes, it's from kernel, go back soon ! - RESTORE_FLAGS() -9: bra ret_from_syscall + STI() + bra ret_from_syscall nop .balign 4 __INV_IMASK: @@ -351,7 +407,9 @@ .balign 4 syscall_ret: +#ifdef COMPAT_OLD_SYSCALL_ABI add $r8, $r15 ! pop off the arguments +#endif mov.l $r0, @(R0,$r15) ! save the return value /* fall through */ @@ -366,9 +424,7 @@ jsr @$r0 nop ret_with_reschedule: - stc $ksp, $r1 - mov.l __minus8192, $r0 - add $r0, $r1 + stc $k_current, $r1 mov.l @(need_resched,$r1), $r0 tst #0xff, $r0 bf reschedule @@ -389,30 +445,14 @@ .long SYMBOL_NAME(softirq_state) __do_softirq: .long SYMBOL_NAME(do_softirq) -__minus8192: - .long -8192 ! offset from stackbase to tsk .balign 4 restore_all: #if defined(__SH4__) - mov.l __fpu_prepare_fd, $r1 - jsr @$r1 + mov.l __fpu_prepare_fd, $r0 + jsr @$r0 stc $sr, $r4 #endif - add #4, $r15 ! Skip syscall number - mov.l @$r15+, $r11 ! Got SSR into R11 -#if defined(__SH4__) - mov $r11, $r12 -#endif - ! - mov.l 1f, $r1 - stc $sr, $r0 - and $r1, $r0 ! Get FD - mov.l 2f, $r1 - and $r1, $r11 - or $r0, $r11 ! Inherit the FD value of SR - stc $r5_bank, $r0 - or $r0, $r11 ! Inherit the IMASK value ! mov.l @$r15+, $r0 mov.l @$r15+, $r1 @@ -422,14 +462,12 @@ mov.l @$r15+, $r5 mov.l @$r15+, $r6 mov.l @$r15+, $r7 - stc $sr, $r14 + ! + stc $sr, $r8 mov.l __blrb_flags, $r9 ! BL =1, RB=1 - or $r9, $r14 - ldc $r14, $sr ! here, change the register bank - mov $r11, $k1 -#if defined(__SH4__) - mov $r12, $k2 -#endif + or $r9, $r8 + ldc $r8, $sr ! here, change the register bank + ! mov.l @$r15+, $r8 mov.l @$r15+, $r9 mov.l @$r15+, $r10 @@ -437,20 +475,33 @@ mov.l @$r15+, $r12 mov.l @$r15+, $r13 mov.l @$r15+, $r14 - mov.l @$r15+, $k0 ! original stack + mov.l @$r15+, $k4 ! original stack pointer + ldc.l @$r15+, $spc + lds.l @$r15+, $pr + mov.l @$r15+, $k3 ! original SR ldc.l @$r15+, $gbr lds.l @$r15+, $mach lds.l @$r15+, $macl - lds.l @$r15+, $pr - ldc.l @$r15+, $spc - ldc $k1, $ssr + add #4, $r15 ! Skip syscall number + ! + ! Calculate new SR value + mov $k3, $k2 ! original SR value + mov.l 1f, $k1 + stc $sr, $k0 + and $k1, $k0 ! Get current FD-bit + mov.l 2f, $k1 + and $k1, $k2 ! Mask orignal SR value + or $k0, $k2 ! Inherit current FD-bit + or $g_imask, $k2 ! Inherit the IMASK-bits + ldc $k2, $ssr + ! #if defined(__SH4__) - shll $k1 - shll $k1 + shll $k2 + shll $k2 bf 9f ! user mode /* Kernel to kernel transition */ mov.l 1f, $k1 - tst $k1, $k2 + tst $k1, $k3 bf 9f ! it hadn't FPU ! Kernel to kernel and FPU was used ! There's the case we don't get FPU now @@ -462,14 +513,15 @@ ldc $k2, $sr ! Grab FPU mov.l __init_task_flags, $k1 mov.l @$k1, $k2 - mov.l __PF_USEDFPU, $k1 - or $k1, $k2 - mov.l __init_task_flags, $k1 + mov.l __PF_USEDFPU, $k0 + or $k0, $k2 mov.l $k2, @$k1 ! Set init_task.flags |= PF_USEDFPU ! ! Restoring FPU... ! -7: fmov.s @$r15+, $fr0 +7: mov.l 3f, $k1 + lds $k1, $fpscr + fmov.s @$r15+, $fr0 fmov.s @$r15+, $fr1 fmov.s @$r15+, $fr2 fmov.s @$r15+, $fr3 @@ -489,7 +541,7 @@ lds.l @$r15+, $fpul 9: #endif - mov $k0, $r15 + mov $k4, $r15 rte nop @@ -505,6 +557,7 @@ #endif 1: .long 0x00008000 ! FD 2: .long 0xffff7f0f ! ~(IMASK+FD) +3: .long 0x00080000 ! SZ=0, PR=1 ! Exception Vector Base ! @@ -569,6 +622,9 @@ ! /* Currently it's not the case for GCC (only udivsi3_i4, divsi3_i4) */ sts.l $fpul, @-$r15 sts.l $fpscr, @-$r15 + mov.l 6f, $k1 + lds $k1, $fpscr + mov.l 3f, $k1 fmov.s $fr15, @-$r15 fmov.s $fr14, @-$r15 fmov.s $fr13, @-$r15 @@ -584,40 +640,47 @@ fmov.s $fr3, @-$r15 fmov.s $fr2, @-$r15 fmov.s $fr1, @-$r15 - fmov.s $fr0, @-$r15 bra 9f - mov.l 3f, $k1 + fmov.s $fr0, @-$r15 #else mov.l 3f, $k1 bt/s 9f ! it's from kernel to kernel transition mov $r15, $k0 ! save original stack to k0 anyway #endif 8: /* User space to kernel */ - mov $kernel_sp, $r15 ! change to kernel stack - mov.l 4f, $k1 ! let kernel release FPU -9: stc.l $spc, @-$r15 - sts.l $pr, @-$r15 + mov #0x20, $k1 + shll8 $k1 ! $k1 <= 8192 + add $current, $k1 + mov $k1, $r15 ! change to kernel stack ! - lds $k3, $pr ! Set the return address to pr + mov.l 4f, $k1 ! let kernel release FPU +9: mov #-1, $k4 + mov.l $k4, @-$r15 ! syscall_nr (default: -1) ! sts.l $macl, @-$r15 sts.l $mach, @-$r15 stc.l $gbr, @-$r15 - mov.l $k0, @-$r15 ! save orignal stack - mov.l $r14, @-$r15 + stc.l $ssr, @-$r15 + sts.l $pr, @-$r15 + stc.l $spc, @-$r15 ! - stc $sr, $r14 ! Back to normal register bank, and - or $k1, $r14 ! Block all interrupts, may release FPU - mov.l 5f, $k1 - and $k1, $r14 ! ... - ldc $r14, $sr ! ...changed here. + lds $k3, $pr ! Set the return address to pr ! + mov.l $k0, @-$r15 ! save orignal stack + mov.l $r14, @-$r15 mov.l $r13, @-$r15 mov.l $r12, @-$r15 mov.l $r11, @-$r15 mov.l $r10, @-$r15 mov.l $r9, @-$r15 mov.l $r8, @-$r15 + ! + stc $sr, $r8 ! Back to normal register bank, and + or $k1, $r8 ! Block all interrupts, may release FPU + mov.l 5f, $k1 + and $k1, $r8 ! ... + ldc $r8, $sr ! ...changed here. + ! mov.l $r7, @-$r15 mov.l $r6, @-$r15 mov.l $r5, @-$r15 @@ -626,23 +689,22 @@ mov.l $r2, @-$r15 mov.l $r1, @-$r15 mov.l $r0, @-$r15 - stc.l $ssr, @-$r15 - mov.l $r0, @-$r15 ! push $r0 again (for syscall number) - ! Then, dispatch to the handler, according to the excepiton code. - stc $k_ex_code, $r1 - shlr2 $r1 - shlr $r1 - mov.l 1f, $r0 - add $r1, $r0 - mov.l @$r0, $r0 - jmp @$r0 - mov.l @$r15, $r0 ! recovering $r0.. + ! Then, dispatch to the handler, according to the exception code. + stc $k_ex_code, $r8 + shlr2 $r8 + shlr $r8 + mov.l 1f, $r9 + add $r8, $r9 + mov.l @$r9, $r9 + jmp @$r9 + nop .balign 4 1: .long SYMBOL_NAME(exception_handling_table) 2: .long 0x00008000 ! FD=1 3: .long 0x000000f0 ! FD=0, IMASK=15 4: .long 0x000080f0 ! FD=1, IMASK=15 5: .long 0xcfffffff ! RB=0, BL=0 +6: .long 0x00080000 ! SZ=0, PR=1 none: rts diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/fpu.c linux/arch/sh/kernel/fpu.c --- v2.3.99-pre5/linux/arch/sh/kernel/fpu.c Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/kernel/fpu.c Mon Apr 24 13:54:17 2000 @@ -23,6 +23,7 @@ { asm volatile("sts.l $fpul, @-%0\n\t" "sts.l $fpscr, @-%0\n\t" + "lds %1, $fpscr\n\t" "frchg\n\t" "fmov.s $fr15, @-%0\n\t" "fmov.s $fr14, @-%0\n\t" @@ -58,7 +59,8 @@ "fmov.s $fr1, @-%0\n\t" "fmov.s $fr0, @-%0" : /* no output */ - : "r" ((char *)(&tsk->thread.fpu.hard.status)) + : "r" ((char *)(&tsk->thread.fpu.hard.status)), + "r" (FPSCR_INIT) : "memory"); tsk->flags &= ~PF_USEDFPU; @@ -68,7 +70,8 @@ static void restore_fpu(struct task_struct *tsk) { - asm volatile("fmov.s @%0+, $fr0\n\t" + asm volatile("lds %1, $fpscr\n\t" + "fmov.s @%0+, $fr0\n\t" "fmov.s @%0+, $fr1\n\t" "fmov.s @%0+, $fr2\n\t" "fmov.s @%0+, $fr3\n\t" @@ -105,7 +108,7 @@ "lds.l @%0+, $fpscr\n\t" "lds.l @%0+, $fpul\n\t" : /* no output */ - : "r" (&tsk->thread.fpu) + : "r" (&tsk->thread.fpu), "r" (FPSCR_INIT) : "memory"); } @@ -163,7 +166,6 @@ { struct task_struct *tsk = current; - regs.syscall_nr = -1; regs.pc += 2; grab_fpu(); @@ -179,15 +181,34 @@ { struct task_struct *tsk = current; - regs.syscall_nr = -1; - if (!user_mode(®s)) { if (tsk != &init_task) { unlazy_fpu(tsk); } tsk = &init_task; - if (tsk->flags & PF_USEDFPU) - BUG(); + if (tsk->flags & PF_USEDFPU) { + /* + * This weird situation can be occurred. + * + * There's race condition in __cli: + * + * (1) $SR --> register + * (2) Set IMASK of register + * (3) $SR <-- register + * + * Between (1) and (2), or (2) and (3) getting + * interrupt, and interrupt handler (or + * softirq) may use FPU. + * + * Then, SR.FD is overwritten by (3). + * + * This results init_task.PF_USEDFPU is on, + * with SR.FD == 1. + * + */ + release_fpu(); + return; + } } grab_fpu(); @@ -216,8 +237,8 @@ grab_fpu(); else { if (!(sr & SR_FD)) { - release_fpu(); BUG(); + release_fpu(); } } return; @@ -228,16 +249,20 @@ grab_fpu(); else { if (init_task.flags & PF_USEDFPU) { - init_task.flags &= ~PF_USEDFPU; - BUG(); + /* + * This weird situation can be occurred. + * See the comment in do_fpu_state_restore. + */ + grab_fpu(); + save_fpu(&init_task); } } } else { if (init_task.flags & PF_USEDFPU) save_fpu(&init_task); else { - release_fpu(); BUG(); + release_fpu(); } } } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/head.S linux/arch/sh/kernel/head.S --- v2.3.99-pre5/linux/arch/sh/kernel/head.S Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/kernel/head.S Mon Apr 24 13:54:17 2000 @@ -41,12 +41,21 @@ ldc $r0, $sr ! Initialize global interrupt mask mov #0, $r0 - ldc $r0, $r5_bank + ldc $r0, $r6_bank ! mov.l 2f, $r0 mov $r0, $r15 ! Set initial r15 (stack pointer) - ldc $r0, $r4_bank ! and stack base + mov #0x20, $r1 ! + shll8 $r1 ! $r1 = 8192 + sub $r1, $r0 ! + ldc $r0, $r7_bank ! ... and init_task ! +#if defined(__SH4__) + ! Initialize fpu + mov.l 7f, $r0 + jsr @$r0 + nop +#endif ! Enable cache mov.l 6f, $r0 jsr @$r0 @@ -71,3 +80,6 @@ 4: .long SYMBOL_NAME(_end) 5: .long SYMBOL_NAME(start_kernel) 6: .long SYMBOL_NAME(cache_init) +#if defined(__SH4__) +7: .long SYMBOL_NAME(fpu_init) +#endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c --- v2.3.99-pre5/linux/arch/sh/kernel/irq.c Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/kernel/irq.c Mon Apr 24 13:54:17 2000 @@ -235,8 +235,6 @@ struct irqaction * action; unsigned int status; - regs.syscall_nr = -1; /* It's not system call */ - /* Get IRQ number */ asm volatile("stc $r2_bank, %0\n\t" "shlr2 %0\n\t" diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/irq_imask.c linux/arch/sh/kernel/irq_imask.c --- v2.3.99-pre5/linux/arch/sh/kernel/irq_imask.c Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/kernel/irq_imask.c Mon Apr 24 13:54:17 2000 @@ -43,7 +43,7 @@ } static struct hw_interrupt_type imask_irq_type = { - "Interrupt using IMASK of SR register", + "SR.IMASK", startup_imask_irq, shutdown_imask_irq, enable_imask_irq, @@ -56,13 +56,13 @@ { unsigned long __dummy; - asm volatile("ldc %2, $r5_bank\n\t" + asm volatile("ldc %2, $r6_bank\n\t" "stc $sr, %0\n\t" "and #0xf0, %0\n\t" - "shlr8 %0\n\t" - "cmp/eq #0x0f, %0\n\t" - "bt 1f ! CLI-ed\n\t" - "stc $sr, %0\n\t" + "shlr2 %0\n\t" + "cmp/eq #0x3c, %0\n\t" + "bt/s 1f ! CLI-ed\n\t" + " stc $sr, %0\n\t" "and %1, %0\n\t" "or %2, %0\n\t" "ldc %0, $sr\n" diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/irq_onchip.c linux/arch/sh/kernel/irq_onchip.c --- v2.3.99-pre5/linux/arch/sh/kernel/irq_onchip.c Tue Mar 7 14:32:25 2000 +++ linux/arch/sh/kernel/irq_onchip.c Mon Apr 24 13:54:17 2000 @@ -61,7 +61,7 @@ } static struct hw_interrupt_type onChip_irq_type = { - "On-Chip Supporting Module", + "On-Chip-IPR", startup_onChip_irq, shutdown_onChip_irq, enable_onChip_irq, @@ -193,7 +193,7 @@ } static struct hw_interrupt_type onChip2_irq_type = { - "SH7709 Extended On-Chip Supporting Module", + "Extended-IPR", startup_onChip2_irq, shutdown_onChip2_irq, enable_onChip2_irq, diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c --- v2.3.99-pre5/linux/arch/sh/kernel/process.c Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/kernel/process.c Mon Apr 24 13:54:17 2000 @@ -136,20 +136,20 @@ */ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { /* Don't use this in BL=1(cli). Or else, CPU resets! */ - register unsigned long __sc0 __asm__ ("$r0") = __NR_clone; + register unsigned long __sc0 __asm__ ("$r3") = __NR_clone; register unsigned long __sc4 __asm__ ("$r4") = (long) flags | CLONE_VM; register unsigned long __sc5 __asm__ ("$r5") = 0; register unsigned long __sc8 __asm__ ("$r8") = (long) arg; register unsigned long __sc9 __asm__ ("$r9") = (long) fn; - __asm__("trapa #0\n\t" /* Linux/SH system call */ + __asm__("trapa #0x12\n\t" /* Linux/SH system call */ "tst #0xff, $r0\n\t" /* child or parent? */ "bf 1f\n\t" /* parent - jump */ "jsr @$r9\n\t" /* call fn */ " mov $r8, $r4\n\t" /* push argument */ "mov $r0, $r4\n\t" /* return value to arg of exit */ - "mov %2, $r0\n\t" /* exit */ - "trapa #0\n" + "mov %2, $r3\n\t" /* exit */ + "trapa #0x11\n" "1:" : "=z" (__sc0) : "0" (__sc0), "i" (__NR_exit), @@ -194,7 +194,11 @@ fpvalid = tsk->used_math; if (fpvalid) { + unsigned long flags; + + save_and_cli(flags); unlazy_fpu(tsk); + restore_flags(flags); memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu)); } @@ -214,7 +218,11 @@ struct task_struct *tsk = current; if (tsk != &init_task) { + unsigned long flags; + + save_and_cli(flags); unlazy_fpu(tsk); + restore_flags(flags); p->thread.fpu = current->thread.fpu; p->used_math = tsk->used_math; } @@ -263,16 +271,21 @@ void __switch_to(struct task_struct *prev, struct task_struct *next) { #if defined(__SH4__) - if (prev != &init_task) + if (prev != &init_task) { + unsigned long flags; + + save_and_cli(flags); unlazy_fpu(prev); + restore_flags(flags); + } #endif /* - * Restore the kernel stack onto kernel mode register - * k4 (r4_bank1) + * Restore the kernel mode register + * k7 (r7_bank1) */ - asm volatile("ldc %0, $r4_bank" + asm volatile("ldc %0, $r7_bank" : /* no output */ - :"r" ((unsigned long)next+8192)); + :"r" (next)); } asmlinkage int sys_fork(unsigned long r4, unsigned long r5, diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c --- v2.3.99-pre5/linux/arch/sh/kernel/setup.c Tue Mar 7 14:32:25 2000 +++ linux/arch/sh/kernel/setup.c Mon Apr 24 13:54:17 2000 @@ -244,7 +244,7 @@ /* * Reserve the kernel text and - * Reserve the bootmem bitmap.We do this in two steps (first step + * Reserve the bootmem bitmap. We do this in two steps (first step * was init_bootmem()), because this catches the (definitely buggy) * case of us accidentally initializing the bootmem allocator with * an invalid RAM area. @@ -262,17 +262,17 @@ if (LOADER_TYPE && INITRD_START) { if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { reserve_bootmem(INITRD_START+__MEMORY_START, INITRD_SIZE); - initrd_start = - INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0; + initrd_start = + INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0; initrd_end = initrd_start + INITRD_SIZE; } else { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", INITRD_START + INITRD_SIZE, max_low_pfn << PAGE_SHIFT); - initrd_start = 0; - } - } + initrd_start = 0; + } + } #endif #if 0 @@ -301,10 +301,9 @@ #endif #if defined(__SH4__) + /* We already grab/initialized FPU in head.S. Make it consisitent. */ init_task.used_math = 1; init_task.flags |= PF_USEDFPU; - grab_fpu(); - fpu_init(); #endif paging_init(); } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c --- v2.3.99-pre5/linux/arch/sh/kernel/signal.c Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/kernel/signal.c Mon Apr 24 13:54:17 2000 @@ -152,30 +152,36 @@ #if defined(__SH4__) static inline int restore_sigcontext_fpu(struct sigcontext *sc) { - current->used_math = 1; + struct task_struct *tsk = current; + + tsk->used_math = 1; return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0], - sizeof(long)*(NUM_FPU_REGS*2+2)); + sizeof(long)*(16*2+2)); } static inline int save_sigcontext_fpu(struct sigcontext *sc) { struct task_struct *tsk = current; + unsigned long flags; if (!tsk->used_math) { - sc->owend_fp = 0; + sc->sc_ownedfp = 0; return 0; } - sc->owend_fp = 1; + sc->sc_ownedfp = 1; /* This will cause a "finit" to be triggered by the next attempted FPU operation by the 'current' process. */ tsk->used_math = 0; + save_and_cli(flags); unlazy_fpu(tsk); + restore_flags(flags); + return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard, - sizeof(long)*(NUM_FPU_REGS*2+2)); + sizeof(long)*(16*2+2)); } #endif @@ -206,7 +212,7 @@ regs->sr |= SR_FD; /* Release FPU */ clear_fpu(tsk); current->used_math = 0; - __get_user (owned_fp, &context->sc_ownedfp); + __get_user (owned_fp, &sc->sc_ownedfp); if (owned_fp) err |= restore_sigcontext_fpu(sc); } @@ -363,11 +369,11 @@ if (ka->sa.sa_flags & SA_RESTORER) { regs->pr = (unsigned long) ka->sa.sa_restorer; } else { - /* This is : mov #__NR_sigreturn,r0 ; trapa #0 */ + /* This is : mov #__NR_sigreturn,r3 ; trapa #0x10 */ #ifdef __LITTLE_ENDIAN__ - unsigned long code = 0xc300e000 | (__NR_sigreturn); + unsigned long code = 0xc310e300 | (__NR_sigreturn); #else - unsigned long code = 0xe000c300 | (__NR_sigreturn << 16); + unsigned long code = 0xe300c310 | (__NR_sigreturn << 16); #endif regs->pr = (unsigned long) frame->retcode; @@ -437,11 +443,11 @@ if (ka->sa.sa_flags & SA_RESTORER) { regs->pr = (unsigned long) ka->sa.sa_restorer; } else { - /* This is : mov #__NR_rt_sigreturn,r0 ; trapa #0 */ + /* This is : mov #__NR_rt_sigreturn,r3 ; trapa #0x10 */ #ifdef __LITTLE_ENDIAN__ - unsigned long code = 0xc300e000 | (__NR_rt_sigreturn); + unsigned long code = 0xc310e300 | (__NR_rt_sigreturn); #else - unsigned long code = 0xe000c300 | (__NR_rt_sigreturn << 16); + unsigned long code = 0xe300c310 | (__NR_rt_sigreturn << 16); #endif regs->pr = (unsigned long) frame->retcode; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c --- v2.3.99-pre5/linux/arch/sh/kernel/time.c Tue Mar 7 14:32:25 2000 +++ linux/arch/sh/kernel/time.c Mon Apr 24 13:54:17 2000 @@ -33,6 +33,23 @@ #define TMU0_TCR_INIT 0x0020 #define TMU_TSTR_INIT 1 +/* RCR1 Bits */ +#define RCR1_CF 0x80 /* Carry Flag */ +#define RCR1_CIE 0x10 /* Carry Interrupt Enable */ +#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ +#define RCR1_AF 0x01 /* Alarm Flag */ + +/* RCR2 Bits */ +#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */ +#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */ +#define RCR2_RTCEN 0x08 /* ENable RTC */ +#define RCR2_ADJ 0x04 /* ADJustment (30-second) */ +#define RCR2_RESET 0x02 /* Reset bit */ +#define RCR2_START 0x01 /* Start bit */ + +#define RTC_IRQ 22 +#define RTC_IPR_OFFSET 0 + #if defined(__sh3__) #define TMU_TOCR 0xfffffe90 /* Byte access */ #define TMU_TSTR 0xfffffe92 /* Byte access */ @@ -43,9 +60,6 @@ #define FRQCR 0xffffff80 -#define RTC_IRQ 22 -#define RTC_IPR_OFFSET 0 - /* SH-3 RTC */ #define R64CNT 0xfffffec0 #define RSECCNT 0xfffffec2 @@ -74,9 +88,6 @@ #define FRQCR 0xffc00000 -#define RTC_IRQ 22 -#define RTC_IPR_OFFSET 0 - /* SH-4 RTC */ #define R64CNT 0xffc80000 #define RSECCNT 0xffc80004 @@ -149,7 +160,7 @@ int retval = 0; int real_seconds, real_minutes, cmos_minutes; - ctrl_outb(0x02, RCR2); /* reset pre-scaler & stop RTC */ + ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */ cmos_minutes = ctrl_inb(RMINCNT); BCD_TO_BIN(cmos_minutes); @@ -178,7 +189,7 @@ retval = -1; } - ctrl_outb(0x01, RCR2); /* start RTC */ + ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */ return retval; } @@ -283,8 +294,8 @@ unsigned int sec, min, hr, wk, day, mon, yr, yr100; again: - ctrl_outb(0x01, RCR1); /* clear CF bit */ do { + ctrl_outb(0, RCR1); /* Clear CF-bit */ sec = ctrl_inb(RSECCNT); min = ctrl_inb(RMINCNT); hr = ctrl_inb(RHRCNT); @@ -299,7 +310,7 @@ yr = ctrl_inb(RYRCNT); yr100 = (yr == 0x99) ? 0x19 : 0x20; #endif - } while ((ctrl_inb(RCR1) & 0x80) != 0); + } while ((ctrl_inb(RCR1) & RCR1_CF) != 0); BCD_TO_BIN(yr100); BCD_TO_BIN(yr); @@ -313,7 +324,7 @@ hr > 23 || min > 59 || sec > 59) { printk(KERN_ERR "SH RTC: invalid value, resetting to 1 Jan 2000\n"); - ctrl_outb(0x02, RCR2); /* reset, stop */ + ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */ ctrl_outb(0, RSECCNT); ctrl_outb(0, RMINCNT); ctrl_outb(0, RHRCNT); @@ -325,7 +336,7 @@ #else ctrl_outb(0, RYRCNT); #endif - ctrl_outb(0x01, RCR2); /* start */ + ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */ goto again; } @@ -339,13 +350,13 @@ sti(); do {} while (ctrl_inb(R64CNT) != 0); - ctrl_outb(0x11, RCR1); + ctrl_outb(RCR1_CIE, RCR1); /* Enable carry interrupt */ asm volatile( "1:\t" "tst %1,%1\n\t" "bt/s 1b\n\t" " add #1,%0" - : "=&r"(count), "=&z" (__dummy) + : "=r"(count), "=z" (__dummy) : "0" (0), "1" (0)); cli(); /* @@ -373,7 +384,7 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - ctrl_outb(0x01, RCR1); + ctrl_outb(0, RCR1); /* Disable Carry Interrupts */ regs->regs[0] = 1; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c --- v2.3.99-pre5/linux/arch/sh/kernel/traps.c Tue Mar 7 14:32:25 2000 +++ linux/arch/sh/kernel/traps.c Mon Apr 24 13:54:17 2000 @@ -43,7 +43,6 @@ \ asm volatile("stc $r2_bank, %0": "=r" (error_code)); \ sti(); \ - regs.syscall_nr = -1; \ tsk->thread.error_code = error_code; \ tsk->thread.trap_no = trapnr; \ force_sig(signr, tsk); \ @@ -95,9 +94,9 @@ DO_ERROR(12, SIGILL, "reserved instruction", reserved_inst, current) DO_ERROR(13, SIGILL, "illegal slot instruction", illegal_slot_inst, current) -asmlinkage void do_exception_error (unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs regs) +asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) { long ex; asm volatile("stc $r2_bank, %0" : "=r" (ex)); @@ -131,7 +130,8 @@ unsigned long *p; asm("mov $r15, %0" : "=r" (start)); - asm("stc $r4_bank, %0" : "=r" (end)); + asm("stc $r7_bank, %0" : "=r" (end)); + end += 8192; printk("%08lx:%08lx\n", (unsigned long)start, (unsigned long)end); for (p=start; p < end; p++) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c --- v2.3.99-pre5/linux/arch/sh/mm/cache.c Tue Apr 11 15:09:14 2000 +++ linux/arch/sh/mm/cache.c Mon Apr 24 13:54:17 2000 @@ -175,13 +175,13 @@ * * For SH-4, flush (write back) Operand Cache, as Instruction Cache * doesn't have "updated" data. + * + * Assumes that called in interrupt disabled. */ static void cache_wback_all(void) { - unsigned long flags; unsigned long addr, data, i, j; - save_and_cli(flags); jump_to_P2(); for (i=0; imm, vma, start, 1) <= 0) goto bad_area; if (!size) break; @@ -168,7 +168,7 @@ * the fault. */ { - int fault = handle_mm_fault(tsk, vma, address, writeaccess); + int fault = handle_mm_fault(mm, vma, address, writeaccess); if (fault < 0) goto out_of_memory; if (!fault) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v2.3.99-pre5/linux/arch/sparc/kernel/Makefile Tue Apr 11 15:09:14 2000 +++ linux/arch/sparc/kernel/Makefile Wed Apr 12 09:12:34 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.52 1999/12/21 04:02:17 davem Exp $ +# $Id: Makefile,v 1.53 2000/03/31 04:06:19 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/cpu.c linux/arch/sparc/kernel/cpu.c --- v2.3.99-pre5/linux/arch/sparc/kernel/cpu.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/kernel/cpu.c Wed Apr 12 09:12:34 2000 @@ -92,7 +92,7 @@ /* Someone please write the code to support this beast! ;) */ { 2, 0, "Bipolar Integrated Technology - B5010"}, { 3, 0, "LSI Logic Corporation - unknown-type"}, - { 4, 0, "Texas Instruments, Inc. - SuperSparc 50"}, + { 4, 0, "Texas Instruments, Inc. - SuperSparc-(II)"}, /* SparcClassic -- borned STP1010TAB-50*/ { 4, 1, "Texas Instruments, Inc. - MicroSparc"}, { 4, 2, "Texas Instruments, Inc. - MicroSparc II"}, diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.3.99-pre5/linux/arch/sparc/kernel/ptrace.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/kernel/ptrace.c Wed Apr 12 09:16:31 2000 @@ -60,7 +60,7 @@ static void pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr) { - if (current->personality & PER_BSD) + if (current->personality == PER_SUNOS) pt_succ_return (regs, val); else pt_succ_return_linux (regs, val, addr); @@ -155,7 +155,7 @@ pt_error_return(regs, EIO); return; } - if (current->personality & PER_BSD) + if (current->personality == PER_SUNOS) pt_succ_return (regs, v); else pt_succ_return_linux (regs, v, addr); @@ -310,8 +310,8 @@ goto out; } - if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH)) - || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) { + if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) + || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { unsigned long flags; if(child == current) { @@ -349,9 +349,7 @@ pt_succ_return(regs, 0); goto out; } - if (!(child->flags & PF_PTRACED) - && ((current->personality & PER_BSD) && (request != PTRACE_SUNATTACH)) - && (!(current->personality & PER_BSD) && (request != PTRACE_ATTACH))) { + if (!(child->flags & PF_PTRACED)) { pt_error_return(regs, ESRCH); goto out; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v2.3.99-pre5/linux/arch/sparc/kernel/signal.c Tue Apr 11 15:09:14 2000 +++ linux/arch/sparc/kernel/signal.c Wed Apr 12 09:12:34 2000 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.101 2000/01/21 11:38:38 jj Exp $ +/* $Id: signal.c,v 1.102 2000/04/08 02:11:36 davem Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c --- v2.3.99-pre5/linux/arch/sparc/kernel/sun4d_smp.c Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc/kernel/sun4d_smp.c Fri Apr 21 16:37:39 2000 @@ -8,7 +8,6 @@ #include -#include #include #include #include @@ -443,38 +442,14 @@ panic("Bogon SMP message pass."); } -/* Protects counters touched during level14 ticker */ -static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; - -#ifdef CONFIG_PROFILE - -/* 32-bit Sparc specific profiling function. */ -static inline void sparc_do_profile(unsigned long pc) -{ - if(prof_buffer && current->pid) { - extern int _stext; - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - - spin_lock(&ticker_lock); - if(pc < prof_len) - prof_buffer[pc]++; - else - prof_buffer[prof_len - 1]++; - spin_unlock(&ticker_lock); - } -} - -#endif - extern unsigned int prof_multiplier[NR_CPUS]; extern unsigned int prof_counter[NR_CPUS]; extern void update_one_process(struct task_struct *p, unsigned long ticks, unsigned long user, unsigned long system, int cpu); - + +extern void sparc_do_profile(unsigned long pc, unsigned long o7); void smp4d_percpu_timer_interrupt(struct pt_regs *regs) { @@ -493,12 +468,13 @@ show_leds(cpu); } -#ifdef CONFIG_PROFILE if(!user_mode(regs)) - sparc_do_profile(regs->pc); -#endif + sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); + if(!--prof_counter[cpu]) { int user = user_mode(regs); + + irq_enter(cpu, 0); if(current->pid) { update_one_process(current, 1, user, !user, cpu); @@ -507,7 +483,6 @@ current->need_resched = 1; } - spin_lock(&ticker_lock); if(user) { if(current->priority < DEF_PRIORITY) { kstat.cpu_nice++; @@ -520,9 +495,9 @@ kstat.cpu_system++; kstat.per_cpu_system[cpu]++; } - spin_unlock(&ticker_lock); } prof_counter[cpu] = prof_multiplier[cpu]; + irq_exit(cpu, 0); } } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c --- v2.3.99-pre5/linux/arch/sparc/kernel/sun4m_smp.c Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc/kernel/sun4m_smp.c Fri Apr 14 09:37:09 2000 @@ -440,27 +440,6 @@ ccall_info.processors_out[i] = 1; } -/* Protects counters touched during level14 ticker */ -static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; - -/* 32-bit Sparc specific profiling function. */ -static inline void sparc_do_profile(unsigned long pc) -{ - if(prof_buffer && current->pid) { - extern int _stext; - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - - spin_lock(&ticker_lock); - if(pc < prof_len) - prof_buffer[pc]++; - else - prof_buffer[prof_len - 1]++; - spin_unlock(&ticker_lock); - } -} - extern unsigned int prof_multiplier[NR_CPUS]; extern unsigned int prof_counter[NR_CPUS]; @@ -468,6 +447,8 @@ unsigned long user, unsigned long system, int cpu); +extern void sparc_do_profile(unsigned long pc, unsigned long o7); + void smp4m_percpu_timer_interrupt(struct pt_regs *regs) { int cpu = smp_processor_id(); @@ -475,7 +456,7 @@ clear_profile_irq(mid_xlate[cpu]); if(!user_mode(regs)) - sparc_do_profile(regs->pc); + sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); if(!--prof_counter[cpu]) { int user = user_mode(regs); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/sys_solaris.c linux/arch/sparc/kernel/sys_solaris.c --- v2.3.99-pre5/linux/arch/sparc/kernel/sys_solaris.c Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc/kernel/sys_solaris.c Thu Apr 13 08:11:48 2000 @@ -23,9 +23,7 @@ int ret; lock_kernel(); - put_exec_domain(current->exec_domain); - current->personality = PER_SVR4; - current->exec_domain = lookup_exec_domain(PER_SVR4); + set_personality(PER_SVR4); if (current->exec_domain && current->exec_domain->handler){ current->exec_domain->handler (0, regs); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.3.99-pre5/linux/arch/sparc/kernel/sys_sunos.c Tue Apr 11 15:09:14 2000 +++ linux/arch/sparc/kernel/sys_sunos.c Wed Apr 26 09:25:17 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.118 2000/03/26 11:28:56 davem Exp $ +/* $Id: sys_sunos.c,v 1.121 2000/04/13 00:55:48 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -50,6 +50,7 @@ #include #include #include +#include #include /* for sunos_select */ @@ -69,7 +70,6 @@ down(¤t->mm->mmap_sem); lock_kernel(); - current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { static int cnt; if (cnt++ < 10) @@ -170,7 +170,7 @@ */ if (brk <= current->mm->brk) { current->mm->brk = brk; - do_munmap(newbrk, oldbrk-newbrk); + do_munmap(current->mm, newbrk, oldbrk-newbrk); goto out; } /* @@ -582,7 +582,6 @@ /* SunOS binaries expect that select won't change the tvp contents */ lock_kernel(); - current->personality |= STICKY_TIMEOUTS; ret = sys_select (width, inp, outp, exp, tvp); if (ret == -EINTR && tvp) { time_t sec, usec; @@ -712,7 +711,7 @@ * address to create a socket and bind it to a reserved * port on this system */ - if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount)) + if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount))) return -EFAULT; server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); @@ -803,14 +802,14 @@ dev_fname = getname(data); } else if(strcmp(type_page, "nfs") == 0) { ret = sunos_nfs_mount (dir_page, flags, data); - goto out2 + goto out2; } else if(strcmp(type_page, "ufs") == 0) { printk("Warning: UFS filesystem mounts unsupported.\n"); ret = -ENODEV; - goto out2 + goto out2; } else if(strcmp(type_page, "proc")) { ret = -ENODEV; - goto out2 + goto out2; } ret = PTR_ERR(dev_fname); if (IS_ERR(dev_fname)) @@ -1054,18 +1053,6 @@ return rval; } -asmlinkage int sunos_open(const char *filename, int flags, int mode) -{ - int ret; - - lock_kernel(); - current->personality |= PER_BSD; - ret = sys_open (filename, flags, mode); - unlock_kernel(); - return ret; -} - - #define SUNOS_EWOULDBLOCK 35 /* see the sunos man page read(2v) for an explanation @@ -1199,8 +1186,6 @@ { struct k_sigaction new_ka, old_ka; int ret; - - current->personality |= PER_BSD; if(act) { old_sigset_t mask; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S --- v2.3.99-pre5/linux/arch/sparc/kernel/systbls.S Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc/kernel/systbls.S Fri Apr 14 09:37:09 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.96 2000/03/15 02:43:32 davem Exp $ +/* $Id: systbls.S,v 1.97 2000/04/13 00:55:49 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -79,7 +79,7 @@ .globl sunos_sys_table sunos_sys_table: /*0*/ .long sunos_indir, sys_exit, sys_fork - .long sunos_read, sunos_write, sunos_open + .long sunos_read, sunos_write, sys_open .long sys_close, sunos_wait4, sys_creat .long sys_link, sys_unlink, sunos_execv .long sys_chdir, sunos_nosys, sys_mknod diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c --- v2.3.99-pre5/linux/arch/sparc/kernel/time.c Thu Feb 10 17:11:05 2000 +++ linux/arch/sparc/kernel/time.c Fri Apr 14 09:37:09 2000 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.53 2000/02/09 21:11:04 davem Exp $ +/* $Id: time.c,v 1.54 2000/04/13 08:14:30 anton Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -70,6 +70,37 @@ #endif +static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; + +/* 32-bit Sparc specific profiling function. */ +void sparc_do_profile(unsigned long pc, unsigned long o7) +{ + if(prof_buffer && current->pid) { + extern int _stext; + extern int __copy_user_begin, __copy_user_end; + extern int __atomic_begin, __atomic_end; + extern int __bitops_begin, __bitops_end; + + if ((pc >= (unsigned long) &__copy_user_begin && + pc < (unsigned long) &__copy_user_end) || + (pc >= (unsigned long) &__atomic_begin && + pc < (unsigned long) &__atomic_end) || + (pc >= (unsigned long) &__bitops_begin && + pc < (unsigned long) &__bitops_end)) + pc = o7; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + + spin_lock(&ticker_lock); + if(pc < prof_len) + prof_buffer[pc]++; + else + prof_buffer[prof_len - 1]++; + spin_unlock(&ticker_lock); + } +} + __volatile__ unsigned int *master_l10_counter; __volatile__ unsigned int *master_l10_limit; @@ -81,6 +112,11 @@ { /* last time the cmos clock got updated */ static long last_rtc_update=0; + +#ifndef __SMP__ + if(!user_mode(regs)) + sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); +#endif #ifdef CONFIG_SUN4 if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) || diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile --- v2.3.99-pre5/linux/arch/sparc/lib/Makefile Tue Apr 11 15:09:14 2000 +++ linux/arch/sparc/lib/Makefile Wed Apr 12 09:12:34 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.33 2000/03/16 00:52:07 anton Exp $ +# $Id: Makefile,v 1.34 2000/03/31 04:06:20 davem Exp $ # Makefile for Sparc library files.. # diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/lib/atomic.S linux/arch/sparc/lib/atomic.S --- v2.3.99-pre5/linux/arch/sparc/lib/atomic.S Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc/lib/atomic.S Fri Apr 14 09:37:09 2000 @@ -10,6 +10,9 @@ .text .align 4 + .globl __atomic_begin +__atomic_begin: + #ifndef __SMP__ .globl ___xchg32_sun4c ___xchg32_sun4c: @@ -92,3 +95,6 @@ nop; nop; nop; ! Let the bits set jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h mov %g4, %o7 ! Restore %o7 + + .globl __atomic_end +__atomic_end: diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/lib/bitops.S linux/arch/sparc/lib/bitops.S --- v2.3.99-pre5/linux/arch/sparc/lib/bitops.S Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc/lib/bitops.S Fri Apr 14 09:37:09 2000 @@ -10,6 +10,9 @@ .text .align 4 + .globl __bitops_begin +__bitops_begin: + /* Take bits in %g2 and set them in word at %g1, * return whether bits were set in original value * in %g2. %g4 holds value to restore into %o7 @@ -159,3 +162,6 @@ nop; nop; nop jmpl %o7, %g0 mov %g4, %o7 + + .globl __bitops_end +__bitops_end: diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/lib/copy_user.S linux/arch/sparc/lib/copy_user.S --- v2.3.99-pre5/linux/arch/sparc/lib/copy_user.S Tue Jan 11 22:31:38 2000 +++ linux/arch/sparc/lib/copy_user.S Fri Apr 14 09:37:09 2000 @@ -112,6 +112,9 @@ .text .align 4 + .globl __copy_user_begin +__copy_user_begin: + .globl C_LABEL(__copy_user) dword_align: andcc %o1, 1, %g0 @@ -482,3 +485,6 @@ sub %o0, %g3, %o0 ba fixupretl add %g3, %o2, %g3 + + .globl __copy_user_end +__copy_user_end: diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile --- v2.3.99-pre5/linux/arch/sparc/mm/Makefile Tue Apr 11 15:09:14 2000 +++ linux/arch/sparc/mm/Makefile Wed Apr 12 09:12:35 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.36 2000/01/29 01:09:05 anton Exp $ +# $Id: Makefile,v 1.37 2000/03/31 04:06:22 davem Exp $ # Makefile for the linux Sparc-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v2.3.99-pre5/linux/arch/sparc/mm/fault.c Sun Feb 20 21:12:38 2000 +++ linux/arch/sparc/mm/fault.c Tue Apr 25 17:52:01 2000 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.114 2000/02/14 04:52:36 jj Exp $ +/* $Id: fault.c,v 1.115 2000/04/25 04:13:25 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -250,7 +250,7 @@ * the fault. */ { - int fault = handle_mm_fault(tsk, vma, address, write); + int fault = handle_mm_fault(mm, vma, address, write); if (fault < 0) goto out_of_memory; if (!fault) @@ -450,7 +450,7 @@ if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - if (!handle_mm_fault(current, vma, address, write)) + if (!handle_mm_fault(mm, vma, address, write)) goto do_sigbus; up(&mm->mmap_sem); return; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.3.99-pre5/linux/arch/sparc/mm/sun4c.c Tue Apr 11 15:09:14 2000 +++ linux/arch/sparc/mm/sun4c.c Wed Apr 12 09:12:35 2000 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.190 2000/02/14 04:52:34 jj Exp $ +/* $Id: sun4c.c,v 1.191 2000/04/08 02:11:41 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.3.99-pre5/linux/arch/sparc64/config.in Tue Apr 11 15:09:14 2000 +++ linux/arch/sparc64/config.in Mon Apr 24 13:59:57 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.107 2000/03/29 11:56:51 davem Exp $ +# $Id: config.in,v 1.108 2000/04/18 05:20:45 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -187,6 +187,7 @@ fi fi dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI + dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI fi endmenu diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.3.99-pre5/linux/arch/sparc64/defconfig Tue Apr 11 15:09:14 2000 +++ linux/arch/sparc64/defconfig Mon Apr 24 13:59:57 2000 @@ -223,8 +223,8 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC6210 is not set -# CONFIG_AEC6210_TUNING 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_AMD7409 is not set @@ -246,6 +246,7 @@ # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_VIA82CXXX_TUNING is not set # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y CONFIG_BLK_DEV_IDE_MODES=y @@ -293,6 +294,7 @@ # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set CONFIG_SCSI_QLOGIC_ISP=y +CONFIG_SCSI_QLOGIC_FC=m # # Fibre Channel support @@ -370,6 +372,7 @@ CONFIG_AUTOFS_FS=m CONFIG_AUTOFS4_FS=m # CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set CONFIG_AFFS_FS=m # CONFIG_HFS_FS is not set CONFIG_BFS_FS=m @@ -379,47 +382,52 @@ CONFIG_VFAT_FS=m CONFIG_EFS_FS=m CONFIG_CRAMFS=m +CONFIG_RAMFS=m CONFIG_ISO9660_FS=m -# CONFIG_JOLIET is not set +CONFIG_JOLIET=y CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y # CONFIG_DEVFS_FS 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=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m -# CONFIG_SYSV_FS_WRITE is not set +CONFIG_SYSV_FS_WRITE=y CONFIG_UDF_FS=m -# CONFIG_UDF_RW is not set +CONFIG_UDF_RW=y CONFIG_UFS_FS=m -# CONFIG_UFS_FS_WRITE is not set +CONFIG_UFS_FS_WRITE=y # # Network File Systems # CONFIG_CODA_FS=m CONFIG_NFS_FS=y +CONFIG_NFS_V3=y # CONFIG_ROOT_NFS is not set CONFIG_NFSD=m -# CONFIG_NFSD_V3 is not set +CONFIG_NFSD_V3=y CONFIG_SUNRPC=y CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y CONFIG_SMB_FS=m CONFIG_NCP_FS=m -# 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_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_MOUNT_SUBDIR=y +CONFIG_NCPFS_NDS_DOMAINS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y # # Partition Types diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.3.99-pre5/linux/arch/sparc64/kernel/Makefile Tue Apr 11 15:09:14 2000 +++ linux/arch/sparc64/kernel/Makefile Wed Apr 12 09:12:35 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.52 2000/03/19 07:00:29 ecd Exp $ +# $Id: Makefile,v 1.53 2000/03/31 04:06:22 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/binfmt_aout32.c Mon Mar 27 08:08:22 2000 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Thu Apr 13 08:11:48 2000 @@ -198,7 +198,6 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct exec ex; - int fd; unsigned long error; unsigned long fd_offset; unsigned long rlim; @@ -230,7 +229,7 @@ return retval; /* OK, This is the point of no return */ - current->personality = PER_LINUX; + set_personality(PER_SUNOS); current->mm->end_code = ex.a_text + (current->mm->start_code = N_TXTADDR(ex)); @@ -270,15 +269,8 @@ error_time = jiffies; } - fd = get_unused_fd(); - if (fd < 0) - return fd; - get_file(bprm->file); - fd_install(fd, bprm->file); - if (!bprm->file->f_op->mmap) { loff_t pos = fd_offset; - sys_close(fd); do_brk(0, ex.a_text+ex.a_data); bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex), ex.a_text+ex.a_data, &pos); @@ -291,7 +283,6 @@ fd_offset); if (error != N_TXTADDR(ex)) { - sys_close(fd); send_sig(SIGKILL, current, 0); return error; } @@ -300,20 +291,13 @@ PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); - sys_close(fd); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } } beyond_if: - put_exec_domain(current->exec_domain); - if (current->binfmt && current->binfmt->module) - __MOD_DEC_USE_COUNT(current->binfmt->module); - current->exec_domain = lookup_exec_domain(current->personality); - current->binfmt = &aout32_format; - if (current->binfmt && current->binfmt->module) - __MOD_INC_USE_COUNT(current->binfmt->module); + set_binfmt(&aout32_format); set_brk(current->mm->start_brk, current->mm->brk); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/ioctl32.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/ioctl32.c Fri Apr 14 09:37:09 2000 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.87 2000/03/30 02:09:07 davem Exp $ +/* $Id: ioctl32.c,v 1.88 2000/04/14 10:10:34 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -1816,6 +1816,7 @@ #define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32) #define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32) #define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32) +#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32) static struct { unsigned int cmd32; @@ -1836,7 +1837,8 @@ { ATM_GETSTAT32, ATM_GETSTAT }, { ATM_GETSTATZ32, ATM_GETSTATZ }, { ATM_GETLOOP32, ATM_GETLOOP }, - { ATM_SETLOOP32, ATM_SETLOOP } + { ATM_SETLOOP32, ATM_SETLOOP }, + { ATM_QUERYLOOP32, ATM_QUERYLOOP } }; #define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0])) @@ -1996,6 +1998,7 @@ case ATM_GETSTATZ: case ATM_GETLOOP: case ATM_SETLOOP: + case ATM_QUERYLOOP: return do_atmif_sioc(fd, cmd, arg); } @@ -3110,6 +3113,7 @@ HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl) HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl) +HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl) HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/irq.c Thu Mar 2 14:36:22 2000 +++ linux/arch/sparc64/kernel/irq.c Mon Apr 24 13:59:57 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.85 2000/03/02 02:00:24 davem Exp $ +/* $Id: irq.c,v 1.86 2000/04/15 06:02:50 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -538,82 +538,43 @@ } /* Only uniprocessor needs this IRQ/BH locking depth, on SMP it - * lives in the per-cpu structure for cache reasons. + * lives in the brlock table for cache reasons. */ #ifndef __SMP__ unsigned int local_irq_count; unsigned int local_bh_count; - -#define irq_enter(cpu, irq) (local_irq_count++) -#define irq_exit(cpu, irq) (local_irq_count--) #else /* Who has global_irq_lock. */ unsigned char global_irq_holder = NO_PROC_ID; -/* This protects IRQ's. */ -spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; - -/* Global IRQ locking depth. */ -atomic_t global_irq_count = ATOMIC_INIT(0); - -#define irq_enter(cpu, irq) \ -do { hardirq_enter(cpu); \ - spin_unlock_wait(&global_irq_lock); \ -} while(0) -#define irq_exit(cpu, irq) hardirq_exit(cpu) - static void show(char * str) { int cpu = smp_processor_id(); + int i; printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [%u %u]\n", - atomic_read(&global_irq_count), - cpu_data[0].irq_count, cpu_data[1].irq_count); - printk("bh: %d [%u %u]\n", - (spin_is_locked(&global_bh_lock) ? 1 : 0), - cpu_data[0].bh_count, cpu_data[1].bh_count); + printk("irq: %d [ ", irqs_running()); + for (i = 0; i < smp_num_cpus; i++) + printk("%u ", __brlock_array[i][BR_GLOBALIRQ_LOCK]); + printk("]\nbh: %d [ ", + (spin_is_locked(&global_bh_lock) ? 1 : 0)); + for (i = 0; i < smp_num_cpus; i++) + printk("%u ", cpu_data[i].bh_count); + printk("]\n"); } #define MAXCOUNT 100000000 +#if 0 #define SYNC_OTHER_ULTRAS(x) udelay(x+1) - -static inline void wait_on_irq(int cpu) -{ - int count = MAXCOUNT; - for(;;) { - membar("#LoadLoad"); - if (!atomic_read (&global_irq_count)) { - if (local_bh_count || ! spin_is_locked(&global_bh_lock)) - break; - } - spin_unlock (&global_irq_lock); - membar("#StoreLoad | #StoreStore"); - for(;;) { - if (!--count) { - show("wait_on_irq"); - count = ~0; - } - __sti(); - SYNC_OTHER_ULTRAS(cpu); - __cli(); - if (atomic_read(&global_irq_count)) - continue; - if (spin_is_locked (&global_irq_lock)) - continue; - if (!local_bh_count && spin_is_locked (&global_bh_lock)) - continue; - if (spin_trylock(&global_irq_lock)) - break; - } - } -} +#else +#define SYNC_OTHER_ULTRAS(x) membar("#Sync"); +#endif void synchronize_irq(void) { - if (atomic_read(&global_irq_count)) { + if (irqs_running()) { cli(); sti(); } @@ -621,15 +582,37 @@ static inline void get_irqlock(int cpu) { - if (! spin_trylock(&global_irq_lock)) { - if ((unsigned char) cpu == global_irq_holder) - return; - do { - while (spin_is_locked (&global_irq_lock)) - membar("#LoadLoad"); - } while(! spin_trylock(&global_irq_lock)); + int count; + + if ((unsigned char)cpu == global_irq_holder) + return; + + count = MAXCOUNT; +again: + br_write_lock(BR_GLOBALIRQ_LOCK); + for (;;) { + spinlock_t *lock; + + if (!irqs_running() && + (local_bh_count || !spin_is_locked(&global_bh_lock))) + break; + + br_write_unlock(BR_GLOBALIRQ_LOCK); + lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock; + while (irqs_running() || + spin_is_locked(lock) || + (!local_bh_count && spin_is_locked(&global_bh_lock))) { + if (!--count) { + show("wait_on_irq"); + count = (~0 >> 1); + } + __sti(); + SYNC_OTHER_ULTRAS(cpu); + __cli(); + } + goto again; } - wait_on_irq(cpu); + global_irq_holder = cpu; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/pci_common.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/pci_common.c Wed Apr 26 12:13:16 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_common.c,v 1.7 2000/03/25 05:18:11 davem Exp $ +/* $Id: pci_common.c,v 1.11 2000/04/26 10:48:02 davem Exp $ * pci_common.c: PCI controller common support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -66,6 +66,27 @@ kfree(pdev); } +/* Older versions of OBP on PCI systems encode 64-bit MEM + * space assignments incorrectly, this fixes them up. + */ +static void __init fixup_obp_assignments(struct pcidev_cookie *pcp) +{ + int i; + + for (i = 0; i < pcp->num_prom_assignments; i++) { + struct linux_prom_pci_registers *ap; + int space; + + ap = &pcp->prom_assignments[i]; + space = ap->phys_hi >> 24; + if ((space & 0x3) == 2 && + (space & 0x4) != 0) { + ap->phys_hi &= ~(0x7 << 24); + ap->phys_hi |= 0x3 << 24; + } + } +} + /* Fill in the PCI device cookie sysdata for the given * PCI device. This cookie is the means by which one * can get to OBP and PCI controller specific information @@ -147,6 +168,8 @@ (err / sizeof(pcp->prom_assignments[0])); } + fixup_obp_assignments(pcp); + pdev->sysdata = pcp; } @@ -219,10 +242,15 @@ return &pbm->mem_space; case 3: + /* 64-bit MEM space, these are allocated out of + * the 32-bit mem_space range for the PBM, ie. + * we just zero out the upper 32-bits. + */ + return &pbm->mem_space; + default: - /* 64-bit MEM space, unsupported. */ - printk("PCI: 64-bit MEM assignment??? " - "Tell davem@redhat.com about it!\n"); + printk("PCI: What is resource space %x? " + "Tell davem@redhat.com about it!\n", space); return NULL; }; } @@ -231,6 +259,7 @@ __init get_device_resource(struct linux_prom_pci_registers *ap, struct pci_dev *pdev) { + struct resource *res; int breg = (ap->phys_hi & 0xff); int space = (ap->phys_hi >> 24) & 3; @@ -240,7 +269,8 @@ if (space != 2) bad_assignment(ap, NULL, 0); - return &pdev->resource[PCI_ROM_RESOURCE]; + res = &pdev->resource[PCI_ROM_RESOURCE]; + break; case PCI_BASE_ADDRESS_0: case PCI_BASE_ADDRESS_1: @@ -248,12 +278,16 @@ case PCI_BASE_ADDRESS_3: case PCI_BASE_ADDRESS_4: case PCI_BASE_ADDRESS_5: - return &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4]; + res = &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4]; + break; default: bad_assignment(ap, NULL, 0); - return NULL; + res = NULL; + break; }; + + return res; } static void __init pdev_record_assignments(struct pci_pbm_info *pbm, @@ -281,6 +315,31 @@ if ((res->start & 0xffffffffUL) != ap->phys_lo) bad_assignment(ap, res, 1); + /* If it is a 64-bit MEM space assignment, verify that + * the resource is too and that the upper 32-bits match. + */ + if (((ap->phys_hi >> 24) & 3) == 3) { + if (((res->flags & IORESOURCE_MEM) == 0) || + ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) + != PCI_BASE_ADDRESS_MEM_TYPE_64)) + bad_assignment(ap, res, 1); + if ((res->start >> 32) != ap->phys_mid) + bad_assignment(ap, res, 1); + + /* PBM cannot generate cpu initiated PIOs + * to the full 64-bit space. Therefore the + * upper 32-bits better be zero. If it is + * not, just skip it and we will assign it + * properly ourselves. + */ + if ((res->start >> 32) != 0UL) { + printk(KERN_ERR "PCI: OBP assigns out of range MEM address " + "%016lx for region %ld on device %s\n", + res->start, (res - &pdev->resource[0]), pdev->name); + continue; + } + } + /* Adjust the resource into the physical address space * of this PBM. */ @@ -425,13 +484,21 @@ return 0; /* If we are underneath a PCI bridge, use PROM register - * property of parent bridge. + * property of the parent bridge which is closest to + * the PBM. */ if (pdev->bus->number != pbm->pci_first_busno) { struct pcidev_cookie *bus_pcp; + struct pci_dev *pwalk; int offset; - bus_pcp = pdev->bus->self->sysdata; + pwalk = pdev->bus->self; + while (pwalk->bus && + pwalk->bus->number != pbm->pci_first_busno) + pwalk = pwalk->bus->self; + + bus_pcp = pwalk->bus->self->sysdata; + pregs = bus_pcp->prom_regs; offset = prom_getint(bus_pcp->prom_node, "fcode-rom-offset"); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/pci_psycho.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/pci_psycho.c Mon Apr 24 13:59:58 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.15 2000/03/25 05:18:11 davem Exp $ +/* $Id: pci_psycho.c,v 1.16 2000/04/15 10:06:16 davem Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1074,22 +1074,34 @@ { struct pcidev_cookie *pcp = pdev->sysdata; struct pci_pbm_info *pbm = pcp->pbm; - struct resource *res = &pdev->resource[resource]; - struct resource *root; + struct resource *res, *root; u32 reg; - int where, size; + int where, size, is_64bit; + res = &pdev->resource[resource]; + where = PCI_BASE_ADDRESS_0 + (resource * 4); + + is_64bit = 0; if (res->flags & IORESOURCE_IO) root = &pbm->io_space; - else + else { root = &pbm->mem_space; + if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) + == PCI_BASE_ADDRESS_MEM_TYPE_64) + is_64bit = 1; + } - where = PCI_BASE_ADDRESS_0 + (resource * 4); size = res->end - res->start; pci_read_config_dword(pdev, where, ®); reg = ((reg & size) | (((u32)(res->start - root->start)) & ~size)); pci_write_config_dword(pdev, where, reg); + + /* This knows that the upper 32-bits of the address + * must be zero. Our PCI common layer enforces this. + */ + if (is_64bit) + pci_write_config_dword(pdev, where + 4, 0); } /* We have to do the config space accesses by hand, thus... */ diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/pci_sabre.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/pci_sabre.c Mon Apr 24 13:59:58 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.16 2000/03/25 05:18:12 davem Exp $ +/* $Id: pci_sabre.c,v 1.19 2000/04/15 13:07:51 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1012,22 +1012,35 @@ struct pcidev_cookie *pcp = pdev->sysdata; struct pci_pbm_info *pbm = pcp->pbm; struct pci_controller_info *p = pbm->parent; - struct resource *res = &pdev->resource[resource]; + struct resource *res; unsigned long base; u32 reg; - int where, size; + int where, size, is_64bit; + res = &pdev->resource[resource]; + where = PCI_BASE_ADDRESS_0 + (resource * 4); + + is_64bit = 0; if (res->flags & IORESOURCE_IO) base = p->controller_regs + SABRE_IOSPACE; - else + else { base = p->controller_regs + SABRE_MEMSPACE; + if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) + == PCI_BASE_ADDRESS_MEM_TYPE_64) + is_64bit = 1; + } - where = PCI_BASE_ADDRESS_0 + (resource * 4); size = res->end - res->start; pci_read_config_dword(pdev, where, ®); reg = ((reg & size) | (((u32)(res->start - base)) & ~size)); pci_write_config_dword(pdev, where, reg); + + /* This knows that the upper 32-bits of the address + * must be zero. Our PCI common layer enforces this. + */ + if (is_64bit) + pci_write_config_dword(pdev, where + 4, 0); } static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) @@ -1050,6 +1063,20 @@ /* Status register bits are "write 1 to clear". */ sabre_write_word(pdev, PCI_STATUS, 0xffff); sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff); + + /* Use a primary/seconday latency timer value + * of 64. + */ + sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); + sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); + + /* Enable reporting/forwarding of master aborts, + * parity, and SERR. + */ + sabre_write_byte(pdev, PCI_BRIDGE_CONTROL, + (PCI_BRIDGE_CTL_PARITY | + PCI_BRIDGE_CTL_SERR | + PCI_BRIDGE_CTL_MASTER_ABORT)); } } } @@ -1086,17 +1113,6 @@ sabre_bus = pci_scan_bus(p->pci_first_busno, p->pci_ops, &p->pbm_A); - - { - unsigned int devfn; - u8 *addr; - - devfn = PCI_DEVFN(0, 0); - addr = sabre_pci_config_mkaddr(&p->pbm_A, 0, - devfn, PCI_LATENCY_TIMER); - pci_config_write8(addr, 32); - } - apb_init(p, sabre_bus); walk = &sabre_bus->children; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/power.c linux/arch/sparc64/kernel/power.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/power.c Wed Dec 29 13:13:14 1999 +++ linux/arch/sparc64/kernel/power.c Fri Apr 14 09:37:09 2000 @@ -1,4 +1,4 @@ -/* $Id: power.c,v 1.5 1999/12/19 23:28:00 davem Exp $ +/* $Id: power.c,v 1.6 2000/04/13 00:59:59 davem Exp $ * power.c: Power management driver. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -55,8 +55,7 @@ static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; char *argv[] = { "/usr/bin/shutdown", "-h", "now", NULL }; - current->session = 1; - current->pgrp = 1; + daemonize(); sprintf(current->comm, "powerd"); again: diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/process.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/process.c Mon Apr 24 13:59:58 2000 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.105 2000/03/26 09:13:48 davem Exp $ +/* $Id: process.c,v 1.106 2000/04/15 06:02:50 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -269,9 +269,8 @@ unsigned long flags; spin_lock_irqsave(®dump_lock, flags); - printk("CPU[%d]: local_irq_count[%u] global_irq_count[%d]\n", - smp_processor_id(), local_irq_count, - atomic_read(&global_irq_count)); + printk("CPU[%d]: local_irq_count[%u] irqs_running[%d]\n", + smp_processor_id(), local_irq_count, irqs_running()); #endif printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate, regs->tpc, regs->tnpc, regs->y); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/ptrace.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/kernel/ptrace.c Wed Apr 12 09:16:32 2000 @@ -68,7 +68,7 @@ static void pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr) { - if (current->personality & PER_BSD) + if (current->personality == PER_SUNOS) pt_succ_return (regs, val); else pt_succ_return_linux (regs, val, addr); @@ -164,8 +164,8 @@ goto out; } - if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH)) - || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) { + if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) + || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { unsigned long flags; if(child == current) { @@ -203,9 +203,7 @@ pt_succ_return(regs, 0); goto out; } - if (!(child->flags & PF_PTRACED) - && ((current->personality & PER_BSD) && (request != PTRACE_SUNATTACH)) - && (!(current->personality & PER_BSD) && (request != PTRACE_ATTACH))) { + if (!(child->flags & PF_PTRACED)) { pt_error_return(regs, ESRCH); goto out; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/sbus.c Fri Mar 10 16:40:41 2000 +++ linux/arch/sparc64/kernel/sbus.c Fri Apr 14 09:37:09 2000 @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.10 2000/03/10 07:52:08 davem Exp $ +/* $Id: sbus.c,v 1.11 2000/04/14 09:13:04 davem Exp $ * sbus.c: UltraSparc SBUS controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -315,7 +315,7 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size, int dir) { struct sbus_iommu *iommu = sdev->bus->iommu; - unsigned long npages, phys_base, flags; + unsigned long npages, pbase, flags; iopte_t *iopte; u32 dma_base, offset; unsigned long iopte_bits; @@ -323,10 +323,10 @@ if (dir == SBUS_DMA_NONE) BUG(); - phys_base = (unsigned long) ptr; - offset = (u32) (phys_base & ~PAGE_MASK); - size = (PAGE_ALIGN(phys_base + size) - (phys_base & PAGE_MASK)); - phys_base = (unsigned long) __pa(phys_base & PAGE_MASK); + pbase = (unsigned long) ptr; + offset = (u32) (pbase & ~PAGE_MASK); + size = (PAGE_ALIGN(pbase + size) - (pbase & PAGE_MASK)); + pbase = (unsigned long) __pa(pbase & PAGE_MASK); spin_lock_irqsave(&iommu->lock, flags); npages = size >> PAGE_SHIFT; @@ -337,8 +337,8 @@ if (dir != SBUS_DMA_TODEVICE) iopte_bits |= IOPTE_WRITE; while (npages--) { - *iopte++ = __iopte(iopte_bits | (phys_base & IOPTE_PAGE)); - phys_base += PAGE_SIZE; + *iopte++ = __iopte(iopte_bits | (pbase & IOPTE_PAGE)); + pbase += PAGE_SIZE; } npages = size >> PAGE_SHIFT; spin_unlock_irqrestore(&iommu->lock, flags); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/signal.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/signal.c Wed Apr 12 09:12:35 2000 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.48 1999/12/15 22:24:52 davem Exp $ +/* $Id: signal.c,v 1.49 2000/04/08 02:11:46 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/signal32.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/signal32.c Fri Apr 14 09:37:09 2000 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.60 2000/02/25 06:02:37 jj Exp $ +/* $Id: signal32.c,v 1.62 2000/04/12 08:10:19 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -750,8 +750,7 @@ goto sigsegv; if(pte_present(*ptep)) { - unsigned long page = (unsigned long) - __va(pte_pagenr(*ptep) << PAGE_SHIFT); + unsigned long page = page_address(pte_page(*ptep)); __asm__ __volatile__(" membar #StoreStore @@ -1176,8 +1175,7 @@ goto sigsegv; if(pte_present(*ptep)) { - unsigned long page = (unsigned long) - __va(pte_pagenr(*ptep) << PAGE_SHIFT); + unsigned long page = page_address(pte_page(*ptep)); __asm__ __volatile__(" membar #StoreStore diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/smp.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/smp.c Mon Apr 24 13:59:58 2000 @@ -87,7 +87,6 @@ { int i; - cpu_data[id].irq_count = 0; cpu_data[id].bh_count = 0; /* multiplier and counter set by smp_setup_percpu_timer() */ @@ -627,33 +626,7 @@ smp_cross_call(&xcall_promstop, 0, 0, 0); } -static inline void sparc64_do_profile(unsigned long pc, unsigned long o7) -{ - if (prof_buffer && current->pid) { - extern int _stext; - extern int rwlock_impl_begin, rwlock_impl_end; - extern int atomic_impl_begin, atomic_impl_end; - extern int __memcpy_begin, __memcpy_end; - extern int __bitops_begin, __bitops_end; - - if ((pc >= (unsigned long) &atomic_impl_begin && - pc < (unsigned long) &atomic_impl_end) || - (pc >= (unsigned long) &rwlock_impl_begin && - pc < (unsigned long) &rwlock_impl_end) || - (pc >= (unsigned long) &__memcpy_begin && - pc < (unsigned long) &__memcpy_end) || - (pc >= (unsigned long) &__bitops_begin && - pc < (unsigned long) &__bitops_end)) - pc = o7; - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - - if(pc >= prof_len) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } -} +extern void sparc64_do_profile(unsigned long pc, unsigned long o7); static unsigned long current_tick_offset; @@ -682,40 +655,29 @@ clear_softint((1UL << 0)); do { - if(!user) + if (!user) sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]); - if(!--prof_counter(cpu)) - { + if (!--prof_counter(cpu)) { if (cpu == boot_cpu_id) { -/* XXX Keep this in sync with irq.c --DaveM */ -#define irq_enter(cpu, irq) \ -do { hardirq_enter(cpu); \ - spin_unlock_wait(&global_irq_lock); \ -} while(0) -#define irq_exit(cpu, irq) hardirq_exit(cpu) - irq_enter(cpu, 0); - kstat.irqs[cpu][0]++; + kstat.irqs[cpu][0]++; timer_tick_interrupt(regs); irq_exit(cpu, 0); - -#undef irq_enter -#undef irq_exit } - if(current->pid) { + if (current->pid) { unsigned int *inc, *inc2; update_one_process(current, 1, user, !user, cpu); - if(--current->counter <= 0) { + if (--current->counter <= 0) { current->counter = 0; current->need_resched = 1; } - if(user) { - if(current->priority < DEF_PRIORITY) { + if (user) { + if (current->priority < DEF_PRIORITY) { inc = &kstat.cpu_nice; inc2 = &kstat.per_cpu_nice[cpu]; } else { @@ -862,7 +824,7 @@ static void __init smp_tune_scheduling (void) { - unsigned long flush_base, flags, *p; + unsigned long orig_flush_base, flush_base, flags, *p; unsigned int ecache_size, order; cycles_t tick1, tick2, raw; @@ -881,7 +843,8 @@ "ecache-size", (512 * 1024)); if (ecache_size > (4 * 1024 * 1024)) ecache_size = (4 * 1024 * 1024); - flush_base = __get_free_pages(GFP_KERNEL, order = get_order(ecache_size)); + orig_flush_base = flush_base = + __get_free_pages(GFP_KERNEL, order = get_order(ecache_size)); if (flush_base != 0UL) { __save_and_cli(flags); @@ -923,7 +886,7 @@ */ cacheflush_time = (raw - (raw >> 2)); - free_pages(flush_base, order); + free_pages(orig_flush_base, order); } else { cacheflush_time = ((ecache_size << 2) + (ecache_size << 1)); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/sparc64_ksyms.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Apr 24 13:59:58 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.80 2000/03/27 10:38:47 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.83 2000/04/19 08:38:25 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -81,6 +81,8 @@ extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg); extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *); extern long sparc32_open(const char * filename, int flags, int mode); +extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *)); +extern int unregister_ioctl32_conversion(unsigned int cmd); extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); @@ -129,8 +131,6 @@ /* Hard IRQ locking */ EXPORT_SYMBOL(global_irq_holder); -EXPORT_SYMBOL(global_irq_lock); -EXPORT_SYMBOL(global_irq_count); EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL_PRIVATE(global_cli); EXPORT_SYMBOL_PRIVATE(global_sti); @@ -219,6 +219,10 @@ EXPORT_SYMBOL(pci_dma_supported); #endif +/* IOCTL32 emulation hooks. */ +EXPORT_SYMBOL(register_ioctl32_conversion); +EXPORT_SYMBOL(unregister_ioctl32_conversion); + /* Solaris/SunOS binary compatibility */ EXPORT_SYMBOL(_sigpause_common); @@ -297,8 +301,8 @@ /* Special internal versions of library functions. */ EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); -EXPORT_SYMBOL(clear_page); -EXPORT_SYMBOL(copy_page); +EXPORT_SYMBOL(_clear_page); +EXPORT_SYMBOL(_copy_page); EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(copy_user_page); EXPORT_SYMBOL(__bzero); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sparc.c Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc64/kernel/sys_sparc.c Wed Apr 26 09:25:17 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.37 2000/03/17 05:48:46 anton Exp $ +/* $Id: sys_sparc.c,v 1.38 2000/04/13 07:30:34 jj Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -182,6 +183,33 @@ return err; } +extern asmlinkage int sys_newuname(struct new_utsname * name); + +asmlinkage int sparc64_newuname(struct new_utsname * name) +{ + int ret = sys_newuname(name); + + if (current->personality == PER_LINUX32 && !ret) { + ret = copy_to_user(name->machine, "sparc\0\0", 8); + } + return ret; +} + +extern asmlinkage long sys_personality(unsigned long); + +asmlinkage int sparc64_personality(unsigned long personality) +{ + int ret; + lock_kernel(); + if (current->personality == PER_LINUX32 && personality == PER_LINUX) + personality = PER_LINUX32; + ret = sys_personality(personality); + unlock_kernel(); + if (ret == PER_LINUX32) + ret = PER_LINUX; + return ret; +} + /* Linux version of mmap */ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, @@ -232,7 +260,7 @@ (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) return -EINVAL; down(¤t->mm->mmap_sem); - ret = do_munmap(addr, len); + ret = do_munmap(current->mm, addr, len); up(¤t->mm->mmap_sem); return ret; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sparc32.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/sys_sparc32.c Fri Apr 14 09:37:09 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.142 2000/03/24 04:17:38 davem Exp $ +/* $Id: sys_sparc32.c,v 1.145 2000/04/13 07:30:34 jj Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -3542,6 +3542,18 @@ s32 gf32_version; }; +struct nfsctl_fdparm32 { + struct sockaddr gd32_addr; + s8 gd32_path[NFS_MAXPATHLEN+1]; + s32 gd32_version; +}; + +struct nfsctl_fsparm32 { + struct sockaddr gd32_addr; + s8 gd32_path[NFS_MAXPATHLEN+1]; + s32 gd32_maxlen; +}; + struct nfsctl_arg32 { s32 ca32_version; /* safeguard */ union { @@ -3550,15 +3562,17 @@ struct nfsctl_export32 u32_export; struct nfsctl_uidmap32 u32_umap; struct nfsctl_fhparm32 u32_getfh; - u32 u32_debug; + struct nfsctl_fdparm32 u32_getfd; + struct nfsctl_fsparm32 u32_getfs; } u; #define ca32_svc u.u32_svc #define ca32_client u.u32_client #define ca32_export u.u32_export #define ca32_umap u.u32_umap #define ca32_getfh u.u32_getfh +#define ca32_getfd u.u32_getfd +#define ca32_getfs u.u32_getfs #define ca32_authd u.u32_authd -#define ca32_debug u.u32_debug }; union nfsctl_res32 { @@ -3689,6 +3703,38 @@ return err; } +static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) +{ + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= copy_from_user(&karg->ca_getfd.gd_addr, + &arg32->ca32_getfd.gd32_addr, + (sizeof(struct sockaddr))); + err |= copy_from_user(&karg->ca_getfd.gd_path, + &arg32->ca32_getfd.gd32_path, + (NFS_MAXPATHLEN+1)); + err |= __get_user(karg->ca_getfd.gd_version, + &arg32->ca32_getfd.gd32_version); + return err; +} + +static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) +{ + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= copy_from_user(&karg->ca_getfs.gd_addr, + &arg32->ca32_getfs.gd32_addr, + (sizeof(struct sockaddr))); + err |= copy_from_user(&karg->ca_getfs.gd_path, + &arg32->ca32_getfs.gd32_path, + (NFS_MAXPATHLEN+1)); + err |= __get_user(karg->ca_getfs.gd_maxlen, + &arg32->ca32_getfs.gd32_maxlen); + return err; +} + /* This really doesn't need translations, we are only passing * back a union which contains opaque nfs file handle data. */ @@ -3727,6 +3773,7 @@ err = nfs_clnt32_trans(karg, arg32); break; case NFSCTL_EXPORT: + case NFSCTL_UNEXPORT: err = nfs_exp32_trans(karg, arg32); break; /* This one is unimplemented, be we're ready for it. */ @@ -3736,6 +3783,12 @@ case NFSCTL_GETFH: err = nfs_getfh32_trans(karg, arg32); break; + case NFSCTL_GETFD: + err = nfs_getfd32_trans(karg, arg32); + break; + case NFSCTL_GETFS: + err = nfs_getfs32_trans(karg, arg32); + break; default: err = -EINVAL; break; @@ -3747,7 +3800,12 @@ err = sys_nfsservctl(cmd, karg, kres); set_fs(oldfs); - if(!err && cmd == NFSCTL_GETFH) + if (err) + goto done; + + if((cmd == NFSCTL_GETFH) || + (cmd == NFSCTL_GETFD) || + (cmd == NFSCTL_GETFS)) err = nfs_getfh32_res_trans(kres, res32); done: @@ -3922,18 +3980,6 @@ } -extern asmlinkage int sys_newuname(struct new_utsname * name); - -asmlinkage int sys32_newuname(struct new_utsname * name) -{ - int ret = sys_newuname(name); - - if (current->personality == PER_LINUX32 && !ret) { - ret = copy_to_user(name->machine, "sparc\0\0", 8); - } - return ret; -} - extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf, size_t count, loff_t pos); @@ -3954,21 +4000,6 @@ return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo)); } - -extern asmlinkage long sys_personality(unsigned long); - -asmlinkage int sys32_personality(unsigned long personality) -{ - int ret; - lock_kernel(); - if (current->personality == PER_LINUX32 && personality == PER_LINUX) - personality = PER_LINUX32; - ret = sys_personality(personality); - unlock_kernel(); - if (ret == PER_LINUX32) - ret = PER_LINUX; - return ret; -} extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count); diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/sys_sunos32.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/kernel/sys_sunos32.c Wed Apr 26 09:25:17 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.43 2000/03/26 11:28:53 davem Exp $ +/* $Id: sys_sunos32.c,v 1.45 2000/04/13 00:55:49 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -45,6 +45,7 @@ #include #include #include +#include #include /* for sunos_select */ @@ -69,7 +70,6 @@ down(¤t->mm->mmap_sem); lock_kernel(); - current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { static int cnt; if (cnt++ < 10) @@ -141,7 +141,7 @@ /* Always allow shrinking brk. */ if (brk <= current->mm->brk) { current->mm->brk = brk; - do_munmap(newbrk, oldbrk-newbrk); + do_munmap(current->mm, newbrk, oldbrk-newbrk); goto out; } /* Check against rlimit and stack.. */ @@ -549,7 +549,6 @@ /* SunOS binaries expect that select won't change the tvp contents */ lock_kernel(); - current->personality |= STICKY_TIMEOUTS; ret = sys32_select (width, inp, outp, exp, tvp_x); if (ret == -EINTR && tvp_x) { struct timeval32 *tvp = (struct timeval32 *)A(tvp_x); @@ -685,7 +684,7 @@ * address to create a socket and bind it to a reserved * port on this system */ - if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount)) + if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount))) return -EFAULT; server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); @@ -776,14 +775,14 @@ dev_fname = getname(data); } else if(strcmp(type_page, "nfs") == 0) { ret = sunos_nfs_mount (dir_page, flags, data); - goto out2 + goto out2; } else if(strcmp(type_page, "ufs") == 0) { printk("Warning: UFS filesystem mounts unsupported.\n"); ret = -ENODEV; - goto out2 + goto out2; } else if(strcmp(type_page, "proc")) { ret = -ENODEV; - goto out2 + goto out2; } ret = PTR_ERR(dev_fname); if (IS_ERR(dev_fname)) @@ -1214,7 +1213,6 @@ { const char *filename = (const char *)(long)fname; - current->personality |= PER_BSD; return sparc32_open(filename, flags, mode); } @@ -1349,8 +1347,6 @@ { struct k_sigaction new_ka, old_ka; int ret; - - current->personality |= PER_BSD; if (act) { old_sigset_t32 mask; diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S --- v2.3.99-pre5/linux/arch/sparc64/kernel/systbls.S Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc64/kernel/systbls.S Fri Apr 14 09:37:09 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.71 2000/03/15 02:43:36 davem Exp $ +/* $Id: systbls.S,v 1.72 2000/04/13 07:30:34 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -56,8 +56,8 @@ /*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module - .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname -/*190*/ .word sys32_init_module, sys32_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sparc64_newuname +/*190*/ .word sys32_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask /*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir .word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall @@ -115,8 +115,8 @@ /*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module - .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname -/*190*/ .word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sparc64_newuname +/*190*/ .word sys_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask /*200*/ .word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall .word sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c --- v2.3.99-pre5/linux/arch/sparc64/kernel/time.c Thu Mar 2 14:36:22 2000 +++ linux/arch/sparc64/kernel/time.c Fri Apr 14 09:37:09 2000 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.24 2000/03/02 02:00:25 davem Exp $ +/* $Id: time.c,v 1.25 2000/04/13 05:29:44 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -67,6 +67,34 @@ } } +void sparc64_do_profile(unsigned long pc, unsigned long o7) +{ + if (prof_buffer && current->pid) { + extern int _stext; + extern int rwlock_impl_begin, rwlock_impl_end; + extern int atomic_impl_begin, atomic_impl_end; + extern int __memcpy_begin, __memcpy_end; + extern int __bitops_begin, __bitops_end; + + if ((pc >= (unsigned long) &atomic_impl_begin && + pc < (unsigned long) &atomic_impl_end) || + (pc >= (unsigned long) &rwlock_impl_begin && + pc < (unsigned long) &rwlock_impl_end) || + (pc >= (unsigned long) &__memcpy_begin && + pc < (unsigned long) &__memcpy_end) || + (pc >= (unsigned long) &__bitops_begin && + pc < (unsigned long) &__bitops_end)) + pc = o7; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + + if(pc >= prof_len) + pc = prof_len - 1; + atomic_inc((atomic_t *)&prof_buffer[pc]); + } +} + static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { unsigned long ticks, pstate; @@ -74,6 +102,10 @@ write_lock(&xtime_lock); do { +#ifndef __SMP__ + if ((regs->tstate & TSTATE_PRIV) != 0) + sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]); +#endif do_timer(regs); /* Guarentee that the following sequences execute diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile --- v2.3.99-pre5/linux/arch/sparc64/lib/Makefile Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/lib/Makefile Wed Apr 12 09:12:35 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.21 2000/03/27 10:38:41 davem Exp $ +# $Id: Makefile,v 1.22 2000/03/31 04:06:23 davem Exp $ # Makefile for Sparc library files.. # diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S --- v2.3.99-pre5/linux/arch/sparc64/lib/blockops.S Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/lib/blockops.S Fri Apr 14 09:37:10 2000 @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.24 2000/03/27 10:38:41 davem Exp $ +/* $Id: blockops.S,v 1.25 2000/04/13 04:45:58 davem Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com) @@ -26,9 +26,9 @@ .text .align 32 - .globl copy_page - .type copy_page,@function -copy_page: /* %o0=dest, %o1=src */ + .globl _copy_page + .type _copy_page,@function +_copy_page: /* %o0=dest, %o1=src */ VISEntry membar #LoadStore | #StoreStore | #StoreLoad ldda [%o1] ASI_BLK_P, %f0 @@ -205,9 +205,9 @@ stda %f16, [%o0] ASI_BLK_COMMIT_P .align 32 - .globl clear_page - .type clear_page,@function -clear_page: /* %o0=dest */ + .globl _clear_page + .type _clear_page,@function +_clear_page: /* %o0=dest */ VISEntryHalf ba,pt %xcc, clear_page_common clr %o4 diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/mm/Makefile linux/arch/sparc64/mm/Makefile --- v2.3.99-pre5/linux/arch/sparc64/mm/Makefile Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/mm/Makefile Wed Apr 12 09:12:35 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.6 2000/01/31 01:30:49 davem Exp $ +# $Id: Makefile,v 1.7 2000/03/31 04:06:24 davem Exp $ # Makefile for the linux Sparc64-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.3.99-pre5/linux/arch/sparc64/mm/fault.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/mm/fault.c Tue Apr 25 17:52:01 2000 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.45 2000/03/27 10:38:51 davem Exp $ +/* $Id: fault.c,v 1.47 2000/04/25 04:13:25 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -110,7 +110,8 @@ if(!pte_present(pte)) goto out; - pa = (pte_pagenr(pte) << PAGE_SHIFT) + (tpc & ~PAGE_MASK); + pa = phys_base + (pte_pagenr(pte) << PAGE_SHIFT); + pa += (tpc & ~PAGE_MASK); /* Use phys bypass so we don't pollute dtlb/dcache. */ __asm__ __volatile__("lduwa [%1] %2, %0" @@ -295,7 +296,7 @@ } { - int fault = handle_mm_fault(current, vma, + int fault = handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE)); if (fault < 0) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.3.99-pre5/linux/arch/sparc64/mm/init.c Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc64/mm/init.c Wed Apr 26 12:13:17 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.149 2000/03/15 14:42:58 jj Exp $ +/* $Id: init.c,v 1.151 2000/04/26 17:09:32 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -738,22 +738,17 @@ */ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset, unsigned long color) { - unsigned long paddr = __get_free_pages(GFP_KERNEL, 1); + struct page *page = alloc_pages(GFP_KERNEL, 1); - if (paddr) { - struct page *page2 = mem_map + MAP_NR(paddr + PAGE_SIZE); + if (page) { unsigned long *to_free; + unsigned long paddr; pte_t *pte; - /* Set count of second page, so we can free it - * seperately later on. - */ - atomic_set(&page2->count, 1); - - /* Clear out both pages now. */ + set_page_count((page + 1), 1); + paddr = page_address(page); memset((char *)paddr, 0, (PAGE_SIZE << 1)); - /* Determine which page we give to this request. */ if (!color) { pte = (pte_t *) paddr; to_free = (unsigned long *) (paddr + PAGE_SIZE); @@ -804,50 +799,42 @@ } } -#undef DEBUG_BOOTMEM - extern unsigned long cmdline_memory_size; -unsigned long __init bootmem_init(void) +unsigned long __init bootmem_init(unsigned long *pages_avail) { unsigned long bootmap_size, start_pfn, end_pfn; unsigned long end_of_phys_memory = 0UL; - unsigned long bootmap_pfn; + unsigned long bootmap_pfn, bytes_avail, size; int i; - /* XXX It is a bit ambiguous here, whether we should - * XXX treat the user specified mem=xxx as total wanted - * XXX physical memory, or as a limit to the upper - * XXX physical address we allow. For now it is the - * XXX latter. -DaveM - */ -#ifdef DEBUG_BOOTMEM - prom_printf("bootmem_init: Scan sp_banks, "); -#endif + + bytes_avail = 0UL; for (i = 0; sp_banks[i].num_bytes != 0; i++) { end_of_phys_memory = sp_banks[i].base_addr + sp_banks[i].num_bytes; + bytes_avail += sp_banks[i].num_bytes; if (cmdline_memory_size) { - if (end_of_phys_memory > cmdline_memory_size) { - if (cmdline_memory_size < sp_banks[i].base_addr) { - end_of_phys_memory = - sp_banks[i-1].base_addr + - sp_banks[i-1].num_bytes; + if (bytes_avail > cmdline_memory_size) { + unsigned long slack = bytes_avail - cmdline_memory_size; + + bytes_avail -= slack; + end_of_phys_memory -= slack; + + sp_banks[i].num_bytes -= slack; + if (sp_banks[i].num_bytes == 0) { sp_banks[i].base_addr = 0xdeadbeef; - sp_banks[i].num_bytes = 0; } else { - sp_banks[i].num_bytes -= - (end_of_phys_memory - - cmdline_memory_size); - end_of_phys_memory = cmdline_memory_size; - sp_banks[++i].base_addr = 0xdeadbeef; - sp_banks[i].num_bytes = 0; + sp_banks[i+1].num_bytes = 0; + sp_banks[i+1].base_addr = 0xdeadbeef; } break; } } } + *pages_avail = bytes_avail >> PAGE_SHIFT; + /* Start with page aligned address of last symbol in kernel * image. The kernel is hard mapped below PAGE_OFFSET in a * 4MB locked TLB translation. @@ -886,50 +873,40 @@ } #endif /* Initialize the boot-time allocator. */ -#ifdef DEBUG_BOOTMEM - prom_printf("init_bootmem(spfn[%lx],bpfn[%lx],epfn[%lx])\n", - start_pfn, bootmap_pfn, end_pfn); -#endif - bootmap_size = init_bootmem(bootmap_pfn, end_pfn); + bootmap_size = init_bootmem_node(0, bootmap_pfn, phys_base>>PAGE_SHIFT, end_pfn); /* Now register the available physical memory with the * allocator. */ - for (i = 0; sp_banks[i].num_bytes != 0; i++) { -#ifdef DEBUG_BOOTMEM - prom_printf("free_bootmem: base[%lx] size[%lx]\n", - sp_banks[i].base_addr, - sp_banks[i].num_bytes); -#endif + for (i = 0; sp_banks[i].num_bytes != 0; i++) free_bootmem(sp_banks[i].base_addr, sp_banks[i].num_bytes); - } - /* Reserve the kernel text/data/bss, the bootmem bootmap and initrd. */ -#ifdef DEBUG_BOOTMEM -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", - initrd_start, initrd_end - initrd_start); -#endif - prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", - phys_base, (start_pfn << PAGE_SHIFT) - phys_base); - prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", - (bootmap_pfn << PAGE_SHIFT), bootmap_size); -#endif #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) { - reserve_bootmem(initrd_start, initrd_end - initrd_start); + size = initrd_end - initrd_start; + + /* Resert the initrd image area. */ + reserve_bootmem(initrd_start, size); + *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; + initrd_start += PAGE_OFFSET; initrd_end += PAGE_OFFSET; } #endif - reserve_bootmem(phys_base, (start_pfn << PAGE_SHIFT) - phys_base); - reserve_bootmem((bootmap_pfn << PAGE_SHIFT), bootmap_size); + /* Reserve the kernel text/data/bss. */ + size = (start_pfn << PAGE_SHIFT) - phys_base; + reserve_bootmem(phys_base, size); + *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; + + /* Reserve the bootmem map. We do not account for it + * in pages_avail because we will release that memory + * in free_all_bootmem. + */ + size = bootmap_size; + reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size); + *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; -#ifdef DEBUG_BOOTMEM - prom_printf("init_bootmem: return end_pfn[%lx]\n", end_pfn); -#endif return end_pfn; } @@ -946,7 +923,7 @@ extern unsigned int sparc64_vpte_patchme2[1]; unsigned long alias_base = phys_base + PAGE_OFFSET; unsigned long second_alias_page = 0; - unsigned long pt, flags, end_pfn; + unsigned long pt, flags, end_pfn, pages_avail; unsigned long shift = alias_base - ((unsigned long)&empty_zero_page); set_bit(0, mmu_context_bmap); @@ -1001,7 +978,8 @@ flushi((long)&sparc64_vpte_patchme1[0]); /* Setup bootmem... */ - last_valid_pfn = end_pfn = bootmem_init(); + pages_avail = 0; + last_valid_pfn = end_pfn = bootmem_init(&pages_avail); #ifdef CONFIG_SUN_SERIAL /* This does not logically belong here, but we need to @@ -1039,10 +1017,20 @@ flush_tlb_all(); { - unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES]; + unsigned long zholes_size[MAX_NR_ZONES]; + unsigned long npages; + int znum; + + for (znum = 0; znum < MAX_NR_ZONES; znum++) + zones_size[znum] = zholes_size[znum] = 0; + + npages = end_pfn - (phys_base >> PAGE_SHIFT); + zones_size[ZONE_DMA] = npages; + zholes_size[ZONE_DMA] = npages - pages_avail; - zones_size[ZONE_DMA] = end_pfn; - free_area_init(zones_size); + free_area_init_node(0, NULL, zones_size, + phys_base, zholes_size); } device_scan(); @@ -1139,9 +1127,6 @@ struct sparc_phys_banks saved_sp_banks[SPARC_PHYS_BANKS]; int i; -#ifdef DEBUG_BOOTMEM - prom_printf("taint_real_pages: Rescan sp_banks[].\n"); -#endif for (i = 0; i < SPARC_PHYS_BANKS; i++) { saved_sp_banks[i].base_addr = sp_banks[i].base_addr; @@ -1176,10 +1161,6 @@ goto do_next_page; } } -#ifdef DEBUG_BOOTMEM - prom_printf("taint: Page went away, reserve page %lx.\n", - old_start); -#endif reserve_bootmem(old_start, PAGE_SIZE); do_next_page: @@ -1188,70 +1169,6 @@ } } -void __init free_mem_map_range(struct page *first, struct page *last) -{ - first = (struct page *) PAGE_ALIGN((unsigned long)first); - last = (struct page *) ((unsigned long)last & PAGE_MASK); -#ifdef DEBUG_BOOTMEM - prom_printf("[%p,%p] ", first, last); -#endif - while (first < last) { - ClearPageReserved(mem_map + MAP_NR(first)); - set_page_count(mem_map + MAP_NR(first), 1); - free_page((unsigned long)first); - num_physpages++; - - first = (struct page *)((unsigned long)first + PAGE_SIZE); - } -} - -/* Walk through holes in sp_banks regions, if the mem_map array - * areas representing those holes consume a page or more, free - * up such pages. This helps a lot on machines where physical - * ram is configured such that it begins at some hugh value. - * - * The sp_banks array is sorted by base address. - */ -void __init free_unused_mem_map(void) -{ - int i; - -#ifdef DEBUG_BOOTMEM - prom_printf("free_unused_mem_map: "); -#endif - for (i = 0; sp_banks[i].num_bytes; i++) { - if (i == 0) { - struct page *first, *last; - - first = mem_map; - last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT]; - free_mem_map_range(first, last); - } else { - struct page *first, *last; - unsigned long prev_end; - - prev_end = sp_banks[i-1].base_addr + - sp_banks[i-1].num_bytes; - prev_end = PAGE_ALIGN(prev_end); - first = &mem_map[prev_end >> PAGE_SHIFT]; - last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT]; - - free_mem_map_range(first, last); - - if (!sp_banks[i+1].num_bytes) { - prev_end = sp_banks[i].base_addr + - sp_banks[i].num_bytes; - first = &mem_map[prev_end >> PAGE_SHIFT]; - last = &mem_map[last_valid_pfn]; - free_mem_map_range(first, last); - } - } - } -#ifdef DEBUG_BOOTMEM - prom_printf("\n"); -#endif -} - void __init mem_init(void) { unsigned long codepages, datapages, initpages; @@ -1279,16 +1196,10 @@ taint_real_pages(); - max_mapnr = last_valid_pfn; + max_mapnr = last_valid_pfn - (phys_base >> PAGE_SHIFT); high_memory = __va(last_valid_pfn << PAGE_SHIFT); -#ifdef DEBUG_BOOTMEM - prom_printf("mem_init: Calling free_all_bootmem().\n"); -#endif num_physpages = free_all_bootmem(); -#if 0 - free_unused_mem_map(); -#endif codepages = (((unsigned long) &etext) - ((unsigned long)&_start)); codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT; datapages = (((unsigned long) &edata) - ((unsigned long)&etext)); @@ -1317,19 +1228,6 @@ datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10), PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT)); - - /* NOTE NOTE NOTE NOTE - * Please keep track of things and make sure this - * always matches the code in mm/page_alloc.c -DaveM - */ - i = nr_free_pages() >> 7; - if (i < 48) - i = 48; - if (i > 256) - i = 256; - freepages.min = i; - freepages.low = i << 1; - freepages.high = freepages.low + i; } void free_initmem (void) diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/prom/Makefile linux/arch/sparc64/prom/Makefile --- v2.3.99-pre5/linux/arch/sparc64/prom/Makefile Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/prom/Makefile Wed Apr 12 09:12:35 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.5 1999/12/21 04:02:26 davem Exp $ +# $Id: Makefile,v 1.6 2000/03/31 04:06:25 davem Exp $ # Makefile for the Sun Boot PROM interface library under # Linux. # diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c --- v2.3.99-pre5/linux/arch/sparc64/prom/misc.c Wed Dec 29 13:13:15 1999 +++ linux/arch/sparc64/prom/misc.c Mon Apr 24 13:59:58 2000 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.16 1999/11/19 05:53:04 davem Exp $ +/* $Id: misc.c,v 1.17 2000/04/15 06:02:50 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -64,7 +64,7 @@ * on SMP, we need to drop the IRQ locks we hold. */ #ifdef __SMP__ - hardirq_exit(smp_processor_id()); + irq_exit(smp_processor_id(), 0); smp_capture(); #else local_irq_count--; @@ -74,8 +74,8 @@ #ifdef __SMP__ smp_release(); - hardirq_enter(smp_processor_id()); - spin_unlock_wait(&global_irq_lock); + irq_enter(smp_processor_id(), 0); + spin_unlock_wait(&__br_write_locks[BR_GLOBALIRQ_LOCK].lock); #else local_irq_count++; #endif diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c --- v2.3.99-pre5/linux/arch/sparc64/solaris/fs.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/solaris/fs.c Wed Apr 12 09:12:35 2000 @@ -1,4 +1,4 @@ -/* $Id: fs.c,v 1.17 2000/03/10 04:43:30 davem Exp $ +/* $Id: fs.c,v 1.18 2000/04/08 02:11:54 davem Exp $ * fs.c: fs related syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -506,7 +506,7 @@ unlock_kernel(); fput(file); } -out: + return error; } diff -u --recursive --new-file v2.3.99-pre5/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c --- v2.3.99-pre5/linux/arch/sparc64/solaris/misc.c Tue Apr 11 15:09:15 2000 +++ linux/arch/sparc64/solaris/misc.c Fri Apr 14 09:37:10 2000 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.23 2000/03/13 21:57:34 davem Exp $ +/* $Id: misc.c,v 1.26 2000/04/14 09:59:02 davem Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -54,7 +54,8 @@ unsigned long retval, ret_type; lock_kernel(); - current->personality |= PER_SVR4; + /* Do we need it here? */ + set_personality(PER_SVR4); if (flags & MAP_NORESERVE) { static int cnt = 0; @@ -719,11 +720,7 @@ asmlinkage void solaris_register(void) { - lock_kernel(); - current->personality = PER_SVR4; - put_exec_domain(current->exec_domain); - current->exec_domain = lookup_exec_domain(current->personality); - unlock_kernel(); + set_personality(PER_SVR4); } extern long solaris_to_linux_signals[], linux_to_solaris_signals[]; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c --- v2.3.99-pre5/linux/drivers/acorn/net/ether1.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/acorn/net/ether1.c Tue Apr 25 16:54:37 2000 @@ -798,6 +798,8 @@ if (ether1_init_for_open(dev)) printk(KERN_ERR "%s: unable to restart interface\n", dev->name); + else + priv->restart = 0; } /* diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c --- v2.3.99-pre5/linux/drivers/acorn/scsi/fas216.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/acorn/scsi/fas216.c Tue Apr 25 16:54:37 2000 @@ -1415,6 +1415,7 @@ case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out -> Message In */ case STATE(STAT_MESGIN, PHASE_DATAIN): /* Data In -> Message In */ fas216_stoptransfer(info); + case STATE(STAT_MESGIN, PHASE_COMMAND): /* Command -> Message In */ case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In */ case STATE(STAT_MESGIN, PHASE_MSGOUT): /* Message Out -> Message In */ info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; @@ -1753,6 +1754,23 @@ fas216_set_sync(info, SCpnt->target); tot_msglen = msgqueue_msglength(&info->scsi.msgs); + +#ifdef DEBUG_MESSAGES + { + struct message *msg; + int msgnr = 0, i; + + printk("scsi%d.%c: message out: ", + info->host->host_no, '0' + SCpnt->target); + while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { + printk("{ "); + for (i = 0; i < msg->length; i++) + printk("%02x ", msg->msg[i]); + printk("} "); + } + printk("\n"); + } +#endif if (tot_msglen == 1 || tot_msglen == 3) { /* diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/Config.in linux/drivers/atm/Config.in --- v2.3.99-pre5/linux/drivers/atm/Config.in Sat Feb 26 22:31:42 2000 +++ linux/drivers/atm/Config.in Fri Apr 14 09:37:10 2000 @@ -52,8 +52,8 @@ fi fi if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBUS" = "y" ]; then - tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E - if [ "$CONFIG_ATM_FORE200E" != "n" ]; then + tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E_MAYBE + if [ "$CONFIG_ATM_FORE200E_MAYBE" != "n" ]; then if [ "$CONFIG_PCI" = "y" ]; then bool ' PCA-200E support' CONFIG_ATM_FORE200E_PCA y if [ "$CONFIG_ATM_FORE200E_PCA" = "y" ]; then @@ -72,8 +72,16 @@ fi fi fi + fi + if [ "$CONFIG_ATM_FORE200E_PCA" = "y" -o "$CONFIG_ATM_FORE200E_SBA" = "y" ]; \ + then int ' Maximum number of tx retries' CONFIG_ATM_FORE200E_TX_RETRY 16 int ' Debugging level (0-3)' CONFIG_ATM_FORE200E_DEBUG 0 + if [ "$CONFIG_ATM_FORE200E_MAYBE" = "y" ]; then + define_tristate CONFIG_ATM_FORE200E y + else + define_tristate CONFIG_ATM_FORE200E m + fi fi fi endmenu diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/Makefile linux/drivers/atm/Makefile --- v2.3.99-pre5/linux/drivers/atm/Makefile Mon Mar 27 08:08:22 2000 +++ linux/drivers/atm/Makefile Fri Apr 14 09:37:10 2000 @@ -30,10 +30,6 @@ endif endif -ifeq ($(CONFIG_ATM_TNETA1570),y) -O_OBJS += tneta1570.o suni.o -endif - ifeq ($(CONFIG_ATM_NICSTAR),y) O_OBJS += nicstar.o ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) @@ -101,23 +97,29 @@ endif ifeq ($(CONFIG_ATM_FORE200E_PCA),y) -FORE200E_FW_OBJS += fore200e_pca_fw.o + FORE200E_FW_OBJS += fore200e_pca_fw.o + ifeq ($(strip $(CONFIG_ATM_FORE200E_PCA_FW)),"") + CONFIG_ATM_FORE200E_PCA_DEFAULT_FW := y + endif ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y) # guess the target endianess to choose the right PCA-200E firmware image CONFIG_ATM_FORE200E_PCA_FW := $(shell if test -n "`$(CC) -E -dM ../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo pca200e.bin; else echo pca200e_ecd.bin2; fi) endif endif ifeq ($(CONFIG_ATM_FORE200E_SBA),y) -FORE200E_FW_OBJS += fore200e_sba_fw.o + FORE200E_FW_OBJS += fore200e_sba_fw.o + ifeq ($(strip $(CONFIG_ATM_FORE200E_SBA_FW)),"") + CONFIG_ATM_FORE200E_SBA_DEFAULT_FW := y + endif ifeq ($(CONFIG_ATM_FORE200E_SBA_DEFAULT_FW),y) CONFIG_ATM_FORE200E_SBA_FW := sba200e_ecd.bin2 endif endif ifeq ($(CONFIG_ATM_FORE200E),y) -O_OBJS += fore200e.o $(FORE200E_FW_OBJS) + O_OBJS += fore200e.o $(FORE200E_FW_OBJS) else ifeq ($(CONFIG_ATM_FORE200E),m) - M_OBJS += fore_200e.o + M_OBJS += fore_200e.o endif endif @@ -125,33 +127,51 @@ include $(TOPDIR)/Rules.make + # FORE Systems 200E-series firmware magic fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \ fore200e_mkfirm ./fore200e_mkfirm -k -b _fore200e_pca_fw \ -i $(CONFIG_ATM_FORE200E_PCA_FW) -o $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_ATM_FORE200E_PCA_FW)), $$(CONFIG_ATM_FORE200E_PCA_FW))'; \ + echo 'FORE200E_FW_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) >.$@.fw fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \ fore200e_mkfirm ./fore200e_mkfirm -k -b _fore200e_sba_fw \ -i $(CONFIG_ATM_FORE200E_SBA_FW) -o $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_ATM_FORE200E_SBA_FW)), $$(CONFIG_ATM_FORE200E_SBA_FW))'; \ + echo 'FORE200E_FW_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) >.$@.fw fore200e_mkfirm: fore200e_mkfirm.c $(HOSTCC) $(HOSTCFLAGS) $< -o $@ -# deal with the various suffixes of the firmware images -%.bin: %.data - objcopy -Iihex $< -Obinary $@.gz - gzip -df $@.gz - -%.bin1: %.data - objcopy -Iihex $< -Obinary $@.gz - gzip -df $@.gz - -%.bin2: %.data +# deal with the various suffixes of the binary firmware images +%.bin %.bin1 %.bin2: %.data objcopy -Iihex $< -Obinary $@.gz gzip -df $@.gz # module build fore_200e.o: fore200e.o $(FORE200E_FW_OBJS) $(LD) -r -o $@ $< $(FORE200E_FW_OBJS) + +# firmware dependency stuff taken from drivers/sound/Makefile +FORE200E_FW_UP_TO_DATE := + +FORE200E_FW_FILES := $(wildcard .fore200e_*.fw) +ifneq ($(FORE200E_FW_FILES),) +include $(FORE200E_FW_FILES) +endif + +FORE200E_FW_CHANGED := $(filter-out $(FORE200E_FW_UP_TO_DATE), \ + fore200e_pca_fw.c fore200e_sba_fw.c) + +ifneq ($(FORE200E_FW_CHANGED),) +$(FORE200E_FW_CHANGED): dummy +endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c --- v2.3.99-pre5/linux/drivers/atm/ambassador.c Mon Mar 27 08:08:22 2000 +++ linux/drivers/atm/ambassador.c Fri Apr 14 09:37:10 2000 @@ -1251,10 +1251,15 @@ } } + // prevent module unload while sleeping (kmalloc/down) + // doing this any earlier would complicate more error return paths + MOD_INC_USE_COUNT; + // get space for our vcc stuff vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL); if (!vcc) { PRINTK (KERN_ERR, "out of memory!"); + MOD_DEC_USE_COUNT; return -ENOMEM; } atm_vcc->dev_data = (void *) vcc; @@ -1340,7 +1345,6 @@ // indicate readiness set_bit(ATM_VF_READY,&atm_vcc->flags); - MOD_INC_USE_COUNT; return 0; } @@ -1420,7 +1424,9 @@ // say the VPI/VCI is free again clear_bit(ATM_VF_ADDR,&atm_vcc->flags); + MOD_DEC_USE_COUNT; + return; } /********** DebugIoctl **********/ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/ambassador.h linux/drivers/atm/ambassador.h --- v2.3.99-pre5/linux/drivers/atm/ambassador.h Mon Mar 27 08:08:22 2000 +++ linux/drivers/atm/ambassador.h Fri Apr 14 09:37:10 2000 @@ -631,7 +631,7 @@ u32 iobase; u32 * membase; -#if 0 +#ifdef FILL_RX_POOLS_IN_BH struct tq_struct bh; #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/atmdev_init.c linux/drivers/atm/atmdev_init.c --- v2.3.99-pre5/linux/drivers/atm/atmdev_init.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/atm/atmdev_init.c Fri Apr 14 09:37:10 2000 @@ -1,21 +1,15 @@ /* drivers/atm/atmdev_init.c - ATM device driver initialization */ -/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include #include -#ifdef CONFIG_ATM_ENI -extern int eni_detect(void); -#endif #ifdef CONFIG_ATM_ZATM extern int zatm_detect(void); #endif -#ifdef CONFIG_ATM_TNETA1570 -extern int tneta1570_detect(void); -#endif #ifdef CONFIG_ATM_NICSTAR extern int nicstar_detect(void); #endif @@ -33,19 +27,19 @@ #endif +/* + * For historical reasons, atmdev_init returns the number of devices found. + * Note that some detections may not go via atmdev_init (e.g. eni.c), so this + * number is meaningless. + */ + int __init atmdev_init(void) { int devs; devs = 0; -#ifdef CONFIG_ATM_ENI -// devs += eni_detect(); -#endif #ifdef CONFIG_ATM_ZATM devs += zatm_detect(); -#endif -#ifdef CONFIG_ATM_TNETA1570 - devs += tneta1570_detect(); #endif #ifdef CONFIG_ATM_NICSTAR devs += nicstar_detect(); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/eni.c linux/drivers/atm/eni.c --- v2.3.99-pre5/linux/drivers/atm/eni.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/atm/eni.c Fri Apr 14 09:37:10 2000 @@ -879,14 +879,13 @@ set_current_state(TASK_UNINTERRUPTIBLE); } for (;;) { - unsigned long flags; int at_end; u32 tmp; - spin_lock_irqsave(&eni_dev->lock,flags); + tasklet_disable(&eni_dev->task); tmp = readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ; at_end = eni_vcc->rx_pos == tmp >> MID_VCI_READ_SHIFT; - spin_unlock_irqrestore(&eni_dev->lock,flags); + tasklet_enable(&eni_dev->task); if (at_end) break; EVENT("drain discard (host 0x%lx, nic 0x%lx)\n", eni_vcc->rx_pos,tmp); @@ -972,8 +971,8 @@ } #ifdef CONFIG_ATM_ENI_BURST_TX_16W /* may work with some PCI chipsets ... */ if (words & ~15) { - DPRINTK("put_dma: %lx DMA: %d*16/%d words\n",paddr,words >> 4, - words); + DPRINTK("put_dma: %lx DMA: %d*16/%d words\n", + (unsigned long) paddr,words >> 4,words); dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); dma[(*j)++] = paddr; @@ -994,8 +993,8 @@ #endif #ifdef CONFIG_ATM_ENI_BURST_TX_4W /* probably useless if TX_8W or TX_16W */ if (words & ~3) { - DPRINTK("put_dma: %lx DMA: %d*4/%d words\n",paddr,words >> 2, - words); + DPRINTK("put_dma: %lx DMA: %d*4/%d words\n", + (unsigned long) paddr,words >> 2,words); dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); dma[(*j)++] = paddr; @@ -1005,8 +1004,8 @@ #endif #ifdef CONFIG_ATM_ENI_BURST_TX_2W /* probably useless if TX_4W, TX_8W, ... */ if (words & ~1) { - DPRINTK("put_dma: %lx DMA: %d*2/%d words\n",paddr,words >> 1, - words); + DPRINTK("put_dma: %lx DMA: %d*2/%d words\n", + (unsigned long) paddr,words >> 1,words); dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); dma[(*j)++] = paddr; @@ -1188,7 +1187,7 @@ if (tx->send) while ((skb = skb_dequeue(&tx->backlog))) { res = do_tx(skb); - if (res == enq_ok) tx->backlog_len--; + if (res == enq_ok) atomic_dec(&tx->backlog_len); else { DPRINTK("re-queuing TX PDU\n"); skb_queue_head(&tx->backlog,skb); @@ -1327,7 +1326,7 @@ tx->send = mem; tx->words = size >> 2; skb_queue_head_init(&tx->backlog); - tx->backlog_len = 0; + atomic_set(&tx->backlog_len,0); for (order = 0; size > (1 << (order+10)); order++); eni_out((order << MID_SIZE_SHIFT) | ((tx->send-eni_dev->ram) >> (MID_LOC_SKIP+2)), @@ -1399,12 +1398,11 @@ add_wait_queue(&eni_dev->tx_wait,&wait); set_current_state(TASK_UNINTERRUPTIBLE); for (;;) { - unsigned long flags; int txing; - spin_lock_irqsave(&eni_dev->lock,flags); + tasklet_disable(&eni_dev->task); txing = skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing; - spin_unlock_irqrestore(&eni_dev->lock,flags); + tasklet_enable(&eni_dev->task); if (!txing) break; DPRINTK("%d TX left\n",eni_vcc->txing); schedule(); @@ -1468,44 +1466,24 @@ #endif -static void misc_int(struct atm_dev *dev,unsigned long reason) +static void bug_int(struct atm_dev *dev,unsigned long reason) { struct eni_dev *eni_dev; - DPRINTK(">misc_int\n"); + DPRINTK(">bug_int\n"); eni_dev = ENI_DEV(dev); - if (reason & MID_STAT_OVFL) { - EVENT("stat overflow\n",0,0); - eni_dev->lost += eni_in(MID_STAT) & MID_OVFL_TRASH; - } - if (reason & MID_SUNI_INT) { - EVENT("SUNI int\n",0,0); - dev->phy->interrupt(dev); -#if 0 - foo(); -#endif - } - if (reason & MID_DMA_ERR_ACK) { + if (reason & MID_DMA_ERR_ACK) printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA " "error\n",dev->number); - EVENT("---dump ends here---\n",0,0); - printk(KERN_NOTICE "---recent events---\n"); - event_dump(); - } - if (reason & MID_TX_IDENT_MISM) { + if (reason & MID_TX_IDENT_MISM) printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - ident " "mismatch\n",dev->number); - EVENT("---dump ends here---\n",0,0); - printk(KERN_NOTICE "---recent events---\n"); - event_dump(); - } - if (reason & MID_TX_DMA_OVFL) { + if (reason & MID_TX_DMA_OVFL) printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA " "overflow\n",dev->number); - EVENT("---dump ends here---\n",0,0); - printk(KERN_NOTICE "---recent events---\n"); - event_dump(); - } + EVENT("---dump ends here---\n",0,0); + printk(KERN_NOTICE "---recent events---\n"); + event_dump(); } @@ -1513,54 +1491,78 @@ { struct atm_dev *dev; struct eni_dev *eni_dev; - unsigned long reason; + u32 reason; DPRINTK(">eni_int\n"); dev = dev_id; eni_dev = ENI_DEV(dev); - while ((reason = eni_in(MID_ISA))) { - DPRINTK(DEV_LABEL ": int 0x%lx\n",reason); - if (reason & MID_RX_DMA_COMPLETE) { - EVENT("INT: RX DMA complete, starting dequeue_rx\n", - 0,0); - spin_lock(&eni_dev->lock); - dequeue_rx(dev); - EVENT("dequeue_rx done, starting poll_rx\n",0,0); - poll_rx(dev); - spin_unlock(&eni_dev->lock); - EVENT("poll_rx done\n",0,0); - /* poll_tx ? */ - } - if (reason & MID_SERVICE) { - EVENT("INT: service, starting get_service\n",0,0); - spin_lock(&eni_dev->lock); - get_service(dev); - EVENT("get_service done, starting poll_rx\n",0,0); - poll_rx(dev); - spin_unlock(&eni_dev->lock); - EVENT("poll_rx done\n",0,0); - } - if (reason & MID_TX_DMA_COMPLETE) { - EVENT("INT: TX DMA COMPLETE\n",0,0); - spin_lock(&eni_dev->lock); - dequeue_tx(dev); - spin_unlock(&eni_dev->lock); - } - if (reason & MID_TX_COMPLETE) { - EVENT("INT: TX COMPLETE\n",0,0); + reason = eni_in(MID_ISA); + DPRINTK(DEV_LABEL ": int 0x%lx\n",(unsigned long) reason); + /* + * Must handle these two right now, because reading ISA doesn't clear + * them, so they re-occur and we never make it to the tasklet. Since + * they're rare, we don't mind the occasional invocation of eni_tasklet + * with eni_dev->events == 0. + */ + if (reason & MID_STAT_OVFL) { + EVENT("stat overflow\n",0,0); + eni_dev->lost += eni_in(MID_STAT) & MID_OVFL_TRASH; + } + if (reason & MID_SUNI_INT) { + EVENT("SUNI int\n",0,0); + dev->phy->interrupt(dev); +#if 0 + foo(); +#endif + } + spin_lock(&eni_dev->lock); + eni_dev->events |= reason; + spin_unlock(&eni_dev->lock); + tasklet_schedule(&eni_dev->task); +} + + +static void eni_tasklet(unsigned long data) +{ + struct atm_dev *dev = (struct atm_dev *) data; + struct eni_dev *eni_dev = ENI_DEV(dev); + unsigned long flags; + u32 events; + + DPRINTK("eni_tasklet (dev %p)\n",dev); + spin_lock_irqsave(&eni_dev->lock,flags); + events = xchg(&eni_dev->events,0); + spin_unlock_irqrestore(&eni_dev->lock,flags); + if (events & MID_RX_DMA_COMPLETE) { + EVENT("INT: RX DMA complete, starting dequeue_rx\n",0,0); + dequeue_rx(dev); + EVENT("dequeue_rx done, starting poll_rx\n",0,0); + poll_rx(dev); + EVENT("poll_rx done\n",0,0); + /* poll_tx ? */ + } + if (events & MID_SERVICE) { + EVENT("INT: service, starting get_service\n",0,0); + get_service(dev); + EVENT("get_service done, starting poll_rx\n",0,0); + poll_rx(dev); + EVENT("poll_rx done\n",0,0); + } + if (events & MID_TX_DMA_COMPLETE) { + EVENT("INT: TX DMA COMPLETE\n",0,0); + dequeue_tx(dev); + } + if (events & MID_TX_COMPLETE) { + EVENT("INT: TX COMPLETE\n",0,0); tx_complete++; - spin_lock(&eni_dev->lock); - poll_tx(dev); - spin_unlock(&eni_dev->lock); - wake_up(&eni_dev->tx_wait); - /* poll_rx ? */ - } - if (reason & (MID_STAT_OVFL | MID_SUNI_INT | MID_DMA_ERR_ACK | - MID_TX_IDENT_MISM | MID_TX_DMA_OVFL)) { - EVENT("misc interrupt\n",0,0); - misc_int(dev,reason); - } + wake_up(&eni_dev->tx_wait); + /* poll_rx ? */ + } + if (events & (MID_DMA_ERR_ACK | MID_TX_IDENT_MISM | MID_TX_DMA_OVFL)) { + EVENT("bug interrupt\n",0,0); + bug_int(dev,events); } + poll_tx(dev); } @@ -1824,6 +1826,8 @@ eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma, eni_dev->service,buf); spin_lock_init(&eni_dev->lock); + tasklet_init(&eni_dev->task,eni_tasklet,(unsigned long) dev); + eni_dev->events = 0; /* initialize memory management */ buffer_mem = eni_dev->mem-(buf-eni_dev->ram); eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2; @@ -1969,7 +1973,6 @@ struct eni_dev *eni_dev = ENI_DEV(vcc->dev); struct eni_tx *tx = ENI_VCC(vcc)->tx; struct sk_buff *skb; - unsigned long flags; int error,rate,rsv,shp; if (qos->txtp.traffic_class == ATM_NONE) return 0; @@ -1989,7 +1992,7 @@ * Walk through the send buffer and patch the rate information in all * segmentation buffer descriptors of this VCC. */ - spin_lock_irqsave(&eni_dev->lock,flags); + tasklet_disable(&eni_dev->task); for (skb = eni_dev->tx_queue.next; skb != (struct sk_buff *) &eni_dev->tx_queue; skb = skb->next) { unsigned long dsc; @@ -2000,7 +2003,7 @@ (tx->prescaler << MID_SEG_PR_SHIFT) | (tx->resolution << MID_SEG_RATE_SHIFT), dsc); } - spin_unlock_irqrestore(&eni_dev->lock,flags); + tasklet_enable(&eni_dev->task); return 0; } @@ -2061,8 +2064,6 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb) { - unsigned long flags; - DPRINTK(">eni_send\n"); if (!ENI_VCC(vcc)->tx) { if (vcc->pop) vcc->pop(vcc,skb); @@ -2084,13 +2085,10 @@ } submitted++; ATM_SKB(skb)->vcc = vcc; - spin_lock_irqsave(&ENI_DEV(vcc->dev)->lock,flags); /* brute force */ - if (skb_peek(&ENI_VCC(vcc)->tx->backlog) || do_tx(skb)) { - skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb); - ENI_VCC(vcc)->tx->backlog_len++; + skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb); + atomic_inc(&ENI_VCC(vcc)->tx->backlog_len); backlogged++; - } - spin_unlock_irqrestore(&ENI_DEV(vcc->dev)->lock,flags); + tasklet_schedule(&ENI_DEV(vcc->dev)->task); return 0; } @@ -2189,7 +2187,7 @@ } if (--left) continue; return sprintf(page,"%10sbacklog %d bytes\n","", - tx->backlog_len); + atomic_read(&tx->backlog_len)); } for (vcc = dev->vccs; vcc; vcc = vcc->next) { struct eni_vcc *eni_vcc = ENI_VCC(vcc); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/eni.h linux/drivers/atm/eni.h --- v2.3.99-pre5/linux/drivers/atm/eni.h Mon Mar 27 08:08:23 2000 +++ linux/drivers/atm/eni.h Fri Apr 14 09:37:10 2000 @@ -13,6 +13,7 @@ #include #include #include +#include #include "midway.h" @@ -46,7 +47,7 @@ int reserved; /* reserved peak cell rate */ int shaping; /* shaped peak cell rate */ struct sk_buff_head backlog; /* queue of waiting TX buffers */ - int backlog_len; /* length of backlog in bytes */ + atomic_t backlog_len; /* length of backlog in bytes */ }; struct eni_vcc { @@ -68,6 +69,8 @@ struct eni_dev { /*-------------------------------- spinlock */ spinlock_t lock; /* sync with interrupt */ + struct tasklet_struct task; /* tasklet for interrupt work */ + u32 events; /* pending events */ /*-------------------------------- base pointers into Midway address space */ unsigned long phy; /* PHY interface chip registers */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c --- v2.3.99-pre5/linux/drivers/atm/fore200e.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/atm/fore200e.c Fri Apr 14 09:37:10 2000 @@ -1,8 +1,8 @@ /* - $Id: fore200e.c,v 1.2 2000/03/21 21:19:24 davem Exp $ + $Id: fore200e.c,v 1.5 2000/04/14 10:10:34 davem Exp $ A FORE Systems 200E-series driver for ATM on Linux. - Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000. + Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2000. Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). @@ -32,10 +32,11 @@ #include #include #include +#include +#include #include #include #include -#include #include #include #include @@ -66,7 +67,7 @@ #define FORE200E_52BYTE_AAL0_SDU #endif -#define FORE200E_VERSION "0.2b" +#define FORE200E_VERSION "0.2d" #define FORE200E "fore200e: " @@ -444,6 +445,7 @@ } + #ifdef CONFIG_ATM_FORE200E_PCA static u32 fore200e_pca_read(volatile u32* addr) @@ -477,7 +479,8 @@ static void fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); + DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", + dma_addr, size, direction); pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction); } @@ -496,7 +499,8 @@ (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ static int -fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) +fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, + int size, int nbr, int alignment) { #if defined(__sparc_v9__) /* returned chunks are page-aligned */ @@ -659,6 +663,7 @@ sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + pci_enable_device(pci_dev); pci_set_master(pci_dev); return fore200e; @@ -756,7 +761,8 @@ static void fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", dma_addr, size, direction); + DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", + dma_addr, size, direction); sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); } @@ -775,7 +781,8 @@ (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ static int -fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) +fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, + int size, int nbr, int alignment) { chunk->alloc_size = chunk->align_size = size * nbr; @@ -1234,15 +1241,25 @@ } DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]); - fore200e_irq_rx(fore200e); + tasklet_schedule(&fore200e->tasklet); + + fore200e->bus->irq_ack(fore200e); +} + + +static void +fore200e_tasklet(unsigned long data) +{ + struct fore200e* fore200e = (struct fore200e*) data; + fore200e_irq_rx(fore200e); + if (fore200e->host_txq.txing) fore200e_irq_tx(fore200e); - - fore200e->bus->irq_ack(fore200e); } + static int fore200e_select_scheme(struct atm_vcc* vcc) { @@ -1400,7 +1417,7 @@ if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) return 0; - set_bit(ATM_VF_ADDR,&vcc->flags); + set_bit(ATM_VF_ADDR, &vcc->flags); vcc->itf = vcc->dev->number; DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " @@ -1463,7 +1480,7 @@ fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536; fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; - clear_bit(ATM_VF_READY,&vcc->flags); + set_bit(ATM_VF_READY, &vcc->flags); return 0; } @@ -1489,6 +1506,8 @@ fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; up(&fore200e->rate_sf); } + + clear_bit(ATM_VF_READY, &vcc->flags); } @@ -1506,7 +1525,7 @@ struct host_txq_entry* entry; struct tpd* tpd; struct tpd_haddr tpd_haddr; - unsigned long flags; + //unsigned long flags; int retry = CONFIG_ATM_FORE200E_TX_RETRY; int tx_copy = 0; int tx_len = skb->len; @@ -1531,7 +1550,7 @@ retry_here: - spin_lock_irqsave(&fore200e->tx_lock, flags); + tasklet_disable(&fore200e->tasklet); entry = &txq->host_entry[ txq->head ]; @@ -1542,7 +1561,7 @@ if (*entry->status != STATUS_FREE) { - spin_unlock_irqrestore(&fore200e->tx_lock, flags); + tasklet_enable(&fore200e->tasklet); /* retry once again? */ if(--retry > 0) @@ -1582,7 +1601,7 @@ entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); if (entry->data == NULL) { - spin_unlock_irqrestore(&fore200e->tx_lock, flags); + tasklet_enable(&fore200e->tasklet); if (vcc->pop) vcc->pop(vcc, skb); else @@ -1606,10 +1625,10 @@ FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); txq->txing++; - spin_unlock_irqrestore(&fore200e->tx_lock, flags); - + tasklet_enable(&fore200e->tasklet); + /* ensure DMA synchronisation */ - fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); + fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), @@ -1934,8 +1953,7 @@ return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0; case ATM_QUERYLOOP: - return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ? - -EFAULT : 0; + return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ? -EFAULT : 0; } return -ENOSYS; /* not implemented */ @@ -1976,7 +1994,7 @@ /* update rate control parameters */ fore200e_rate_ctrl(qos, &fore200e_vcc->rate); - set_bit(ATM_VF_HASQOS,&vcc->flags); + set_bit(ATM_VF_HASQOS, &vcc->flags); return 0; } @@ -1997,6 +2015,8 @@ printk(FORE200E "IRQ %s reserved for device %s\n", fore200e_irq_itoa(fore200e->irq), fore200e->name); + tasklet_init(&fore200e->tasklet, fore200e_tasklet, (unsigned long)fore200e); + fore200e->state = FORE200E_STATE_IRQ; return 0; } @@ -2338,7 +2358,6 @@ DPRINTK(2, "device %s being initialized\n", fore200e->name); - spin_lock_init(&fore200e->tx_lock); init_MUTEX(&fore200e->rate_sf); cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET); @@ -2714,7 +2733,7 @@ if (media_index < 0 || media_index > 4) media_index = 5; - switch(fore200e->loop_mode) { + switch (fore200e->loop_mode) { case ATM_LM_NONE: oc3_index = 0; break; case ATM_LM_LOC_PHY: oc3_index = 1; @@ -2900,21 +2919,24 @@ #ifdef MODULE -unsigned int -init_module(void) +static unsigned int __init +fore200e_module_init(void) { DPRINTK(1, "module loaded\n"); return fore200e_detect() == 0; } -void -cleanup_module(void) +static void __exit +fore200e_module_cleanup(void) { while (fore200e_boards) { fore200e_cleanup(&fore200e_boards); } DPRINTK(1, "module being removed\n"); } + +module_init(fore200e_module_init); +module_exit(fore200e_module_cleanup); #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/fore200e.h linux/drivers/atm/fore200e.h --- v2.3.99-pre5/linux/drivers/atm/fore200e.h Mon Mar 27 08:08:23 2000 +++ linux/drivers/atm/fore200e.h Fri Apr 14 09:37:10 2000 @@ -1,3 +1,4 @@ +/* $Id: fore200e.h,v 1.4 2000/04/14 10:10:34 davem Exp $ */ #ifndef _FORE200E_H #define _FORE200E_H @@ -827,14 +828,18 @@ # else /* in that case, we'll need to add an extra indirection, e.g. fore200e->bus->dma_direction[ fore200e_dma_direction ] */ -# error PCI and SBUS DMA direction flags differ! +# error PCI and SBUS DMA direction flags have different values! # endif # else -# define FORE200E_DMA_BIDIRECTIONAL SBA_DMA_BIDIRECTIONAL -# define FORE200E_DMA_TODEVICE SBA_DMA_TODEVICE -# define FORE200E_DMA_FROMDEVICE SBA_DMA_FROMDEVICE +# define FORE200E_DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL +# define FORE200E_DMA_TODEVICE SBUS_DMA_TODEVICE +# define FORE200E_DMA_FROMDEVICE SBUS_DMA_FROMDEVICE # endif #else +# ifndef CONFIG_ATM_FORE200E_PCA +# warning compiling the fore200e driver without any hardware support enabled! +# include +# endif # define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL # define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE # define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE @@ -874,7 +879,7 @@ struct stats* stats; /* last snapshot of the stats */ struct semaphore rate_sf; /* protects rate reservation ops */ - spinlock_t tx_lock; /* protects tx ops */ + struct tasklet_struct tasklet; /* performs interrupt work */ } fore200e_t; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/horizon.c linux/drivers/atm/horizon.c --- v2.3.99-pre5/linux/drivers/atm/horizon.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/atm/horizon.c Fri Apr 14 09:37:10 2000 @@ -2490,10 +2490,15 @@ return -EINVAL; } + // prevent module unload while sleeping (kmalloc) + // doing this any earlier would complicate more error return paths + MOD_INC_USE_COUNT; + // get space for our vcc stuff and copy parameters into it vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL); if (!vccp) { PRINTK (KERN_ERR, "out of memory!"); + MOD_DEC_USE_COUNT; return -ENOMEM; } *vccp = vcc; @@ -2525,6 +2530,7 @@ if (error) { PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources"); kfree (vccp); + MOD_DEC_USE_COUNT; return error; } @@ -2537,11 +2543,13 @@ if (rxtp->traffic_class != ATM_NONE) { if (dev->rxer[channel]) { PRINTD (DBG_ERR|DBG_VCC, "VC already open for RX"); - return -EBUSY; + error = -EBUSY; } - error = hrz_open_rx (dev, channel); + if (!error) + error = hrz_open_rx (dev, channel); if (error) { kfree (vccp); + MOD_DEC_USE_COUNT; return error; } // this link allows RX frames through @@ -2556,7 +2564,6 @@ // indicate readiness set_bit(ATM_VF_READY,&atm_vcc->flags); - MOD_INC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/uPD98402.c linux/drivers/atm/uPD98402.c --- v2.3.99-pre5/linux/drivers/atm/uPD98402.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/atm/uPD98402.c Fri Apr 14 09:37:10 2000 @@ -141,7 +141,7 @@ return fetch_stats(dev,(struct sonet_stats *) arg, cmd == SONET_GETSTATZ); case SONET_SETFRAMING: - return set_framing(dev,(int) arg); + return set_framing(dev,(int) (long) arg); case SONET_GETFRAMING: return put_user(PRIV(dev)->framing,(int *) arg) ? -EFAULT : 0; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.3.99-pre5/linux/drivers/block/Config.in Tue Apr 11 15:09:16 2000 +++ linux/drivers/block/Config.in Wed Apr 12 09:38:52 2000 @@ -41,14 +41,16 @@ tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET +tristate 'Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM N +if [ "$CONFIG_BLK_DEV_LVM" != "n" ]; then + bool ' LVM information in proc filesystem' CONFIG_LVM_PROC_FS Y +fi + bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED $CONFIG_BLK_DEV_MD #dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING $CONFIG_BLK_DEV_MD #dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD -if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then - bool ' Boot support (linear, striped)' CONFIG_MD_BOOT -fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.3.99-pre5/linux/drivers/block/floppy.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/block/floppy.c Mon Apr 24 18:17:45 2000 @@ -201,7 +201,7 @@ static unsigned short virtual_dma_port=0x3f0; void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs); static int set_dor(int fdc, char mask, char data); -static void register_devfs_entries (int drive); +static void register_devfs_entries (int drive) __init; static devfs_handle_t devfs_handle = NULL; #define K_64 0x10000 /* 64KB */ @@ -3582,7 +3582,7 @@ #undef IN } -static void config_types(void) +static void __init config_types(void) { int first=1; int drive; @@ -3836,7 +3836,7 @@ revalidate: floppy_revalidate, }; -static void register_devfs_entries (int drive) +static void __init register_devfs_entries (int drive) { int base_minor, i; static char *table[] = @@ -4075,8 +4075,8 @@ printk("\n"); } else DPRINT("botched floppy option\n"); - DPRINT("Read linux/drivers/block/README.fd\n"); - return 1; + DPRINT("Read linux/Documentation/floppy.txt\n"); + return 0; } static int have_no_fdc= -EIO; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.3.99-pre5/linux/drivers/block/genhd.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/genhd.c Wed Apr 12 09:38:52 2000 @@ -37,16 +37,12 @@ #ifdef CONFIG_PARPORT parport_init(); #endif - /* - * I2O must come before block and char as the I2O layer may - * in future claim devices that block/char most not touch. - */ -#ifdef CONFIG_I2O - i2o_init(); -#endif chr_dev_init(); blk_dev_init(); sti(); +#ifdef CONFIG_I2O + i2o_init(); +#endif #ifdef CONFIG_BLK_DEV_DAC960 DAC960_Initialize(); #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.3.99-pre5/linux/drivers/block/ll_rw_blk.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/block/ll_rw_blk.c Wed Apr 26 12:13:16 2000 @@ -1077,6 +1077,12 @@ #ifdef CONFIG_DASD dasd_init(); #endif +#ifdef CONFIG_SUN_JSFLASH + jsfd_init(); +#endif +#ifdef CONFIG_BLK_DEV_LVM + lvm_init(); +#endif return 0; }; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/lvm.c linux/drivers/block/lvm.c --- v2.3.99-pre5/linux/drivers/block/lvm.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/block/lvm.c Wed Apr 12 09:38:52 2000 @@ -287,7 +287,7 @@ static char pv_name[NAME_LEN]; /* static char rootvg[NAME_LEN] = { 0, }; */ static uint lv_open = 0; -static const char *const lvm_name = LVM_NAME; +const char *const lvm_name = LVM_NAME; static int lock = 0; static int loadtime = 0; static uint vg_count = 0; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.3.99-pre5/linux/drivers/block/md.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/block/md.c Wed Apr 12 09:38:52 2000 @@ -46,10 +46,6 @@ #include -#ifdef CONFIG_MD_BOOT -extern kdev_t name_to_kdev_t(char *line) md__init; -#endif - #define DEBUG 0 #if DEBUG # define dprintk(x...) printk(x) @@ -1805,136 +1801,6 @@ #undef OUT -/* support old ioctls/init - cold add only */ -int do_md_add(mddev_t *mddev, kdev_t dev) -{ - int err; - mdk_rdev_t *rdev; - - if (mddev->sb || mddev->pers) - return -EBUSY; - err = md_import_device(dev, 0); - if (err) return err; - rdev = find_rdev_all(dev); - if (!rdev) { - MD_BUG(); - return -EINVAL; - } - rdev->old_dev = dev; - rdev->desc_nr = mddev->nb_dev; - bind_rdev_to_array(rdev, mddev); - return 0; -} - -#define SET_SB(x,v) mddev->sb->x = v -#define SET_RSB(x,y) mddev->sb->disks[nr].x = y -static void autorun_array (mddev_t *mddev); -int do_md_start(mddev_t *mddev, int info) -{ - int pers = (info & 0xFF0000UL)>>16; -// int fault= (info & 0x00FF00UL)>>8; - int factor=(info & 0x0000FFUL); - - struct md_list_head *tmp; - mdk_rdev_t *rdev, *rdev0=NULL; - int err = 0; - - if (mddev->sb) { - printk("array md%d already has superbloc!!\n", - mdidx(mddev)); - return -EBUSY; - } - if (pers==1 || pers==2) { - /* non-persistant super block */ - int devs = mddev->nb_dev; - if (alloc_array_sb(mddev)) - return -ENOMEM; - mddev->sb->major_version = MD_MAJOR_VERSION; - mddev->sb->minor_version = MD_MINOR_VERSION; - mddev->sb->patch_version = MD_PATCHLEVEL_VERSION; - mddev->sb->ctime = CURRENT_TIME; - - SET_SB(level,pers_to_level(pers)); - SET_SB(size,0); - SET_SB(nr_disks, devs); - SET_SB(raid_disks, devs); - SET_SB(md_minor,mdidx(mddev)); - SET_SB(not_persistent, 1); - - - SET_SB(state, 1<sb->md_magic = MD_SB_MAGIC; - - /* - * Generate a 128 bit UUID - */ - get_random_bytes(&mddev->sb->set_uuid0, 4); - get_random_bytes(&mddev->sb->set_uuid1, 4); - get_random_bytes(&mddev->sb->set_uuid2, 4); - get_random_bytes(&mddev->sb->set_uuid3, 4); - - /* add each disc */ - ITERATE_RDEV(mddev,rdev,tmp) { - int nr, size; - nr = rdev->desc_nr; - SET_RSB(number,nr); - SET_RSB(major,MAJOR(rdev->dev)); - SET_RSB(minor,MINOR(rdev->dev)); - SET_RSB(raid_disk,nr); - SET_RSB(state,6); /* ACTIVE|SYNC */ - size = calc_dev_size(rdev->dev, mddev, 0); - rdev->sb_offset = calc_dev_sboffset(rdev->dev, mddev, 0); - - if (!mddev->sb->size || (mddev->sb->size > size)) - mddev->sb->size = size; - } - sync_sbs(mddev); - err = do_md_run(mddev); - if (err) - do_md_stop(mddev, 0); - } else { - /* persistant super block - ignore the info and read the superblocks */ - ITERATE_RDEV(mddev,rdev,tmp) { - if ((err = read_disk_sb(rdev))) { - printk("md: could not read %s's sb, not importing!\n", - partition_name(rdev->dev)); - break; - } - if ((err = check_disk_sb(rdev))) { - printk("md: %s has invalid sb, not importing!\n", - partition_name(rdev->dev)); - break; - } - rdev->desc_nr = rdev->sb->this_disk.number; - if (!rdev0) rdev0=rdev; - if (!uuid_equal(rdev0, rdev)) { - printk("%s has different UUID to %s .. dropping\n", - partition_name(rdev->dev), - partition_name(rdev0->dev)); - err = -EINVAL; - break; - } - if (!sb_equal(rdev0->sb, rdev->sb)) { - printk("%s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev)); - err = -EINVAL; - break; - } - } - if (!err) - autorun_array(mddev); - } - return err; -} -#undef SET_SB -#undef SET_RSB /* * We have to safely support old arrays too. */ @@ -2703,59 +2569,6 @@ } default: } - /* handle "old style" ioctls */ - switch (cmd) - { - case START_MD: - if (!mddev) - return -ENODEV; - err = lock_mddev(mddev); - if (err) { - printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd); - goto abort; - } - err = do_md_start(mddev, (int) arg); - if (err) { - printk("couldn't mdstart\n"); - goto abort_unlock; - } - goto done_unlock; - case STOP_MD: - if (!mddev) - return -ENODEV; - err = lock_mddev(mddev); - if (err) { - printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd); - goto abort_unlock; - } - err = do_md_stop(mddev, 0); - if (err) { - printk("couldn't mdstop\n"); - goto abort_unlock; - } - goto done_unlock; - case REGISTER_DEV: - /* add this device to an unstarted array, - * create the array if needed */ - if (!mddev) - mddev = alloc_mddev(dev); - if (!mddev) { - err = -ENOMEM; - goto abort; - } - err = lock_mddev(mddev); - if (err) { - printk("ioctl, reason %d, cmd %d\n", err, cmd); - goto abort; - } - err = do_md_add(mddev, to_kdev_t((dev_t) arg)); - if (err) { - printk("do_md_add failed %d\n", err); - goto abort_unlock; - } - goto done_unlock; - } - switch (cmd) { case SET_ARRAY_INFO: @@ -3369,94 +3182,11 @@ return; } -#ifdef CONFIG_MD_BOOT -#define MAX_MD_BOOT_DEVS 16 -struct { - unsigned long set; - int pers[MAX_MD_BOOT_DEVS]; - kdev_t devices[MAX_MD_BOOT_DEVS][MAX_REAL]; -} md_setup_args md__initdata = { - 0,{0},{{0}} -}; - -/* - * Parse the command-line parameters given our kernel, but do not - * actually try to invoke the MD device now; that is handled by - * md_setup_drive after the low-level disk drivers have initialised. - * - * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which - * assigns the task of parsing integer arguments to the - * invoked program now). Added ability to initialise all - * the MD devices (by specifying multiple "md=" lines) - * instead of just one. -- KTK - */ -static int __init md_setup(char *str) -{ - int minor, level, factor, fault, i; - kdev_t device; - char *devnames, *pername; - - if(get_option(&str, &minor) != 2 || /* MD Number */ - get_option(&str, &level) != 2 || /* RAID Personality */ - get_option(&str, &factor) != 2 || /* Chunk Size */ - get_option(&str, &fault) != 2) { - printk("md: Too few arguments supplied to md=.\n"); - return 0; - } else if (minor >= MAX_MD_BOOT_DEVS) { - printk ("md: Minor device number too high.\n"); - return 0; - } else if (md_setup_args.set & (1 << minor)) { - printk ("md: Warning - md=%d,... has been specified twice;\n" - " will discard the first definition.\n", minor); - } - switch(level) { -#ifdef CONFIG_MD_LINEAR - case -1: - level = LINEAR<<16; - pername = "linear"; - break; -#endif -#ifdef CONFIG_MD_STRIPED - case 0: - level = STRIPED<<16; - pername = "striped"; - break; -#endif - default: - printk ("md: The kernel has not been configured for raid%d" - " support!\n", level); - return 0; - } - devnames = str; - for (i = 0; str; i++) { - if ((device = name_to_kdev_t(str))) { - md_setup_args.devices[minor][i] = device; - } else { - printk ("md: Unknown device name, %s.\n", str); - return 0; - } - if ((str = strchr(str, ',')) != NULL) - str++; - } - if (!i) { - printk ("md: No devices specified for md%d?\n", minor); - return 0; - } - - printk ("md: Will configure md%d (%s) from %s, below.\n", - minor, pername, devnames); - md_setup_args.devices[minor][i] = (kdev_t) 0; - md_setup_args.pers[minor] = level | factor | (fault << 8); - md_setup_args.set |= (1 << minor); - return 1; -} -#endif - static void md_geninit (void) { int i; - for(i = 0; i < MAX_MD_BOOT_DEVS; i++) { + for(i = 0; i < MAX_MD_DEVS; i++) { md_blocksizes[i] = 1024; md_size[i] = 0; md_maxreadahead[i] = MD_READAHEAD; @@ -3525,27 +3255,6 @@ md_geninit(); return (0); } - -#ifdef CONFIG_MD_BOOT -void __init md_setup_drive(void) -{ - int minor, i; - kdev_t dev; - mddev_t*mddev; - - for (minor = 0; minor < MAX_MD_BOOT_DEVS; minor++) { - if ((md_setup_args.set & (1 << minor)) == 0) - continue; - printk("md: Loading md%d.\n", minor); - mddev = alloc_mddev(MKDEV(MD_MAJOR,minor)); - for (i = 0; (dev = md_setup_args.devices[minor][i]); i++) - do_md_add (mddev, dev); - do_md_start (mddev, md_setup_args.pers[minor]); - } -} - -__setup("md=", md_setup); -#endif MD_EXPORT_SYMBOL(md_size); MD_EXPORT_SYMBOL(register_md_personality); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.3.99-pre5/linux/drivers/block/xd.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/block/xd.c Thu Apr 13 10:48:16 2000 @@ -1190,7 +1190,7 @@ { int i, integers[1 + 3*XD_MAXDRIVES]; - get_options (str, ARRAY_SIZE (ints), ints); + get_options (str, ARRAY_SIZE (integers), integers); if (integers[0]%3 != 0) { printk("xd: incorrect number of parameters for xd_geo\n"); return 1; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/block/xd.h linux/drivers/block/xd.h --- v2.3.99-pre5/linux/drivers/block/xd.h Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/xd.h Thu Apr 13 10:48:16 2000 @@ -103,9 +103,9 @@ const char *name; } XD_SIGNATURE; -void xd_setup (char *command,int *integers); +int xd_setup (char *); #ifndef MODULE -void xd_manual_geo_init (char *command,int *integers); +int xd_manual_geo_init (char *command); #endif /* MODULE */ static u_char xd_detect (u_char *controller, unsigned int *address); static u_char xd_initdrives (void (*init_drive)(u_char drive)); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.3.99-pre5/linux/drivers/cdrom/cdrom.c Tue Mar 7 14:32:25 2000 +++ linux/drivers/cdrom/cdrom.c Sat Apr 15 21:20:41 2000 @@ -465,10 +465,8 @@ if ((cdi = cdrom_find_device(dev)) == NULL) return -ENODEV; - /* just CD-RW for now. DVD-RW will come soon, CD-R and DVD-R - * need to be handled differently. */ - if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_CD_RW)) - return -EROFS; + if (fp->f_mode & FMODE_WRITE) + return -EROFS; /* if this was a O_NONBLOCK open and we should honor the flags, * do a quick open without drive/disc integrity checks. */ @@ -964,7 +962,7 @@ } } cgc->cmd[9] = cgc->buflen; - cgc->data_direction = CGC_DATA_WRITE; + cgc->data_direction = CGC_DATA_READ; } static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type) @@ -986,7 +984,7 @@ } } cgc->cmd[9] = cgc->buflen; - cgc->data_direction = CGC_DATA_READ; + cgc->data_direction = CGC_DATA_WRITE; } static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) @@ -1648,7 +1646,7 @@ if (tracks.data > 0) return CDS_DATA_1; /* Policy mode off */ - cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognise!\n"); + cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n"); return CDS_NO_INFO; } @@ -2529,33 +2527,31 @@ initialized = 1; } -#endif /* endif CONFIG_SYSCTL */ - -#ifdef MODULE static void cdrom_sysctl_unregister(void) { -#ifdef CONFIG_SYSCTL unregister_sysctl_table(cdrom_sysctl_header); -#endif } -int init_module(void) +#endif /* CONFIG_SYSCTL */ + +static int __init cdrom_init(void) { #ifdef CONFIG_SYSCTL cdrom_sysctl_register(); #endif - devfs_handle = devfs_mk_dir (NULL, "cdroms", 6, NULL); + devfs_handle = devfs_mk_dir(NULL, "cdroms", 6, NULL); return 0; } -void cleanup_module(void) +static void __exit cdrom_exit(void) { printk(KERN_INFO "Uniform CD-ROM driver unloaded\n"); #ifdef CONFIG_SYSCTL cdrom_sysctl_unregister(); -#endif /* CONFIG_SYSCTL */ - devfs_unregister (devfs_handle); +#endif + devfs_unregister(devfs_handle); } -#endif /* endif MODULE */ +module_init(cdrom_init); +module_exit(cdrom_exit); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c --- v2.3.99-pre5/linux/drivers/cdrom/cm206.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/cdrom/cm206.c Mon Apr 24 13:39:34 2000 @@ -1483,6 +1483,6 @@ #endif /* !MODULE */ /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D__SMP__ -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c" + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c" * End: */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.3.99-pre5/linux/drivers/char/Config.in Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/Config.in Wed Apr 12 09:16:31 2000 @@ -210,13 +210,13 @@ dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT fi fi - dep_tristate 'CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV + dep_tristate ' CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then if [ "CONFIG_PARPORT_1284" != "n" ]; then - dep_tristate 'CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT + dep_tristate ' CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT fi if [ "$CONFIG_USB" != "n" ]; then - dep_tristate 'CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB + dep_tristate ' CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB fi fi dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV $CONFIG_I2C diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/README.computone linux/drivers/char/README.computone --- v2.3.99-pre5/linux/drivers/char/README.computone Sun Nov 7 16:37:34 1999 +++ linux/drivers/char/README.computone Mon Apr 24 13:39:34 2000 @@ -5,24 +5,30 @@ Release Notes For Linux Kernel 2.2 These notes have been tested on Linux kernels 2.0 and 2.2. +Please refer to Documentation/computone.txt for information on the driver +that is included with the kernel sources. -Version: 1.2.4 -Date: 08/04/99 + +Version: 1.2.9 +Date: 04/12/2000 Fixes and Updates: Doug McNash Historical Author: Andrew Manison +Kernel Integration: Mike Warfield 1. INTRODUCTION This driver supports the entire family of Intelliport II/Plus controllers -with the exception of the MicroChannel controllers. +with the exception of the MicroChannel controllers. This driver was developed on the v2.0.x Linux source tree and has been -tested up to v2.2.10; it will probably not work with earlier v1.X kernels, +tested up to v2.2.14; it will probably not work with earlier v1.X kernels, and has not yet been tested on the v2.1.x tree. The most likely problems will be in patching the kernel sources to support the driver. For this reason there are 2 different patch files for 2.0.XX and 2.2.XX kernels. Make sure you use the right one! -Someday soon it should be included in the 2.3.XX tree. +Note that a version (1.2.5) is included in the 2.2.12+ kernels so this +will not be a new install but and upgrade. + 2. QUICK INSTALLATION @@ -31,10 +37,11 @@ `cat /proc/ioports`. Set the card dip switches to that free address. You may need to configure your BIOS to reserve the irq for the ISA card. PCI and EISA parameters are set - automagically and need no attention. Insert card into - computer with the power off before or after driver installation. + automagically and need only be set to nonzero values. + Insert card into computer with the power off before or after + driver installation. -Software - +Software - New Installation Module installation: @@ -74,6 +81,11 @@ j) reboot using this kernel k) make and run ip2/mkip2dev +Software - Upgrades + +a) Install new sources in proper location, usually /usr/src/linux/drivers/char +b) Follow steps above to create new kernel or modules + 3. INSTALLATION Previously, the driver sources were packaged with a set of patch files @@ -82,7 +94,8 @@ the patches if needed, and build any utilities needed. What you recieve may be a single patch file in conventional kernel patch format build script. That form can also be applied by -running patch -p1 < ThePatchFile. Otherwise run ip2build. +running patch -p1 < ThePatchFile. Otherwise the drivers source may be +a tar file, then untar and run ip2build if a new installation. The driver can be installed as a module (recommended) or built into the kernel. This is selected as for other drivers through the `make config` @@ -97,20 +110,28 @@ where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11, 12,15) and addr1-4 are the base addresses for up to four controllers. If the irqs are not specified the driver uses the default in ip2/ip2.h (which -selects polled mode). If no base addresses are specified the defaults in -ip2.h are used. If you are autoloading the driver module with kerneld or -kmod the base addresses and interrupt number must also be set in ip2/ip2.h -and recompile or just insert and options line in /etc/modules.conf or both. -The options line is equivalent to the command line and takes precidence over -what is in ip2.h. +selects polled mode). The io addresses are set to io=1 for PCI cards,i +io=2 for EISA cards or io=[some valid ISA address] for ISA cards. If no +base addresses are specified the defaults in ip2.h are used. If you are +autoloading the driver module with kerneld or kmod the base addresses and +interrupt number must also be set in ip2/ip2.h and recompile or just insert +an options line in /etc/modules.conf or both. The command line takes +precidence over the options line which takes precidence over the defaults +in ip2.h. + +command line sample: + + modprobe ip2 io=1,0x328 irq=1,10 /etc/modules.conf sample: + options ip2 io=1,0x328 irq=1,10 alias char-major-71 ip2 alias char-major-72 ip2 alias char-major-73 ip2 -equivelant ip2.h: +the equivelant ip2.h: + static ip2config_t ip2config = { {1,10,0,0}, @@ -122,15 +143,17 @@ } }; -Specifying an invalid or in-use irq will default the driver into +Specifying an invalid or in-use ISA irq will default the driver into running in polled mode for that card. If all irq entries are 0 then -all cards will operate in polled mode. +all cards will operate in polled mode. Note that the PCI will be +assigned it's irq by the BIOS and may not match what you specify. +It must be non-zero otherwise it will be polled. Tarball Install: The whole tarfile should be untarred in the /usr/src/linux/drivers/char/ directory. Most files required for the driver are placed in the ip2 -subdirectory. Then execute the script +subdirectory. Then execute the script (for a new install only) ip2build @@ -149,7 +172,7 @@ If you select the driver as part of the kernel run : make depend - make zlilo (or whatever you do to create a bootable kernel) + make bzImage(,zlilo or whatever you do to create a bootable kernel) If you selected a module run : @@ -161,7 +184,8 @@ ports are created. With multiple boards and expansion boxes this will leave gaps in the sequence of device names. ip2mkdev uses Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and cuf0 - cuf255 for -callout devices. +callout devices. Note that the callout devices are going away in the +future and that is what the warning messages are trying to tell you. 4. USING THE DRIVERS @@ -181,7 +205,7 @@ corresponds to the maximum bit rates those chips are capable. For example if the baud base is 921600 and the baud divisor is 18 then the custom rate is 921600/18 = 51200 bps. See the setserial man page for -complete details. Of course if stty accepts the higher rates now you can +complete details. Of course, if stty accepts the higher rates now you can use that as well as the standard ioctls(). 5. NOTES @@ -190,6 +214,14 @@ in all configurations of Linux. If there is any anomalous behaviour that does not match the standard serial port's behaviour please let us know. -Author: dmcnash@computine.com +Some installations report that characters fail to echo immediatly at a +terminal if the kernel/modules are compiled with the CONFIG_M386 and +the card is run in polling mode on a pentium class machine. Compiling +with a more appropriate processor flag or running on interrupt would be +the fix as well as the wise thing to do. + + + +Author: dougm@computone.com Testing: larryg@computone.com -Spport: support@computone.com +Support: support@computone.com diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c --- v2.3.99-pre5/linux/drivers/char/agp/agpgart_be.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/agp/agpgart_be.c Fri Apr 21 16:08:45 2000 @@ -81,7 +81,7 @@ #endif } -#ifdef __SMP__ +#ifdef CONFIG_SMP static atomic_t cpus_waiting; static void ipi_handler(void *null) @@ -102,9 +102,9 @@ barrier(); } #define global_cache_flush smp_flush_cache -#else /* __SMP__ */ +#else /* CONFIG_SMP */ #define global_cache_flush flush_cache -#endif /* __SMP__ */ +#endif /* CONFIG_SMP */ int agp_backend_acquire(void) { @@ -1764,6 +1764,30 @@ #endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_SIS + { PCI_DEVICE_ID_SI_630, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "630", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_540, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "540", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_620, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "620", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_530, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "530", + sis_generic_setup }, { PCI_DEVICE_ID_SI_630, PCI_VENDOR_ID_SI, SIS_GENERIC, diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/amiserial.c linux/drivers/char/amiserial.c --- v2.3.99-pre5/linux/drivers/char/amiserial.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/char/amiserial.c Fri Apr 21 15:17:57 2000 @@ -2066,7 +2066,7 @@ done: if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.3.99-pre5/linux/drivers/char/bttv.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/bttv.c Fri Apr 21 15:19:24 2000 @@ -725,6 +725,7 @@ { 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" }, { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master" }, { 0x6606217d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0x1200bd11, BTTV_PINNACLERAVE, "Pinnacle PCTV Rave" }, { 0, -1, NULL } }; @@ -887,6 +888,10 @@ { "TView99 CPH063", 3, 1, 0, 2, 0x551e00, { 2, 0, 1, 1}, { 0x551400, 0x551200, 0, 0, 0x551200 }, 0,1,1,1,1,0 }, + { "Pinnacle PCTV Rave", + 3, 1, 0, 2, 0x03000F, { 2, 3, 1, 1}, { 2, 0, 0, 0, 1},0, + 1,1,1,1,0 }, + }; #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard)) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/bttv.h linux/drivers/char/bttv.h --- v2.3.99-pre5/linux/drivers/char/bttv.h Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/bttv.h Fri Apr 21 15:19:24 2000 @@ -271,6 +271,7 @@ #define BTTV_TYPHOON_TVIEW 0x24 #define BTTV_PXELVWPLTVPRO 0x25 #define BTTV_MAGICTVIEW063 0x26 +#define BTTV_PINNACLERAVE 0x27 #define AUDIO_TUNER 0x00 diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v2.3.99-pre5/linux/drivers/char/busmouse.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/char/busmouse.c Tue Apr 25 17:38:33 2000 @@ -1,22 +1,11 @@ /* - * linux/drivers/char/mouse.c + * linux/drivers/char/busmouse.c * - * Copyright (C) 1995 - 1998 Russell King - * Protocol taken from busmouse.c + * Copyright (C) 1995 - 1998 Russell King + * Protocol taken from original busmouse.c * read() waiting taken from psaux.c * * Medium-level interface for quadrature or bus mice. - * - * Currently, the majority of kernel busmice drivers in the - * kernel common code to talk to userspace. This driver - * attempts to rectify this situation by presenting a - * simple and safe interface to the mice and user. - * - * This driver: - * - is SMP safe - * - handles multiple opens - * - handles the wakeups and locking - * - has optional blocking reads */ #include @@ -40,10 +29,8 @@ /* Uncomment this if your mouse drivers expect the kernel to * return with EAGAIN if the mouse does not have any events * available, even if the mouse is opened in nonblocking mode. - * - * Should this be on a per-mouse basis? If so, add an entry to - * the struct busmouse structure and add the relevent flag to - * the drivers. + * Please report use of this "feature" to the author using the + * above address. */ /*#define BROKEN_MOUSE*/ @@ -56,7 +43,6 @@ struct fasync_struct *fasyncptr; char active; char buttons; - char latch_buttons; char ready; int dxpos; int dypos; @@ -75,32 +61,19 @@ static struct busmouse_data *busmouse_data[NR_MICE]; static DECLARE_MUTEX(mouse_sem); -/* a mouse driver just has to interface with these functions - * These are !!!OLD!!! Do not use!!! - */ -void add_mouse_movement(int dx, int dy) -{ - struct busmouse_data *mse = busmouse_data[MINOR_TO_MOUSE(6)]; - - mse->dxpos += dx; - mse->dypos += dy; - mse->ready = 1; - wake_up(&mse->wait); -} - -int add_mouse_buttonchange(int set, int value) -{ - struct busmouse_data *mse = busmouse_data[MINOR_TO_MOUSE(6)]; - - mse->buttons = (mse->buttons & ~set) ^ value; - mse->ready = 1; - wake_up(&mse->wait); - return mse->buttons; -} - -/* New interface. !!! Use this one !!! - * These routines will most probably be called from interrupt. +/** + * busmouse_add_movement - notification of a change of mouse position + * @mousedev: mouse number + * @dx: delta X movement + * @dy: delta Y movement + * @buttons: new button state + * + * Updates the mouse position and button information. The mousedev + * parameter is the value returned from register_busmouse. The + * movement information is updated, and the new button state is + * saved. A waiting user thread is woken. */ + void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons) { struct busmouse_data *mse = busmouse_data[mousedev]; @@ -113,7 +86,6 @@ add_mouse_randomness((buttons << 16) + (dy << 8) + dx); mse->buttons = buttons; -// mse->latch_buttons |= buttons; mse->dxpos += dx; mse->dypos += dy; mse->ready = 1; @@ -143,6 +115,17 @@ } } +/** + * busmouse_add_movement - notification of a change of mouse position + * @mousedev: mouse number + * @dx: delta X movement + * @dy: delta Y movement + * + * Updates the mouse position. The mousedev parameter is the value + * returned from register_busmouse. The movement information is + * updated, and a waiting user thread is woken. + */ + void busmouse_add_movement(int mousedev, int dx, int dy) { struct busmouse_data *mse = busmouse_data[mousedev]; @@ -150,6 +133,18 @@ busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons); } +/** + * busmouse_add_buttons - notification of a change of button state + * @mousedev: mouse number + * @clear: mask of buttons to clear + * @eor: mask of buttons to change + * + * Updates the button state. The mousedev parameter is the value + * returned from register_busmouse. The buttons are updated by: + * new_state = (old_state & ~clear) ^ eor + * A waiting user thread is woken up. + */ + void busmouse_add_buttons(int mousedev, int clear, int eor) { struct busmouse_data *mse = busmouse_data[mousedev]; @@ -191,7 +186,6 @@ static int busmouse_open(struct inode *inode, struct file *file) { struct busmouse_data *mse; - unsigned long flags; unsigned int mousedev; int ret = -ENODEV; @@ -219,7 +213,7 @@ MOD_INC_USE_COUNT; - spin_lock_irqsave(&mse->lock, flags); + spin_lock_irq(&mse->lock); mse->ready = 0; mse->dxpos = 0; @@ -229,7 +223,7 @@ else mse->buttons = 7; - spin_unlock_irqrestore(&mse->lock, flags); + spin_unlock_irq(&mse->lock); end: up(&mouse_sem); return ret; @@ -244,21 +238,20 @@ { struct busmouse_data *mse = (struct busmouse_data *)file->private_data; DECLARE_WAITQUEUE(wait, current); - unsigned long flags; int dxpos, dypos, buttons; if (count < 3) return -EINVAL; - spin_lock_irqsave(&mse->lock, flags); + spin_lock_irq(&mse->lock); if (!mse->ready) { #ifdef BROKEN_MOUSE - spin_unlock_irqrestore(&mse->lock, flags); + spin_unlock_irq(&mse->lock); return -EAGAIN; #else if (file->f_flags & O_NONBLOCK) { - spin_unlock_irqrestore(&mse->lock, flags); + spin_unlock_irq(&mse->lock); return -EAGAIN; } @@ -266,9 +259,9 @@ repeat: set_current_state(TASK_INTERRUPTIBLE); if (!mse->ready && !signal_pending(current)) { - spin_unlock_irqrestore(&mse->lock, flags); + spin_unlock_irq(&mse->lock); schedule(); - spin_lock_irqsave(&mse->lock, flags); + spin_lock_irq(&mse->lock); goto repeat; } @@ -276,7 +269,7 @@ remove_wait_queue(&mse->wait, &wait); if (signal_pending(current)) { - spin_unlock_irqrestore(&mse->lock, flags); + spin_unlock_irq(&mse->lock); return -ERESTARTSYS; } #endif @@ -285,7 +278,6 @@ dxpos = mse->dxpos; dypos = mse->dypos; buttons = mse->buttons; -// mse->latch_buttons = mse->buttons; if (dxpos < -127) dxpos =- 127; @@ -306,7 +298,7 @@ */ mse->ready = mse->dxpos || mse->dypos; - spin_unlock_irqrestore(&mse->lock, flags); + spin_unlock_irq(&mse->lock); /* Write out data to the user. Format is: * byte 0 - identifer (0x80) and (inverted) mouse buttons @@ -326,6 +318,7 @@ return count; } +/* No kernel lock held - fine */ static unsigned int busmouse_poll(struct file *file, poll_table *wait) { struct busmouse_data *mse = (struct busmouse_data *)file->private_data; @@ -412,6 +405,7 @@ int unregister_busmouse(int mousedev) { int err = -EINVAL; + if (mousedev < 0) return 0; if (mousedev >= NR_MICE) { @@ -434,7 +428,7 @@ goto fail; } - err=misc_deregister(&busmouse_data[mousedev]->miscdev); + err = misc_deregister(&busmouse_data[mousedev]->miscdev); kfree(busmouse_data[mousedev]); busmouse_data[mousedev] = NULL; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/busmouse.h linux/drivers/char/busmouse.h --- v2.3.99-pre5/linux/drivers/char/busmouse.h Mon Mar 27 08:08:23 2000 +++ linux/drivers/char/busmouse.h Tue Apr 25 17:38:33 2000 @@ -1,12 +1,12 @@ /* - * linux/drivers/char/mouse.h + * linux/drivers/char/busmouse.h * * Copyright (C) 1995 - 1998 Russell King * * Prototypes for generic busmouse interface */ -#ifndef MOUSE_H -#define MOUSE_H +#ifndef BUSMOUSE_H +#define BUSMOUSE_H struct busmouse { int minor; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/cpia.c linux/drivers/char/cpia.c --- v2.3.99-pre5/linux/drivers/char/cpia.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/cpia.c Tue Apr 25 16:53:13 2000 @@ -1577,9 +1577,13 @@ cmd[7] = 0; retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data); - if (retval) + if (retval) { DBG("%x - failed, retval=%d\n", command, retval); - else { + if (command == CPIA_COMMAND_GetColourParams || + command == CPIA_COMMAND_GetColourBalance || + command == CPIA_COMMAND_GetExposure) + up(&cam->param_lock); + } else { switch(command) { case CPIA_COMMAND_GetCPIAVersion: cam->params.version.firmwareVersion = data[0]; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/efirtc.c linux/drivers/char/efirtc.c --- v2.3.99-pre5/linux/drivers/char/efirtc.c Sat Feb 26 22:31:44 2000 +++ linux/drivers/char/efirtc.c Fri Apr 21 15:21:24 2000 @@ -39,7 +39,7 @@ #include #include -#define EFI_RTC_VERSION "0.1" +#define EFI_RTC_VERSION "0.2" #define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT) /* @@ -47,7 +47,7 @@ */ #define EFI_RTC_EPOCH 1998 -static spinlock_t efi_rtc_lock; +static spinlock_t efi_rtc_lock = SPIN_LOCK_UNLOCKED; static int efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); @@ -153,6 +153,8 @@ efi_time_t eft; efi_time_cap_t cap; struct rtc_time wtime; + struct rtc_wkalrm *ewp; + unsigned char enabled, pending; switch (cmd) { case RTC_UIE_ON: @@ -203,6 +205,50 @@ spin_unlock_irqrestore(&efi_rtc_lock,flags); return status == EFI_SUCCESS ? 0 : -EINVAL; + + case RTC_WKALM_SET: + + if (!capable(CAP_SYS_TIME)) return -EACCES; + + ewp = (struct rtc_wkalrm *)arg; + + if ( get_user(enabled, &ewp->enabled) + || copy_from_user(&wtime, &ewp->time, sizeof(struct rtc_time)) ) + return -EFAULT; + + convert_to_efi_time(&wtime, &eft); + + spin_lock_irqsave(&efi_rtc_lock, flags); + /* + * XXX Fixme: + * As of EFI 0.92 with the firmware I have on my + * machine this call does not seem to work quite + * right + */ + status = efi.set_wakeup_time((efi_bool_t)enabled, &eft); + + spin_unlock_irqrestore(&efi_rtc_lock,flags); + + return status == EFI_SUCCESS ? 0 : -EINVAL; + + case RTC_WKALM_RD: + + spin_lock_irqsave(&efi_rtc_lock, flags); + + status = efi.get_wakeup_time((efi_bool_t *)&enabled, (efi_bool_t *)&pending, &eft); + + spin_unlock_irqrestore(&efi_rtc_lock,flags); + + if (status != EFI_SUCCESS) return -EINVAL; + + ewp = (struct rtc_wkalrm *)arg; + + if ( put_user(enabled, &ewp->enabled) + || put_user(pending, &ewp->pending)) return -EFAULT; + + convert_from_efi_time(&eft, &wtime); + + return copy_to_user((void *)&ewp->time, &wtime, sizeof(struct rtc_time)); } return -EINVAL; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/fip_firm.h linux/drivers/char/ip2/fip_firm.h --- v2.3.99-pre5/linux/drivers/char/ip2/fip_firm.h Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/ip2/fip_firm.h Mon Apr 24 13:39:35 2000 @@ -2,10 +2,10 @@ /* -31232 bytes read from ff.lod */ unsigned char fip_firm[] __initdata = { -0x3C,0x42,0x8A,0xE1,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x57,0x65,0x64,0x20,0x4A,0x75,0x6E,0x20,0x32,0x33,0x20,0x31,0x35,0x3A,0x33,0x30, -0x3A,0x31,0x33,0x20,0x31,0x39,0x39,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0xE9,0x68,0x0F,0x42,0x65,0x47,0x69,0x4E,0x6E,0x49,0x6E,0x47,0x20,0x6F,0x46,0x20, +0x3C,0x42,0x37,0x18,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x57,0x65,0x64,0x20,0x44,0x65,0x63,0x20,0x30,0x31,0x20,0x31,0x32,0x3A,0x32,0x34, +0x3A,0x33,0x30,0x20,0x31,0x39,0x39,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xE9,0x6C,0x0F,0x42,0x65,0x47,0x69,0x4E,0x6E,0x49,0x6E,0x47,0x20,0x6F,0x46,0x20, 0x63,0x4F,0x64,0x45,0xCC,0x13,0x5A,0x15,0xE8,0x16,0x76,0x18,0x04,0x1A,0x92,0x1B, 0x20,0x1D,0xAE,0x1E,0x3C,0x20,0xCA,0x21,0x58,0x23,0xE6,0x24,0x74,0x26,0x02,0x28, 0x90,0x29,0x1E,0x2B,0xAC,0x2C,0x3A,0x2E,0xC8,0x2F,0x56,0x31,0xE4,0x32,0x72,0x34, @@ -18,7 +18,7 @@ 0x53,0x33,0xDB,0x25,0x07,0x00,0x75,0x0A,0x8A,0x1E,0x08,0x01,0x83,0xE3,0x0C,0xEB, 0x20,0x90,0x3C,0x01,0x75,0x0A,0x8A,0x1E,0x08,0x01,0x80,0xE3,0xC0,0xEB,0x12,0x90, 0x8A,0x1E,0x0D,0x01,0x3C,0x02,0x75,0x06,0x80,0xE3,0x0C,0xEB,0x04,0x90,0x80,0xE3, -0xC0,0x53,0x50,0x8B,0x1E,0xBA,0x13,0x8E,0xDB,0xE8,0x4C,0x65,0x55,0x8B,0xEC,0x53, +0xC0,0x53,0x50,0x8B,0x1E,0xBA,0x13,0x8E,0xDB,0xE8,0x6A,0x65,0x55,0x8B,0xEC,0x53, 0x1E,0x2B,0xC0,0x8E,0xD8,0x8B,0x5E,0x04,0xC1,0xE3,0x04,0x03,0x5E,0x06,0xD1,0xE3, 0x2E,0x8B,0x9F,0x44,0x00,0x8D,0x47,0x2A,0x1E,0x5A,0x1F,0x5B,0x5D,0xC3,0x55,0x8B, 0xEC,0x53,0x1E,0x2B,0xC0,0x8E,0xD8,0x8B,0x5E,0x04,0xC1,0xE3,0x04,0x03,0x5E,0x06, @@ -32,33 +32,33 @@ 0x26,0x8A,0x47,0x24,0x88,0x44,0x15,0x26,0x8A,0x47,0x5A,0x88,0x44,0x0E,0x33,0xC0, 0x89,0x44,0x06,0x89,0x44,0x08,0x88,0x44,0x0B,0x88,0x44,0x0A,0xB0,0x21,0xB4,0x64, 0x89,0x44,0x04,0x89,0x44,0x02,0xB0,0x55,0x88,0x44,0x0D,0x88,0x44,0x0C,0xE8,0x6A, -0x00,0x72,0x5B,0xE8,0xC9,0x00,0xE8,0xBD,0x10,0x89,0x44,0x08,0x80,0x7C,0x0F,0x01, -0x74,0x29,0xE8,0x2B,0x02,0xE8,0x7F,0x02,0x80,0x7C,0x0F,0x03,0x74,0x1D,0xE8,0xA5, +0x00,0x72,0x5B,0xE8,0xC9,0x00,0xE8,0xC1,0x10,0x89,0x44,0x08,0x80,0x7C,0x0F,0x01, +0x74,0x29,0xE8,0x2B,0x02,0xE8,0x7F,0x02,0x80,0x7C,0x0F,0x03,0x74,0x1D,0xE8,0xA9, 0x10,0x8B,0xF8,0x2B,0x44,0x08,0x3D,0xA0,0x0F,0x72,0x10,0x89,0x7C,0x08,0x33,0xC0, 0x87,0x44,0x06,0x85,0xC0,0x75,0x04,0xC6,0x44,0x0A,0xFF,0x8A,0x44,0x0A,0x84,0xC0, -0x75,0x0B,0xB8,0x08,0x00,0xE8,0x4C,0x4A,0xE8,0xA9,0x01,0x73,0xBF,0xE8,0x4F,0x01, -0x81,0x66,0x48,0x7F,0xFF,0x83,0x66,0x7A,0xBF,0xB0,0x02,0xE8,0x00,0x0E,0x8A,0x44, +0x75,0x0B,0xB8,0x08,0x00,0xE8,0x6A,0x4A,0xE8,0xA9,0x01,0x73,0xBF,0xE8,0x4F,0x01, +0x81,0x66,0x48,0x7F,0xFF,0x83,0x66,0x7A,0xBF,0xB0,0x02,0xE8,0x04,0x0E,0x8A,0x44, 0x0A,0x98,0x07,0x1F,0x5F,0x5E,0x5A,0x59,0x5B,0x5D,0xC3,0x81,0x4E,0x48,0x80,0x00, -0xB0,0x40,0xE8,0x1F,0x4A,0xE8,0x6B,0x40,0x73,0x2A,0xE8,0x49,0x10,0x8B,0xD8,0xB0, -0x05,0xE8,0x10,0x4A,0xF6,0x46,0x27,0x02,0x75,0x1A,0xE8,0x39,0x10,0x2B,0xC3,0x3D, -0x58,0x1B,0x72,0xEB,0x81,0x66,0x48,0x7F,0xFF,0xB0,0x02,0xE8,0xC0,0x0D,0xC6,0x44, -0x0A,0x01,0xF9,0xC3,0x83,0x4E,0x7A,0x40,0xF8,0xC3,0xFB,0xB0,0x01,0xE8,0xE4,0x49, -0xFA,0xE8,0x95,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xB0,0x4E,0xE6,0x0A,0xFB,0xB0, -0x01,0xE8,0xD0,0x49,0xFA,0xE8,0x81,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xC3,0xFA, -0xE8,0x76,0x1E,0xE4,0xEC,0x88,0x44,0x16,0xE4,0xE4,0x88,0x44,0x17,0xE4,0xF8,0x88, +0xB0,0x40,0xE8,0x3D,0x4A,0xE8,0x89,0x40,0x73,0x2A,0xE8,0x4D,0x10,0x8B,0xD8,0xB0, +0x05,0xE8,0x2E,0x4A,0xF6,0x46,0x27,0x02,0x75,0x1A,0xE8,0x3D,0x10,0x2B,0xC3,0x3D, +0x58,0x1B,0x72,0xEB,0x81,0x66,0x48,0x7F,0xFF,0xB0,0x02,0xE8,0xC4,0x0D,0xC6,0x44, +0x0A,0x01,0xF9,0xC3,0x83,0x4E,0x7A,0x40,0xF8,0xC3,0xFB,0xB0,0x01,0xE8,0x02,0x4A, +0xFA,0xE8,0x99,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xB0,0x4E,0xE6,0x0A,0xFB,0xB0, +0x01,0xE8,0xEE,0x49,0xFA,0xE8,0x85,0x1E,0xE4,0x0A,0x84,0xC0,0x75,0xF0,0xC3,0xFA, +0xE8,0x7A,0x1E,0xE4,0xEC,0x88,0x44,0x16,0xE4,0xE4,0x88,0x44,0x17,0xE4,0xF8,0x88, 0x44,0x18,0xE4,0xF0,0x88,0x44,0x19,0xE4,0x10,0x88,0x44,0x1A,0xE4,0x12,0x88,0x44, 0x1B,0xE4,0x14,0x88,0x44,0x1C,0xE4,0x34,0x88,0x44,0x1D,0xE4,0x36,0x88,0x44,0x1E, 0xE4,0xD8,0x24,0x01,0x8A,0xE0,0xE4,0xDA,0x24,0x02,0x0A,0xC4,0x88,0x44,0x1F,0x8A, -0x44,0x10,0xE8,0xC9,0x1F,0x8A,0x44,0x11,0xE8,0x31,0x21,0x8A,0x44,0x12,0xE8,0x85, -0x21,0x8A,0x44,0x13,0xE8,0x3F,0x21,0xC6,0x86,0xA1,0x00,0x00,0xE4,0x14,0x24,0x10, +0x44,0x10,0xE8,0xCD,0x1F,0x8A,0x44,0x11,0xE8,0x35,0x21,0x8A,0x44,0x12,0xE8,0x89, +0x21,0x8A,0x44,0x13,0xE8,0x43,0x21,0xC6,0x86,0xA1,0x00,0x00,0xE4,0x14,0x24,0x10, 0xE6,0x14,0xE4,0x12,0x24,0x3D,0xE6,0x12,0x8A,0x44,0x15,0x3C,0x01,0x72,0x1E,0x77, 0x16,0xB0,0x11,0xE6,0x34,0xB0,0x13,0xE6,0x36,0xE4,0x14,0x0C,0x10,0xE6,0x14,0xE4, 0x12,0x0C,0x40,0xE6,0x12,0xEB,0x06,0xE4,0x12,0x0C,0x02,0xE6,0x12,0x8A,0x44,0x0F, 0x3C,0x01,0x74,0x06,0x3C,0x02,0x74,0x0A,0xEB,0x0E,0xE4,0x12,0x0C,0x08,0xE6,0x12, 0xEB,0x06,0xE4,0x12,0x0C,0x10,0xE6,0x12,0xE8,0x2F,0xFF,0x8A,0x44,0x14,0x3C,0x02, 0x75,0x08,0xB0,0x55,0x88,0x44,0x0C,0x88,0x44,0x0D,0xB0,0x21,0xB4,0x64,0x89,0x44, -0x04,0x89,0x44,0x02,0xE4,0x0C,0x0C,0x10,0xE6,0x0C,0xE8,0xCF,0x39,0xFB,0xC3,0xE8, -0x41,0x3F,0x73,0x08,0xFB,0xB0,0x0A,0xE8,0xEA,0x48,0xEB,0xF3,0xFA,0xE8,0x99,0x1D, +0x04,0x89,0x44,0x02,0xE4,0x0C,0x0C,0x10,0xE6,0x0C,0xE8,0xED,0x39,0xFB,0xC3,0xE8, +0x5F,0x3F,0x73,0x08,0xFB,0xB0,0x0A,0xE8,0x08,0x49,0xEB,0xF3,0xFA,0xE8,0x9D,0x1D, 0x8A,0x64,0x16,0x8A,0x44,0x17,0x89,0x86,0x94,0x00,0xE6,0xE4,0x8A,0xC4,0xE6,0xEC, 0x8A,0x64,0x18,0x8A,0x44,0x19,0x89,0x86,0x96,0x00,0xE6,0xF0,0x8A,0xC4,0xE6,0xF8, 0x8A,0x44,0x1A,0xE6,0x10,0x8A,0x44,0x1B,0xE6,0x12,0x8A,0x44,0x1C,0xE6,0x14,0x8A, @@ -73,947 +73,949 @@ 0xFF,0xAA,0xE8,0xA7,0xFF,0xAA,0xE8,0xA3,0xFF,0xAA,0xE8,0x9F,0xFF,0x88,0x44,0x0C, 0x89,0x5C,0x02,0x80,0x44,0x0B,0x04,0x89,0x7E,0x22,0x83,0x6E,0x24,0x04,0x83,0x46, 0x1A,0x04,0x80,0x7E,0x26,0x02,0x74,0x06,0x80,0x66,0x26,0xFD,0xFB,0xC3,0x60,0xB0, -0xFD,0xE8,0xE4,0x3E,0x61,0xFB,0xC3,0xFA,0x80,0x7C,0x0F,0x03,0x75,0x09,0xC6,0x44, -0x0B,0x00,0xE8,0xC7,0x38,0xFB,0xC3,0xC4,0x7E,0x14,0x8B,0x4E,0x3A,0x85,0xC9,0x75, +0xFD,0xE8,0x02,0x3F,0x61,0xFB,0xC3,0xFA,0x80,0x7C,0x0F,0x03,0x75,0x09,0xC6,0x44, +0x0B,0x00,0xE8,0xE5,0x38,0xFB,0xC3,0xC4,0x7E,0x14,0x8B,0x4E,0x3A,0x85,0xC9,0x75, 0x35,0x26,0x8B,0x0D,0x47,0x47,0xE3,0xEA,0x3B,0x7E,0x04,0x76,0x22,0xB8,0x02,0x00, 0x39,0x46,0x2E,0x77,0x07,0xC7,0x46,0x2E,0x00,0x00,0xEB,0x13,0x8B,0x5E,0x2C,0x89, 0x5E,0x04,0x26,0xC7,0x07,0x00,0x00,0x43,0x43,0x89,0x5E,0x2C,0x29,0x46,0x2E,0x85, 0xC9,0x78,0xCE,0x89,0x4E,0x3A,0x8A,0x44,0x0D,0x8B,0x5C,0x04,0x26,0x8A,0x25,0x47, 0x3A,0xC4,0x75,0x16,0xFE,0x4C,0x0B,0xFF,0x44,0x06,0xE8,0x0F,0xFF,0xE2,0xED,0x88, -0x44,0x0D,0x89,0x5C,0x04,0x89,0x4E,0x3A,0xEB,0xA7,0xC6,0x44,0x0A,0xFE,0xE8,0x5B, -0x38,0xFB,0xC3,0x90,0xE8,0xAF,0x0D,0x8A,0xE8,0x8A,0x0E,0xCB,0x13,0xB3,0x07,0x8A, +0x44,0x0D,0x89,0x5C,0x04,0x89,0x4E,0x3A,0xEB,0xA7,0xC6,0x44,0x0A,0xFE,0xE8,0x79, +0x38,0xFB,0xC3,0x90,0xE8,0xB3,0x0D,0x8A,0xE8,0x8A,0x0E,0xCB,0x13,0xB3,0x07,0x8A, 0xC1,0xEE,0xEB,0x00,0xEC,0x3A,0xC1,0x75,0x09,0x02,0xCD,0xFE,0xCB,0x75,0xF0,0xEB, 0x0C,0x90,0x88,0x0E,0xCB,0x13,0x8A,0xE8,0xBB,0xFF,0xFF,0xF9,0xC3,0x88,0x0E,0xCB, 0x13,0xF8,0xC3,0x90,0xBB,0x3F,0x3F,0x8A,0x8E,0x9E,0x00,0xBA,0xFE,0x00,0xEC,0x8A, 0xE8,0x32,0xC1,0x22,0xC3,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x90,0xE8,0xE5,0xFF,0x73, 0x01,0xC3,0xBA,0xD0,0x00,0xBB,0x03,0x03,0x8A,0x8E,0x9F,0x00,0xEC,0x8A,0xE8,0x32, 0xC1,0x22,0xC3,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x90,0x33,0xC0,0x8E,0xD8,0x8E,0xC0, -0x80,0x3E,0xC8,0x13,0x00,0x75,0x07,0xB0,0x0A,0xE8,0x08,0x47,0xEB,0xF2,0xFB,0x33, +0x80,0x3E,0xC8,0x13,0x00,0x75,0x07,0xB0,0x0A,0xE8,0x26,0x47,0xEB,0xF2,0xFB,0x33, 0xDB,0x8A,0x1E,0xC9,0x13,0x43,0x43,0x83,0xFB,0x7E,0x76,0x07,0x33,0xDB,0xB0,0x02, -0xE8,0xF1,0x46,0x2E,0x8B,0xAF,0x44,0x00,0x83,0x7E,0x08,0x00,0x74,0xE7,0x88,0x1E, -0xC9,0x13,0xB0,0x02,0xE8,0xDD,0x46,0xFA,0xF7,0x46,0x38,0x40,0x00,0x74,0x14,0xE8, -0x92,0x1B,0xE8,0x7F,0xFF,0x72,0x1C,0x33,0xD2,0x8A,0x96,0x9F,0x00,0x83,0xC2,0x0E, -0xEB,0x0C,0x90,0xE8,0x73,0x1B,0xE8,0x83,0xFF,0x72,0x08,0xBA,0x48,0x00,0xE8,0x33, +0xE8,0x0F,0x47,0x2E,0x8B,0xAF,0x44,0x00,0x83,0x7E,0x08,0x00,0x74,0xE7,0x88,0x1E, +0xC9,0x13,0xB0,0x02,0xE8,0xFB,0x46,0xFA,0xF7,0x46,0x38,0x40,0x00,0x74,0x14,0xE8, +0x96,0x1B,0xE8,0x7F,0xFF,0x72,0x1C,0x33,0xD2,0x8A,0x96,0x9F,0x00,0x83,0xC2,0x0E, +0xEB,0x0C,0x90,0xE8,0x77,0x1B,0xE8,0x83,0xFF,0x72,0x08,0xBA,0x48,0x00,0xE8,0x33, 0xFF,0x73,0xAB,0x23,0xCB,0x89,0x8E,0x9A,0x00,0x89,0x96,0x9C,0x00,0xFE,0x86,0xB5, -0x00,0xC6,0x06,0xC8,0x13,0x00,0xB0,0x0A,0xE8,0x63,0x0A,0xFB,0xEB,0x89,0x10,0x18, +0x00,0xC6,0x06,0xC8,0x13,0x00,0xB0,0x0A,0xE8,0x67,0x0A,0xFB,0xEB,0x89,0x10,0x18, 0x08,0x28,0x33,0xC0,0xA0,0x05,0x01,0x8A,0xC8,0x24,0x40,0x75,0x24,0xC7,0x06,0x7C, -0x12,0x70,0x45,0xC7,0x06,0x42,0x12,0x01,0x00,0xC6,0x06,0x54,0x12,0x02,0xB0,0x08, +0x12,0x8E,0x45,0xC7,0x06,0x42,0x12,0x01,0x00,0xC6,0x06,0x54,0x12,0x02,0xB0,0x08, 0xF6,0xC1,0x01,0x74,0x02,0xB0,0x04,0xA3,0x46,0x12,0xA2,0x4C,0x12,0xA2,0x94,0x12, -0xC3,0xC7,0x06,0x7C,0x12,0x98,0x45,0xA0,0x0F,0x01,0x84,0xC0,0x75,0x0E,0x6A,0x00, -0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xAD,0x0C,0x90,0xC7,0x06,0x44,0x12, +0xC3,0xC7,0x06,0x7C,0x12,0xB6,0x45,0xA0,0x0F,0x01,0x84,0xC0,0x75,0x0E,0x6A,0x00, +0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xB1,0x0C,0x90,0xC7,0x06,0x44,0x12, 0x01,0x00,0xA3,0x42,0x12,0x8B,0xD8,0xC1,0xE3,0x04,0x88,0x1E,0x94,0x12,0xBE,0xE2, 0x05,0x2B,0xF0,0x8B,0xC8,0x33,0xDB,0x8B,0xFB,0x2E,0xAC,0x88,0x85,0x48,0x12,0x8A, 0xD8,0x0C,0x05,0xE6,0xFE,0x8A,0xE0,0xEB,0x00,0xE4,0xFE,0x32,0xC4,0xA8,0x3F,0x74, -0x03,0xE9,0x9A,0x00,0xE4,0x00,0x88,0x85,0x50,0x12,0x8A,0xE0,0x24,0x30,0xBA,0x10, +0x03,0xE9,0x9E,0x00,0xE4,0x00,0x88,0x85,0x50,0x12,0x8A,0xE0,0x24,0x30,0xBA,0x10, 0xFF,0x3C,0x30,0x74,0x12,0x80,0xFC,0x04,0x74,0x0A,0xBA,0x04,0x03,0xF6,0x06,0x08, 0x01,0xFE,0x74,0x03,0xBA,0x08,0x0F,0x88,0x95,0x4C,0x12,0x02,0xFA,0x32,0xC0,0xF6, -0xC4,0x08,0x74,0x02,0xB0,0x01,0x88,0x85,0x58,0x12,0x8A,0xC4,0x3C,0x35,0x74,0x57, -0x3C,0x34,0x74,0x53,0x3C,0x04,0x74,0x4F,0x3C,0x14,0x74,0x4B,0x3C,0x15,0x74,0x47, -0xA8,0x40,0x74,0x25,0xC6,0x85,0x54,0x12,0x04,0xD1,0xE7,0xB4,0x03,0x8A,0xC3,0x89, -0x85,0x5C,0x12,0x8A,0xC3,0x8A,0xE3,0x80,0xCC,0x01,0x89,0x85,0x64,0x12,0xD1,0xEF, -0x47,0xE2,0x03,0xEB,0x1A,0x90,0xE9,0x70,0xFF,0xC6,0x85,0x54,0x12,0x02,0xD1,0xE7, -0x8A,0xE6,0x8A,0xC3,0x0C,0x04,0x89,0x85,0x5C,0x12,0xD1,0xEF,0x47,0xE2,0xE7,0x33, -0xC0,0x8A,0xC7,0xA3,0x46,0x12,0xC3,0xC6,0x85,0x54,0x12,0x06,0xEB,0xBB,0xC6,0x85, -0x54,0x12,0x00,0x33,0xC0,0x88,0x85,0x50,0x12,0x88,0x85,0x4C,0x12,0x88,0x85,0x58, -0x12,0xEB,0xA6,0xC7,0x46,0x26,0x02,0x12,0x8B,0x46,0x1E,0x89,0x46,0x00,0x89,0x46, -0x22,0x8B,0x46,0x20,0x89,0x46,0x24,0xC7,0x46,0x1A,0x00,0x00,0xC3,0xC7,0x46,0x3C, -0x80,0x00,0xC7,0x46,0x38,0x01,0x00,0x1E,0x56,0x8B,0x76,0x30,0x89,0x76,0x04,0x89, -0x76,0x14,0x8E,0x5E,0x06,0x33,0xC0,0x89,0x04,0x46,0x46,0x89,0x76,0x2C,0x89,0x46, -0x3A,0x8B,0x46,0x32,0x48,0x48,0x89,0x46,0x2E,0x5E,0x1F,0xC3,0x33,0xC0,0x89,0x46, -0x48,0x89,0x46,0x4A,0xC7,0x46,0x46,0xAE,0x01,0x89,0x46,0x4E,0x8B,0x46,0x44,0x89, -0x46,0x50,0x8B,0x46,0x42,0x89,0x46,0x40,0x89,0x46,0x08,0xC3,0x33,0xC0,0x89,0x46, -0x76,0x89,0x46,0x78,0xC7,0x46,0x7A,0x10,0x00,0x56,0x1E,0x8B,0x76,0x70,0x89,0x76, -0x10,0x89,0x76,0x0C,0x8E,0x5E,0x12,0xC7,0x04,0x00,0x00,0x8B,0x46,0x72,0x89,0x46, -0x74,0x1F,0x5E,0xC3,0x89,0x56,0x18,0x89,0x56,0x02,0x89,0x56,0x06,0x89,0x56,0x0A, -0x89,0x56,0x0E,0x89,0x56,0x12,0x89,0x56,0x16,0x8B,0xD8,0x4B,0x4B,0xC1,0xE3,0x02, -0xBF,0x02,0x00,0x89,0x7E,0x1E,0x03,0xFB,0x89,0x7E,0x30,0x03,0xFB,0x89,0x7E,0x42, -0x03,0xFB,0x89,0x7E,0x70,0x83,0xEB,0x08,0x89,0x5E,0x20,0x89,0x5E,0x32,0x89,0x5E, -0x44,0x89,0x5E,0x72,0x50,0xE8,0x2B,0xFF,0xE8,0x71,0xFF,0xE8,0x3F,0xFF,0xE8,0x8B, -0xFF,0x58,0xC3,0xB8,0x10,0x75,0xC1,0xE8,0x04,0x0E,0x5B,0x03,0xC3,0xA3,0xBA,0x13, -0x83,0x3E,0x42,0x12,0x00,0x74,0x07,0x80,0x3E,0x94,0x12,0x00,0x75,0x0E,0x6A,0x00, -0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xBD,0x0A,0x90,0xB8,0x30,0x7A,0xC1, -0xE8,0x04,0x40,0xA3,0xC0,0x13,0x2B,0x06,0x12,0x01,0xF7,0xD8,0x33,0xD2,0x8B,0xCA, -0x8A,0x0E,0x94,0x12,0xF7,0xF1,0x3D,0x80,0x00,0x77,0x0E,0x6A,0x00,0x1F,0xC6,0x06, -0x93,0x12,0x25,0x9C,0x0E,0xE8,0x90,0x0A,0x90,0x48,0x3D,0xFF,0x07,0x72,0x03,0xB8, -0xFF,0x07,0xA3,0xC2,0x13,0x33,0xC9,0x8A,0x0E,0x94,0x12,0x33,0xF6,0xB8,0x00,0x09, -0x2E,0x8B,0xAC,0x44,0x00,0x89,0x46,0x4C,0x40,0x46,0x46,0xE2,0xF3,0x8A,0x0E,0x94, -0x12,0x33,0xF6,0x8B,0x16,0xC0,0x13,0xA1,0xC2,0x13,0x2E,0x8B,0xAC,0x44,0x00,0xE8, -0x22,0xFF,0x03,0xD0,0x46,0x46,0xE2,0xF2,0xC3,0x33,0xC0,0x2E,0x8B,0xAD,0x44,0x00, -0x89,0x46,0x08,0x47,0x47,0xE2,0xF4,0xC3,0x51,0x33,0xC0,0x0A,0xC2,0x2E,0x8B,0xAD, -0x44,0x00,0x89,0x86,0x9E,0x00,0x81,0x4E,0x38,0x00,0x20,0x47,0x47,0xFE,0xC4,0x80, -0xFC,0x04,0x72,0x04,0x32,0xE4,0xFE,0xC0,0xE2,0xE3,0x59,0x83,0xE9,0x10,0x74,0x05, -0xF7,0xD9,0xE8,0xC4,0xFF,0xC3,0x51,0x33,0xC0,0x0A,0xC2,0x2E,0x8B,0xAD,0x44,0x00, -0x89,0x86,0x9E,0x00,0x83,0x4E,0x38,0x40,0x47,0x47,0x80,0xC4,0x10,0x79,0x04,0x32, -0xE4,0xFE,0xC0,0xE2,0xE6,0x59,0x83,0xE9,0x10,0x74,0x05,0xF7,0xD9,0xE8,0x99,0xFF, -0xC3,0xE8,0xD2,0xFF,0xC3,0x89,0x08,0x98,0x08,0xC6,0x08,0xF1,0x08,0x8B,0x0E,0x42, -0x12,0x33,0xF6,0x51,0x56,0x33,0xDB,0x8B,0xCB,0x8A,0x94,0x48,0x12,0x8A,0x8C,0x4C, -0x12,0x8A,0x9C,0x54,0x12,0x8B,0xFE,0xC1,0xE7,0x05,0x85,0xDB,0x75,0x02,0xB1,0x10, -0x2E,0xFF,0x97,0xF5,0x08,0x5E,0x59,0x46,0xE2,0xD9,0xC3,0x01,0xCC,0x03,0xD0,0x00, -0xE8,0x02,0xD0,0x00,0xE8,0x01,0xD0,0x00,0xE8,0x00,0xD0,0x00,0xE8,0x04,0xD0,0xA8, -0xDA,0x00,0xDC,0x00,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x04,0xD0,0xA8, -0xDA,0x20,0xDC,0x00,0xDE,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x00,0xD8,0x03,0xCC,0x03, +0xC4,0x08,0x74,0x02,0xB0,0x01,0x88,0x85,0x58,0x12,0x8A,0xC4,0x3C,0x35,0x74,0x5B, +0x3C,0x36,0x74,0x57,0x3C,0x34,0x74,0x53,0x3C,0x04,0x74,0x4F,0x3C,0x14,0x74,0x4B, +0x3C,0x15,0x74,0x47,0xA8,0x40,0x74,0x25,0xC6,0x85,0x54,0x12,0x04,0xD1,0xE7,0xB4, +0x03,0x8A,0xC3,0x89,0x85,0x5C,0x12,0x8A,0xC3,0x8A,0xE3,0x80,0xCC,0x01,0x89,0x85, +0x64,0x12,0xD1,0xEF,0x47,0xE2,0x03,0xEB,0x1A,0x90,0xE9,0x6C,0xFF,0xC6,0x85,0x54, +0x12,0x02,0xD1,0xE7,0x8A,0xE6,0x8A,0xC3,0x0C,0x04,0x89,0x85,0x5C,0x12,0xD1,0xEF, +0x47,0xE2,0xE7,0x33,0xC0,0x8A,0xC7,0xA3,0x46,0x12,0xC3,0xC6,0x85,0x54,0x12,0x06, +0xEB,0xBB,0xC6,0x85,0x54,0x12,0x00,0x33,0xC0,0x88,0x85,0x50,0x12,0x88,0x85,0x4C, +0x12,0x88,0x85,0x58,0x12,0xEB,0xA6,0xC7,0x46,0x26,0x02,0x12,0x8B,0x46,0x1E,0x89, +0x46,0x00,0x89,0x46,0x22,0x8B,0x46,0x20,0x89,0x46,0x24,0xC7,0x46,0x1A,0x00,0x00, +0xC3,0xC7,0x46,0x3C,0x80,0x00,0xC7,0x46,0x38,0x01,0x00,0x1E,0x56,0x8B,0x76,0x30, +0x89,0x76,0x04,0x89,0x76,0x14,0x8E,0x5E,0x06,0x33,0xC0,0x89,0x04,0x46,0x46,0x89, +0x76,0x2C,0x89,0x46,0x3A,0x8B,0x46,0x32,0x48,0x48,0x89,0x46,0x2E,0x5E,0x1F,0xC3, +0x33,0xC0,0x89,0x46,0x48,0x89,0x46,0x4A,0xC7,0x46,0x46,0xAE,0x01,0x89,0x46,0x4E, +0x8B,0x46,0x44,0x89,0x46,0x50,0x8B,0x46,0x42,0x89,0x46,0x40,0x89,0x46,0x08,0xC3, +0x33,0xC0,0x89,0x46,0x76,0x89,0x46,0x78,0xC7,0x46,0x7A,0x10,0x00,0x56,0x1E,0x8B, +0x76,0x70,0x89,0x76,0x10,0x89,0x76,0x0C,0x8E,0x5E,0x12,0xC7,0x04,0x00,0x00,0x8B, +0x46,0x72,0x89,0x46,0x74,0x1F,0x5E,0xC3,0x89,0x56,0x18,0x89,0x56,0x02,0x89,0x56, +0x06,0x89,0x56,0x0A,0x89,0x56,0x0E,0x89,0x56,0x12,0x89,0x56,0x16,0x8B,0xD8,0x4B, +0x4B,0xC1,0xE3,0x02,0xBF,0x02,0x00,0x89,0x7E,0x1E,0x03,0xFB,0x89,0x7E,0x30,0x03, +0xFB,0x89,0x7E,0x42,0x03,0xFB,0x89,0x7E,0x70,0x83,0xEB,0x08,0x89,0x5E,0x20,0x89, +0x5E,0x32,0x89,0x5E,0x44,0x89,0x5E,0x72,0x50,0xE8,0x2B,0xFF,0xE8,0x71,0xFF,0xE8, +0x3F,0xFF,0xE8,0x8B,0xFF,0x58,0xC3,0xB8,0x30,0x75,0xC1,0xE8,0x04,0x0E,0x5B,0x03, +0xC3,0xA3,0xBA,0x13,0x83,0x3E,0x42,0x12,0x00,0x74,0x07,0x80,0x3E,0x94,0x12,0x00, +0x75,0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1E,0x9C,0x0E,0xE8,0xBD,0x0A,0x90, +0xB8,0x30,0x7A,0xC1,0xE8,0x04,0x40,0xA3,0xC0,0x13,0x2B,0x06,0x12,0x01,0xF7,0xD8, +0x33,0xD2,0x8B,0xCA,0x8A,0x0E,0x94,0x12,0xF7,0xF1,0x3D,0x80,0x00,0x77,0x0E,0x6A, +0x00,0x1F,0xC6,0x06,0x93,0x12,0x25,0x9C,0x0E,0xE8,0x90,0x0A,0x90,0x48,0x3D,0xFF, +0x07,0x72,0x03,0xB8,0xFF,0x07,0xA3,0xC2,0x13,0x33,0xC9,0x8A,0x0E,0x94,0x12,0x33, +0xF6,0xB8,0x00,0x09,0x2E,0x8B,0xAC,0x44,0x00,0x89,0x46,0x4C,0x40,0x46,0x46,0xE2, +0xF3,0x8A,0x0E,0x94,0x12,0x33,0xF6,0x8B,0x16,0xC0,0x13,0xA1,0xC2,0x13,0x2E,0x8B, +0xAC,0x44,0x00,0xE8,0x22,0xFF,0x03,0xD0,0x46,0x46,0xE2,0xF2,0xC3,0x33,0xC0,0x2E, +0x8B,0xAD,0x44,0x00,0x89,0x46,0x08,0x47,0x47,0xE2,0xF4,0xC3,0x51,0x33,0xC0,0x0A, +0xC2,0x2E,0x8B,0xAD,0x44,0x00,0x89,0x86,0x9E,0x00,0x81,0x4E,0x38,0x00,0x20,0x47, +0x47,0xFE,0xC4,0x80,0xFC,0x04,0x72,0x04,0x32,0xE4,0xFE,0xC0,0xE2,0xE3,0x59,0x83, +0xE9,0x10,0x74,0x05,0xF7,0xD9,0xE8,0xC4,0xFF,0xC3,0x51,0x33,0xC0,0x0A,0xC2,0x2E, +0x8B,0xAD,0x44,0x00,0x89,0x86,0x9E,0x00,0x83,0x4E,0x38,0x40,0x47,0x47,0x80,0xC4, +0x10,0x79,0x04,0x32,0xE4,0xFE,0xC0,0xE2,0xE6,0x59,0x83,0xE9,0x10,0x74,0x05,0xF7, +0xD9,0xE8,0x99,0xFF,0xC3,0xE8,0xD2,0xFF,0xC3,0x8D,0x08,0x9C,0x08,0xCA,0x08,0xF5, +0x08,0x8B,0x0E,0x42,0x12,0x33,0xF6,0x51,0x56,0x33,0xDB,0x8B,0xCB,0x8A,0x94,0x48, +0x12,0x8A,0x8C,0x4C,0x12,0x8A,0x9C,0x54,0x12,0x8B,0xFE,0xC1,0xE7,0x05,0x85,0xDB, +0x75,0x02,0xB1,0x10,0x2E,0xFF,0x97,0xF9,0x08,0x5E,0x59,0x46,0xE2,0xD9,0xC3,0x01, +0xCC,0x03,0xD0,0x00,0xE8,0x02,0xD0,0x00,0xE8,0x01,0xD0,0x00,0xE8,0x00,0xD0,0x00, +0xE8,0x04,0xD0,0xA8,0xDA,0x00,0xDC,0x00,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03, +0xCC,0x04,0xD0,0xA8,0xDA,0x20,0xDC,0x00,0xDE,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x00, +0xD8,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03, 0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03, -0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x04,0xD0,0x00, -0xDA,0x20,0xDC,0x03,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x03,0xCC,0x00, -0xD8,0x00,0xCC,0x00,0xD0,0x00,0x00,0x56,0x52,0x1E,0x0E,0x1F,0xBE,0x2B,0x09,0x33, -0xD2,0xFC,0xAD,0x85,0xC0,0x74,0x0D,0x8A,0xD4,0xEE,0xAD,0x85,0xC0,0x74,0x05,0x8A, -0xD4,0xEE,0xEB,0xEE,0x1F,0x5A,0x5E,0xC3,0xE4,0x80,0x84,0xC0,0x74,0x16,0x78,0x14, -0xB0,0x27,0xE6,0xFC,0xB0,0x11,0xE6,0x34,0xE4,0xFC,0x3C,0x27,0x75,0x06,0xE4,0x11, -0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x83,0xEA,0x02,0xB0, -0x10,0xEE,0x88,0x86,0xAF,0x00,0xB0,0x11,0x83,0xC2,0x04,0xEE,0x83,0xC2,0x02,0xEE, -0xB0,0x13,0x83,0xC2,0x02,0xEE,0x83,0xC2,0x02,0xEE,0x2E,0xA1,0x2E,0x2D,0x89,0x86, -0x94,0x00,0x83,0xEA,0x0E,0xEE,0x83,0xC2,0x02,0x8A,0xC4,0xEE,0x83,0xC2,0x04,0xB0, -0x03,0xEE,0x88,0x86,0xA8,0x00,0x83,0xEA,0x04,0x32,0xC0,0xEE,0x83,0xC2,0x02,0xB0, -0x89,0xEE,0x88,0x86,0xA6,0x00,0x0C,0x06,0xEE,0xB0,0x40,0xB4,0x38,0x89,0x46,0x1C, -0xC7,0x46,0x36,0x38,0x00,0x83,0xC2,0x04,0x32,0xC0,0xEE,0x88,0x86,0xA7,0x00,0xC3, -0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x83,0xEA,0x02,0xEC,0x3A,0x86,0xAF,0x00,0x75,0x24, -0x83,0xC2,0x04,0xEC,0x3C,0x11,0x75,0x1C,0x83,0xC2,0x06,0xEC,0x3C,0x13,0x75,0x14, -0x83,0xEA,0x08,0x8A,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x02,0xEC,0x24,0xC0,0x3C,0xC0, -0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x33,0xC9,0x8B,0xD1,0x8B,0xF1,0x8A,0x0E,0x94,0x12, -0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x0E,0x8A, -0x86,0x9E,0x00,0xE6,0xFE,0x32,0xC0,0xE6,0x80,0x42,0xE8,0xFA,0xFE,0x83,0xC6,0x08, -0xE2,0xE1,0x85,0xD2,0x74,0x03,0xE8,0x05,0x08,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E, -0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x06,0xE8,0x73, -0x16,0xE8,0x12,0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94, -0x12,0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x16, -0xE8,0x46,0x16,0xE8,0xD2,0xFE,0x73,0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1C, -0x9C,0x0E,0xE8,0xE3,0x07,0x90,0x83,0xC6,0x08,0xE2,0xD9,0xC3,0x33,0xC9,0x8B,0xF1, -0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x16, -0xE8,0x21,0x16,0xE8,0x2A,0xFF,0x73,0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1C, -0x9C,0x0E,0xE8,0xB3,0x07,0x90,0x46,0x46,0xE2,0xDA,0xC3,0x0C,0x00,0x00,0x10,0x00, -0x13,0x12,0x00,0x00,0x14,0x00,0x28,0x3C,0x00,0x1B,0x3E,0x00,0x00,0x2A,0x00,0x00, -0x2C,0x00,0x00,0x42,0x00,0x14,0xD8,0x00,0x00,0xDA,0x00,0x00,0x34,0x00,0x11,0x36, -0x00,0x13,0x38,0x00,0x11,0x3A,0x00,0x13,0x00,0x00,0x56,0x50,0x52,0xBE,0x2B,0x0B, -0x2E,0xAD,0x85,0xC0,0x74,0x06,0x92,0x2E,0xAC,0xEE,0xEB,0xF4,0x5A,0x58,0x5E,0xC3, -0x53,0x2E,0xA1,0x5C,0x22,0xE6,0xE4,0xE6,0xF0,0x8A,0xC4,0xE6,0xEC,0xE6,0xF8,0xE8, -0xD8,0xFF,0xB0,0x4B,0xE6,0x10,0xB0,0x50,0xE6,0x12,0xB0,0x38,0xE6,0x14,0xE8,0xAE, -0x15,0xB0,0x46,0xE6,0x0A,0xE8,0xA7,0x15,0xB0,0x1A,0xE6,0x0A,0xE8,0xA0,0x15,0xB0, -0x22,0xE6,0x0A,0xE8,0x99,0x15,0xE8,0xFD,0x06,0x8B,0xD8,0xE4,0x16,0xA8,0x04,0x75, -0x18,0xE8,0xF2,0x06,0x2B,0xC3,0x3D,0x32,0x00,0x72,0xF0,0x6A,0x00,0x1F,0xC6,0x06, -0x93,0x12,0x23,0x9C,0x0E,0xE8,0x10,0x07,0x90,0xE8,0xDA,0x06,0x2B,0xC3,0x3D,0x24, -0x00,0x77,0x1B,0xB0,0x31,0xE6,0xFC,0x56,0x51,0x55,0xB9,0x10,0x00,0x2E,0x8B,0xAC, -0x44,0x00,0x81,0x4E,0x38,0x80,0x00,0x46,0x46,0xE2,0xF2,0x5D,0x59,0x5E,0xE8,0x69, -0xFF,0xE8,0x4B,0x15,0xB0,0x46,0xE6,0x0A,0xE8,0x44,0x15,0x5B,0xC3,0x33,0xF6,0x8B, -0x0E,0x42,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x06,0xE8, -0x17,0x15,0xE8,0x5B,0xFF,0x83,0xC6,0x20,0xE2,0xE9,0xC3,0x8B,0xC2,0x05,0x04,0x00, -0x89,0x46,0x28,0x2E,0xA1,0x2E,0x2D,0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x89, -0x86,0x92,0x00,0xC6,0x86,0xA3,0x00,0x0A,0xC6,0x86,0xC3,0x00,0x03,0x52,0x83,0xC2, -0x04,0x8A,0x86,0xA6,0x00,0x0C,0x06,0xEE,0x5A,0x83,0xC2,0x02,0xB0,0x05,0xEE,0x88, -0x86,0xA5,0x00,0xC3,0xE8,0x03,0xFF,0xE8,0xE5,0x14,0xB0,0x42,0xE6,0x0A,0xF7,0x46, -0x38,0x80,0x00,0x74,0x06,0x2E,0xA1,0x98,0x22,0xEB,0x04,0x2E,0xA1,0x68,0x22,0xC7, -0x46,0x1C,0x0C,0x00,0x89,0x86,0x94,0x00,0x89,0x86,0x96,0x00,0x89,0x86,0x8E,0x00, -0x89,0x86,0x90,0x00,0x89,0x86,0x92,0x00,0xE6,0xF0,0xE6,0xE4,0x8A,0xC4,0xE6,0xF8, -0xE6,0xEC,0xC6,0x86,0xC3,0x00,0x03,0xE8,0xA5,0x14,0xB0,0x1A,0xE6,0x0A,0xB0,0x10, -0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E, -0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x06,0xE8,0x76,0x14,0xE8,0x5A, -0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,0x8B, -0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x06,0xE8,0x4C,0x14,0xE8,0x74,0xFF, -0x46,0x46,0xE2,0xEA,0xC3,0x90,0x83,0x3E,0x44,0x12,0x00,0x75,0x14,0xB0,0x01,0xBA, -0x06,0x01,0xEE,0x2A,0xC0,0xEE,0xB0,0x02,0xEE,0xB0,0x04,0xEE,0xB8,0x00,0x02,0xEB, -0x0F,0xBA,0x06,0x01,0xB0,0x40,0xEE,0xB8,0x01,0x00,0x8A,0x0E,0x0E,0x01,0xD3,0xE0, -0xA3,0x88,0x12,0xC3,0xA1,0x88,0x12,0xA3,0x84,0x12,0x2D,0x20,0x00,0xA3,0x8A,0x12, -0x2D,0x20,0x00,0xA3,0x82,0x12,0xC7,0x06,0x86,0x12,0x20,0x00,0xC7,0x06,0x80,0x12, -0x32,0x00,0xC3,0x83,0x3E,0x44,0x12,0x00,0x74,0x76,0x8B,0x0E,0x42,0x12,0x33,0xF6, -0x8A,0xA4,0x54,0x12,0x84,0xE4,0x74,0x5F,0x8A,0x84,0x48,0x12,0x0C,0x04,0xE6,0xFE, -0xF6,0xC4,0x04,0x74,0x25,0xB0,0x1B,0xBA,0x00,0x00,0xEE,0xEB,0x00,0x2A,0xC0,0xBA, -0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,0xEE,0xEB,0x00,0x32,0xC0,0xBA,0x02,0x00,0xEE, -0xEB,0x00,0xBA,0x00,0x00,0xB0,0x00,0xEE,0xEB,0x2D,0xB0,0x1F,0xBA,0x00,0x00,0xEE, -0xEB,0x00,0x2A,0xC0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,0xEE,0xEB,0x00,0xD1, -0xE6,0x8A,0x84,0x5D,0x12,0xD1,0xEE,0xF6,0xD0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xBA, -0x00,0x00,0xB0,0x0A,0xEE,0xEB,0x00,0xE4,0x04,0xEB,0x00,0xE4,0x04,0x46,0xE2,0x90, -0xC3,0x90,0xB8,0x14,0x00,0xBA,0x3E,0xFF,0xEF,0xB8,0x06,0x00,0xBA,0x32,0xFF,0xEF, -0xB8,0x0F,0x00,0xBA,0x34,0xFF,0xEF,0xBA,0x36,0xFF,0xEF,0x83,0x3E,0x44,0x12,0x00, -0x75,0x16,0xB8,0x11,0x00,0xBA,0x38,0xFF,0xEF,0xB8,0x12,0x00,0xBA,0x3A,0xFF,0xEF, -0xB8,0x1B,0x00,0xBA,0x3C,0xFF,0xEF,0xC3,0xB8,0x11,0x00,0xBA,0x38,0xFF,0xEF,0xB8, -0x12,0x00,0xBA,0x3A,0xFF,0xEF,0xB8,0x1B,0x00,0xBA,0x3C,0xFF,0xEF,0xC3,0xB8,0xFC, -0x00,0xBA,0x28,0xFF,0xEF,0xFB,0x83,0x3E,0x44,0x12,0x00,0x74,0x07,0xB8,0xCC,0x00, -0xBA,0x28,0xFF,0xEF,0xC3,0x00,0xFF,0xFF,0x20,0x24,0x28,0xFF,0x2C,0xFF,0xFF,0x30, -0x34,0x38,0xFF,0xFF,0x3C,0x90,0x3C,0x0F,0x77,0x0E,0xBB,0x15,0x0E,0x2E,0xD7,0x3C, -0xFF,0x74,0x05,0x8A,0xD8,0xF8,0xC3,0x90,0x2A,0xDB,0xF9,0xC3,0x83,0x3E,0x44,0x12, -0x00,0x74,0x27,0xA0,0x06,0x01,0x80,0x26,0x06,0x01,0x30,0x80,0x3E,0x06,0x01,0x30, -0x75,0x18,0xB9,0x02,0x00,0xBF,0xC4,0x13,0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xF8, -0xBA,0x04,0x01,0xED,0xAB,0xE2,0xF1,0xEB,0x16,0x90,0xB9,0x04,0x00,0xBF,0xC4,0x13, -0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xF8,0xBA,0x04,0x01,0xEC,0xAA,0xE2,0xF1,0xFA, -0x90,0xBE,0xC4,0x13,0xAD,0x80,0xE4,0x3F,0x80,0xFC,0x02,0x74,0x0E,0x6A,0x00,0x1F, -0xC6,0x06,0x93,0x12,0x0A,0x9C,0x0E,0xE8,0x3E,0x04,0x90,0xAD,0x3C,0x0F,0x75,0xED, -0x8A,0xC4,0xE8,0x81,0xFF,0x72,0xE6,0x88,0x1E,0x1A,0x01,0xC6,0x06,0x8E,0x12,0x00, -0xB0,0x00,0x0A,0x06,0x1A,0x01,0xBA,0x00,0x01,0xEE,0xC6,0x06,0x8F,0x12,0x40,0x83, -0x3E,0x44,0x12,0x00,0x75,0x06,0xB8,0x0C,0x00,0xEB,0x04,0x90,0xB8,0x4C,0x00,0xBA, -0x28,0xFF,0xEF,0xC3,0x83,0x3E,0x44,0x12,0x00,0x75,0x01,0xC3,0xA1,0x50,0x12,0x0B, -0x06,0x52,0x12,0x0A,0xC4,0xA8,0x08,0x74,0xF2,0xA0,0x0F,0x01,0x2A,0xE4,0x50,0xFF, -0x36,0xBA,0x13,0x1F,0xE8,0x36,0x56,0x83,0xC4,0x02,0x6A,0x00,0x1F,0x33,0xC0,0xA3, -0xBC,0x13,0xA0,0x0F,0x01,0xA3,0xBE,0x13,0x8B,0x1E,0xBC,0x13,0x8A,0x87,0x50,0x12, -0xF6,0x87,0x50,0x12,0x08,0x74,0x0D,0x24,0x07,0x8A,0xE0,0xBE,0xCC,0x00,0xA0,0xBC, -0x13,0xE8,0x7A,0x3D,0xFF,0x06,0xBC,0x13,0xFF,0x0E,0xBE,0x13,0x75,0xDA,0xC3,0x90, -0x1E,0x33,0xC0,0x8E,0xD8,0xB0,0x01,0xE8,0x3A,0x3D,0x1F,0xC3,0x33,0xC9,0x8B,0xF1, -0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xC7,0x46,0x62,0x1A,0x44,0xC7,0x46, -0x7C,0xDE,0x3B,0xC7,0x46,0x7E,0xC4,0x3B,0xC7,0x86,0x80,0x00,0xCE,0x3C,0xE8,0xAB, -0x16,0xC6,0x86,0xC0,0x00,0x11,0x83,0x7E,0x08,0x00,0x74,0x07,0x51,0x56,0xE8,0x19, -0x33,0x5E,0x59,0x46,0x46,0xE2,0xCD,0xC3,0x33,0xC9,0x8B,0xF1,0x8B,0xF9,0x8A,0x0E, -0x94,0x12,0xC1,0xE9,0x02,0xE3,0x13,0x2E,0x8B,0xAC,0x44,0x00,0x8A,0x86,0x9E,0x00, -0x88,0x85,0x6C,0x12,0x83,0xC6,0x08,0x47,0xE2,0xED,0xC3,0xFA,0xFC,0xB0,0xC0,0xBA, -0x00,0x01,0xEE,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8E,0xD0,0xBF,0x16,0x01,0xB9,0xCC, -0x77,0x2B,0xCF,0xD1,0xE9,0xF3,0xAB,0xBC,0x40,0x12,0xE8,0xD9,0x02,0xE8,0x56,0x3C, -0xBE,0xC8,0x0F,0xE8,0xD8,0x3C,0xF4,0x90,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8E,0xD0, -0xF6,0x06,0x0A,0x01,0x80,0x74,0x0B,0xBE,0x17,0x55,0xE8,0xC1,0x3C,0xB0,0x01,0xE8, -0x92,0x3C,0xE8,0xB3,0x00,0xE8,0xFA,0xF5,0xE8,0x08,0xF8,0xE8,0x0F,0xF9,0xE8,0x85, -0xFA,0xE8,0xB6,0xFA,0xE8,0xEF,0xFC,0xE8,0xC2,0x10,0xE8,0xE9,0x3B,0xE8,0xB2,0xFD, -0xE8,0x30,0xFD,0xE8,0x54,0x02,0xC6,0x06,0x8F,0x12,0xC0,0xE8,0xBB,0xFA,0xE8,0xEB, -0xFA,0xE8,0xE9,0xFB,0xE8,0xAF,0xFC,0xE8,0x8D,0xFC,0xE8,0x1F,0xFF,0xE8,0x58,0xFF, -0xE8,0xDB,0xFD,0xE8,0x16,0xFE,0x33,0xC0,0xBE,0x5A,0x05,0xE8,0x70,0x3C,0xE8,0xA3, -0xFE,0xE8,0xE0,0xFC,0xFB,0xBE,0x86,0x44,0xE8,0x63,0x3C,0xE9,0xB0,0x2D,0x56,0x98, -0x8B,0xF0,0x8B,0x42,0x52,0x85,0xC0,0x75,0x27,0xC7,0x42,0x52,0x01,0x00,0x53,0x36, -0x8B,0x9C,0x2C,0x01,0xF6,0xC3,0x01,0x75,0x0C,0x36,0x89,0x68,0x52,0x36,0x89,0xAC, -0x2C,0x01,0x5B,0x5E,0xC3,0x36,0x89,0xAC,0x2C,0x01,0x36,0x89,0xAC,0x1C,0x01,0x5B, -0x5E,0xC3,0x56,0x98,0x8B,0xF0,0x33,0xED,0x36,0x8B,0x84,0x1C,0x01,0xA8,0x01,0x75, -0x15,0x8B,0xE8,0x33,0xC0,0x87,0x42,0x52,0x36,0x89,0x84,0x1C,0x01,0xA8,0x01,0x74, -0x05,0x36,0x89,0x84,0x2C,0x01,0x5E,0xC3,0x56,0x51,0x33,0xF6,0xB8,0x01,0x00,0xB9, -0x08,0x00,0x89,0x84,0x1C,0x01,0x89,0x84,0x2C,0x01,0x46,0x46,0xE2,0xF4,0x59,0x5E, -0xC3,0x90,0xBB,0x01,0x00,0x8B,0xE8,0xFF,0x4E,0x6E,0x74,0x0A,0x8B,0xDD,0x8B,0x46, -0x58,0xA8,0x01,0x74,0xF0,0xC3,0x8B,0x46,0x48,0xA9,0x08,0x00,0x74,0x45,0xF7,0x46, -0x38,0x40,0x00,0x74,0x27,0xE8,0x5C,0x10,0x80,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x24, -0xBF,0x88,0x86,0xA8,0x00,0xEE,0x60,0xB0,0xFE,0xE8,0x6C,0x32,0x61,0xB0,0x02,0xE8, -0x4C,0xFF,0x8B,0x46,0x48,0x24,0xF7,0x89,0x46,0x48,0xEB,0x17,0xE8,0x2A,0x10,0x81, -0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C, -0x8B,0x46,0x48,0xA9,0x04,0x00,0x74,0x14,0xB0,0x02,0xE8,0x21,0xFF,0x8B,0x46,0x48, -0x24,0xFB,0x89,0x46,0x48,0x60,0xB0,0xDF,0xE8,0x2D,0x32,0x61,0x33,0xC0,0x87,0x46, -0x58,0xF6,0xC3,0x01,0x75,0x0B,0x36,0x89,0x47,0x58,0xA8,0x01,0x75,0x0D,0xE9,0x74, -0xFF,0xA3,0x22,0x01,0xA8,0x01,0x75,0x03,0xE9,0x6A,0xFF,0x89,0x1E,0x32,0x01,0xC3, -0xBB,0x01,0x00,0x8B,0xE8,0xF7,0x46,0x38,0x40,0x00,0x74,0x15,0xE8,0xD5,0x0F,0x80, -0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x0A,0x8B,0xDD,0x8B,0x46,0x56,0xA8,0x01,0x74,0xE3, -0xC3,0x8B,0x46,0x26,0x80,0xE4,0xFE,0x80,0xCC,0x02,0x89,0x46,0x26,0xB0,0x02,0xE8, -0xBC,0xFE,0x33,0xC0,0x87,0x46,0x56,0xF6,0xC3,0x01,0x75,0x0A,0x36,0x89,0x47,0x56, -0xA8,0x01,0x75,0x0B,0xEB,0xBD,0xA3,0x20,0x01,0xA8,0x01,0x75,0x02,0xEB,0xB4,0x89, -0x1E,0x30,0x01,0xC3,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA0,0x90,0x12,0x84,0xC0, -0x75,0x49,0xA1,0x22,0x01,0xA8,0x01,0x75,0x03,0xE8,0xF6,0xFE,0xA1,0x20,0x01,0xA8, -0x01,0x75,0x03,0xE8,0x8A,0xFF,0xA1,0xAC,0x13,0x48,0x78,0x05,0x74,0x45,0xA3,0xAC, -0x13,0xA1,0xAE,0x13,0x48,0x78,0x05,0x74,0x51,0xA3,0xAE,0x13,0xA1,0xB0,0x13,0x48, -0x78,0x05,0x74,0x63,0xA3,0xB0,0x13,0xA1,0x7E,0x12,0x40,0x78,0x03,0xA3,0x7E,0x12, -0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0xA0,0x91,0x12,0x40,0x3C, -0x02,0x72,0x0B,0x33,0xC0,0xA2,0x91,0x12,0xFF,0x16,0x7C,0x12,0xEB,0xA4,0xA2,0x91, -0x12,0xEB,0x9F,0xA0,0x8E,0x12,0x32,0x06,0x8F,0x12,0xA2,0x8E,0x12,0x0A,0x06,0x1A, -0x01,0xBA,0x00,0x01,0xEE,0xB8,0x2C,0x01,0xEB,0xA4,0x83,0x3E,0x84,0x12,0x10,0x72, -0x11,0xBA,0x28,0xFF,0xED,0x0C,0x81,0xEF,0xE8,0x39,0x37,0xBA,0x28,0xFF,0xED,0x24, -0x7E,0xEF,0xB8,0x04,0x00,0xEB,0x92,0xC6,0x06,0x8D,0x12,0x01,0xE8,0x25,0x37,0xC6, -0x06,0x8D,0x12,0x00,0xA1,0xB2,0x13,0xEB,0x8B,0x90,0x8A,0x1E,0x0B,0x01,0x2A,0xFF, -0x6B,0xC3,0x19,0xBA,0x62,0xFF,0xEF,0xB8,0x0A,0x00,0xBA,0x60,0xFF,0xEF,0xB8,0x01, -0xE0,0xBA,0x66,0xFF,0xEF,0xB8,0xFF,0xFF,0xBA,0x52,0xFF,0xEF,0xB8,0x09,0xC0,0xBA, -0x56,0xFF,0xEF,0xC7,0x06,0xAC,0x13,0x2C,0x01,0xC7,0x06,0xAE,0x13,0x04,0x00,0xC6, -0x06,0x91,0x12,0x00,0xC3,0x90,0x8A,0x1E,0x0B,0x01,0x2A,0xFF,0x6B,0xC3,0x05,0xD1, -0xE8,0xA3,0x18,0x01,0xC3,0x90,0x52,0xBA,0x50,0xFF,0xED,0x5A,0xC3,0x90,0x53,0x51, -0x8B,0x1E,0x18,0x01,0xB9,0x32,0x05,0x90,0xE2,0xFE,0x4B,0x75,0xF7,0x59,0x5B,0xC3, -0xB0,0x80,0xBA,0x00,0x01,0x0A,0x06,0x1A,0x01,0xEE,0xC3,0x90,0xB0,0x40,0xEB,0xF2, -0xB0,0xC0,0xEB,0xEE,0xB0,0x00,0xEB,0xEA,0xFA,0x60,0x06,0x1E,0x16,0x2B,0xDB,0x8E, -0xDB,0x2E,0xA1,0x9C,0x4C,0x2E,0xA3,0x74,0x4C,0xA0,0x93,0x12,0x98,0x8B,0xE8,0x89, -0x26,0x2D,0x7A,0x80,0x3E,0xCA,0x13,0x00,0x74,0x03,0xE9,0x51,0x42,0xE8,0xC0,0xFF, -0xE8,0xAB,0xFF,0xE8,0xA8,0xFF,0xB0,0x20,0xC6,0x06,0x90,0x12,0x00,0xFF,0x16,0x7C, -0x12,0x8B,0xFD,0x83,0xFF,0x0A,0x72,0x11,0xE8,0xB9,0xFF,0xE8,0x90,0xFF,0xE8,0xAB, -0xFF,0xE8,0x8A,0xFF,0x83,0xEF,0x0A,0xEB,0xEA,0x0B,0xFF,0x74,0x0F,0xE8,0xA4,0xFF, -0xE8,0x7B,0xFF,0xE8,0x9A,0xFF,0xE8,0x75,0xFF,0x4F,0x75,0xF1,0xE8,0x95,0xFF,0xE8, -0x6C,0xFF,0xEB,0xB9,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE,0x88,0x86,0xA5,0x00,0xC3, -0x8A,0x86,0xA6,0x00,0x0C,0x02,0xEE,0xC3,0x8B,0x76,0x38,0xF7,0xC6,0x01,0x00,0x74, -0xEF,0x8B,0x4E,0x36,0x8B,0x46,0x2E,0x3B,0xC1,0x73,0x02,0x8B,0xC8,0x2B,0xC1,0x89, -0x46,0x2E,0x01,0x4E,0x34,0xC4,0x7E,0x04,0x26,0x01,0x0D,0x8B,0x7E,0x2C,0x83,0xEA, -0x04,0xF3,0x6C,0x8E,0xC1,0x89,0x7E,0x2C,0x3B,0x46,0x3C,0x72,0x12,0xF7,0xC6,0x20, -0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,0x38,0xB0,0x00,0xE8,0xA0,0xFC,0xC3,0xF7, -0xC6,0x04,0x00,0x74,0x1B,0x8B,0xD8,0x83,0xCE,0x10,0x89,0x76,0x38,0x8A,0x86,0xA7, -0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xC2,0x08,0xEE,0x83,0xEA,0x08,0x8B,0xC3, -0x3D,0x40,0x00,0x72,0x01,0xC3,0x81,0x4E,0x38,0x00,0x04,0x83,0xC2,0x02,0x8A,0x86, -0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0xC3,0x8A,0x86,0xA6,0x00,0x0C,0x02, -0xEE,0xC3,0xF7,0x46,0x38,0x01,0x00,0x74,0xF1,0x8B,0x4E,0x2E,0x32,0xDB,0x8A,0xBE, -0xA3,0x00,0x83,0xC2,0x06,0xC4,0x76,0x04,0x8B,0x7E,0x2C,0x83,0xF9,0x08,0x72,0x2C, -0xEC,0xA8,0x01,0x74,0x16,0x8A,0xE0,0x83,0xEA,0x0A,0xEC,0x83,0xC2,0x0A,0x84,0xE7, -0x75,0x51,0xAA,0xFE,0xC3,0x49,0x83,0xF9,0x08,0x73,0xE5,0x32,0xFF,0x26,0x01,0x1C, -0x01,0x5E,0x34,0x89,0x76,0x04,0x89,0x4E,0x2E,0x89,0x7E,0x2C,0x3B,0x4E,0x3C,0x72, -0x11,0xF6,0x46,0x38,0x20,0x74,0x01,0xC3,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xFD, -0xFB,0xC3,0xF6,0x46,0x38,0x04,0x74,0x15,0x83,0x4E,0x38,0x10,0x8A,0x86,0xA7,0x00, -0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xEA,0x02,0xEE,0x83,0xC2,0x02,0x3D,0x40,0x00, -0x72,0x5D,0xC3,0x32,0xFF,0x26,0x03,0x1C,0x85,0xDB,0x74,0x09,0x26,0x89,0x1C,0x8B, -0xF7,0x47,0x47,0x49,0x49,0x80,0xE4,0x1E,0x80,0xCC,0xC0,0x26,0x89,0x04,0xF6,0xC4, -0x10,0x74,0x27,0x8B,0x76,0x38,0xF7,0xC6,0x00,0x10,0x74,0x0B,0x50,0xFE,0x86,0xB2, -0x00,0xB0,0x0A,0xE8,0xA8,0xFB,0x58,0xF7,0xC6,0x00,0x01,0x74,0x0D,0xE8,0x68,0x26, -0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,0x8B,0xF7,0x33,0xC0,0xAB,0x32, -0xDB,0x8A,0xBE,0xA3,0x00,0x49,0x49,0x83,0xF9,0x08,0x72,0x17,0xE9,0x41,0xFF,0x81, -0x4E,0x38,0x00,0x04,0x83,0xC2,0xF8,0x8A,0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5, -0x00,0xEE,0xC3,0xE9,0x45,0xFF,0x83,0xC2,0x08,0xEC,0x88,0x86,0xAA,0x00,0xC0,0xE8, -0x04,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,0x32,0xE0,0x8B,0x5E,0x3E,0x84,0xE3, -0x74,0x4F,0x8A,0xC1,0x8B,0x4E,0x26,0xF6,0xC5,0x04,0x74,0x0C,0xA8,0x08,0x74,0x05, -0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,0x40,0xF6,0xC5,0x08,0x74,0x0C,0xA8,0x02,0x74, -0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,0xC9,0x80,0x88,0x4E,0x26,0x8B,0xF0,0x8A,0x86, -0xA5,0x00,0x84,0xC9,0x74,0x08,0xA8,0x02,0x74,0x15,0x24,0xFD,0xEB,0x06,0xA8,0x02, -0x75,0x0D,0x0C,0x02,0x88,0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,0x83,0xC2,0x0A,0x8B, -0xC6,0x84,0xE7,0x75,0x01,0xC3,0xC6,0x86,0xBA,0x00,0x01,0xB0,0x0E,0xE8,0xEE,0xFA, -0xF7,0x46,0x38,0x00,0x02,0x74,0xEE,0x83,0x7E,0x2E,0x06,0x72,0xE8,0x8A,0xA6,0xAA, -0x00,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0xB0,0xFF,0xAA,0xB0,0x02,0xAB,0x26,0x83,0x07, -0x03,0x83,0x6E,0x2E,0x03,0x89,0x7E,0x2C,0xF6,0x46,0x38,0x20,0x74,0x01,0xC3,0x83, -0x4E,0x38,0x20,0xB0,0x00,0xE8,0xB6,0xFA,0xC3,0x90,0x83,0xEA,0x08,0xE9,0xB4,0xFD, -0x83,0xC2,0x06,0x8B,0x5E,0x26,0xF6,0xC3,0xC0,0x75,0xEF,0x8B,0x4E,0x1C,0xEC,0x88, -0x86,0xA4,0x00,0x83,0xEA,0x0A,0xA8,0x20,0x75,0x02,0x8A,0xCD,0x32,0xED,0x8B,0x46, -0x1A,0x3B,0xC8,0x73,0x18,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,0xC5,0x76,0x00, -0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,0x00,0x72,0x30,0xC3,0x85,0xC0,0x74, -0x31,0x8B,0xC8,0x01,0x46,0x2A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x80,0xCB,0x02, -0x89,0x5E,0x26,0xE8,0x32,0xF1,0xF6,0xC7,0x01,0x75,0x16,0x83,0xC2,0x02,0xE8,0x53, -0xFD,0xF6,0xC7,0x10,0x75,0x0B,0xB0,0x02,0xE8,0x43,0xFA,0xC3,0xF6,0xC7,0x01,0x74, -0xF0,0xC3,0x80,0xCB,0x02,0x89,0x5E,0x26,0xF6,0xC7,0x01,0x74,0xDE,0x83,0xC2,0x02, -0xE8,0x31,0xFD,0xF6,0x86,0xA4,0x00,0x40,0x74,0x0B,0x80,0xE7,0xFE,0x80,0xCF,0x02, -0x89,0x5E,0x26,0xEB,0xCC,0xB0,0x04,0xE8,0x14,0xFA,0xC3,0xC0,0xC2,0xC8,0xCA,0xC4, -0xC6,0xCC,0xCE,0xD0,0xD2,0xD8,0xDA,0xD4,0xD6,0xDC,0xDE,0x90,0xE9,0x0E,0x01,0xE4, -0xC4,0x8A,0xE0,0xE4,0xC4,0x8B,0xD0,0x83,0xF9,0x08,0x72,0xF0,0x26,0x83,0x3F,0x00, -0x74,0x04,0x8B,0xDF,0x49,0x49,0x8B,0xFB,0x8A,0xDE,0x83,0xE3,0x0F,0x2E,0x8A,0xA7, -0x2B,0x16,0xAB,0xF6,0xC4,0x10,0x74,0x24,0xF7,0xC6,0x00,0x10,0x74,0x0B,0x50,0xFE, -0x86,0xB2,0x00,0xB0,0x0A,0xE8,0xC6,0xF9,0x58,0xF7,0xC6,0x00,0x01,0x74,0x0D,0xE8, -0x86,0x24,0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,0x89,0x7E,0x04,0x33, -0xC0,0xAB,0x49,0x49,0x89,0x4E,0x2E,0x89,0x7E,0x2C,0x8B,0xC1,0xEB,0x4E,0x90,0xEB, -0x9E,0x90,0xE4,0xD6,0x84,0xC0,0x79,0x63,0xE6,0xD0,0x8A,0xC8,0x25,0x03,0x00,0x03, -0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,0x8B,0x4E,0x2E,0xC4, -0x5E,0x04,0x8B,0x7E,0x2C,0x8B,0x76,0x38,0xE4,0x86,0x24,0x07,0x3C,0x03,0x75,0xCF, -0xE4,0x1C,0x91,0x3B,0xC1,0x73,0x02,0x8B,0xC8,0x2B,0xC1,0x89,0x46,0x2E,0x01,0x4E, -0x34,0x26,0x01,0x0F,0xBA,0xC4,0x00,0xF3,0x6C,0x89,0x7E,0x2C,0x3B,0x46,0x3C,0x72, -0x1C,0xF7,0xC6,0x20,0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,0x38,0xB0,0x00,0xE8, -0x3C,0xF9,0x8A,0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD6,0xC3,0xF9,0xC3,0xF7,0xC6,0x0A, -0x00,0x74,0x35,0xF7,0xC6,0x10,0x00,0x75,0x2F,0x83,0xCE,0x10,0x89,0x76,0x38,0xF7, -0xC6,0x02,0x00,0x74,0x0E,0x50,0xE4,0xD8,0x24,0xFE,0xE6,0xD8,0x58,0xF7,0xC6,0x08, -0x00,0x74,0x15,0x50,0x51,0xB9,0xE8,0x03,0xE4,0x0A,0x84,0xC0,0xE0,0xFA,0x84,0xC0, -0x75,0x04,0xB0,0x24,0xE6,0x0A,0x59,0x58,0x3D,0x40,0x00,0x73,0xB5,0x8A,0x86,0xA5, -0x00,0x24,0xEF,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0xCE,0x10,0x04,0x89,0x76,0x38, -0xEB,0xA0,0x00,0x08,0x04,0x0C,0x01,0x09,0x05,0x0D,0x02,0x0A,0x06,0x0E,0x03,0x0B, -0x07,0x0F,0x00,0x40,0x80,0xC0,0x20,0x60,0xA0,0xE0,0x10,0x50,0x90,0xD0,0x30,0x70, -0xB0,0xF0,0xE4,0xD2,0xE6,0xD0,0x8A,0xC8,0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E, -0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,0xE4,0xD8,0xC0,0xE8,0x04,0x8B,0xD8,0x2E, -0x8A,0x87,0x62,0x17,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,0x32,0xE0,0xE4,0x98, -0x8B,0x5E,0x3E,0x84,0xE3,0x74,0x54,0x8A,0xC1,0x8B,0x4E,0x26,0xF6,0xC5,0x04,0x74, -0x0C,0xA8,0x08,0x74,0x05,0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,0x40,0xF6,0xC5,0x08, -0x74,0x0C,0xA8,0x02,0x74,0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,0xC9,0x80,0x88,0x4E, -0x26,0x8B,0xF0,0x8A,0x86,0xA5,0x00,0xF6,0xC1,0xFD,0x74,0x08,0xA8,0x06,0x74,0x19, -0x24,0xF9,0xEB,0x0F,0xA8,0x06,0x75,0x11,0xF6,0xC5,0x01,0x75,0x04,0x0C,0x04,0xEB, -0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x8B,0xC6,0x84,0xE7,0x75,0x09,0x8A, -0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD2,0xC3,0xC6,0x86,0xBA,0x00,0x01,0xB0,0x0E,0xE8, -0x1C,0xF8,0xF7,0x46,0x38,0x00,0x02,0x74,0xE6,0x83,0x7E,0x2E,0x06,0x72,0xE0,0x8A, -0x86,0xA9,0x00,0x8A,0xE0,0x86,0x86,0xAA,0x00,0x8A,0xC8,0x32,0xC4,0x80,0xC9,0x0B, -0x22,0xC1,0xC0,0xE4,0x04,0x0A,0xE0,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0xB0,0xFF,0xAA, -0xB0,0x02,0xAB,0x26,0x83,0x07,0x03,0x83,0x6E,0x2E,0x03,0x89,0x7E,0x2C,0xF6,0x46, -0x38,0x20,0x75,0xAB,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xD1,0xF7,0xEB,0xA0,0x90, -0xE4,0x12,0x24,0xDF,0xE6,0x12,0x81,0xE3,0xFE,0x9F,0x89,0x5E,0x26,0x83,0x66,0x48, -0xF7,0xEB,0x73,0x90,0xF6,0xC7,0x20,0x75,0xE7,0xE4,0x12,0x0C,0x20,0xE6,0x12,0x32, -0xC0,0xE6,0xC6,0xB0,0x83,0xE6,0xC6,0x80,0xCF,0x20,0x89,0x5E,0x26,0x8A,0x86,0xA5, -0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xEB,0x74,0x90,0xF6,0xC7,0x40,0x75, -0xD3,0xE4,0x12,0x0C,0x20,0xE6,0x12,0x32,0xC0,0xE6,0xC6,0xB0,0x81,0xE6,0xC6,0x80, -0xE7,0xDF,0x80,0xCB,0x01,0x89,0x5E,0x26,0xB0,0x06,0xE8,0x71,0xF7,0x90,0x8A,0x86, -0xA5,0x00,0x24,0xF9,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,0x43,0xE4,0xD4,0xE6,0xD0, -0x8B,0xF8,0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x8B,0x5E, -0x26,0xF6,0xC7,0x60,0x75,0xB6,0xF6,0xC3,0xC0,0x75,0xD3,0xBA,0xC6,0x00,0x8B,0x4E, -0x1C,0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x1E,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A, -0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,0x00,0x72,0x3D,0x8B, -0xC7,0x24,0x3F,0xE6,0xD4,0xC3,0x85,0xC0,0x74,0x39,0x8B,0xC8,0x01,0x46,0x2A,0xC5, -0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x83,0xCB,0x02,0x89,0x5E,0x26,0xE8,0xD9,0xED,0xF6, -0xC7,0x01,0x75,0x39,0x8A,0x86,0xA5,0x00,0x24,0xF9,0xE6,0x0C,0x88,0x86,0xA5,0x00, -0xF6,0xC7,0x10,0x75,0xCA,0xB0,0x02,0xE8,0xE4,0xF6,0xEB,0xC3,0xF6,0xC7,0x01,0x74, -0xEF,0xEB,0xBC,0xF6,0xC7,0x01,0x74,0xDC,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,0x11, -0x81,0xE3,0xFF,0xFE,0x81,0xCB,0x00,0x02,0x89,0x5E,0x26,0xEB,0xC7,0x8A,0x86,0xA5, -0x00,0x24,0xFB,0x0C,0x02,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,0x92,0x90,0xFD,0xF7, -0xDF,0x7F,0xFE,0xFB,0xEF,0xBF,0x00,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04, -0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, -0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04, -0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, -0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04, -0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, -0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04, -0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, -0x06,0x04,0x05,0x04,0x05,0x04,0x03,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04, -0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, -0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x01,0x04, -0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, -0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04, -0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, -0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x07,0x04, -0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x06,0x04, -0x06,0x04,0x05,0x04,0x05,0x04,0x33,0xDB,0x8A,0xD8,0x8A,0x87,0x6C,0x12,0xE6,0xFE, -0xC1,0xE3,0x02,0xE4,0xCE,0xA8,0x04,0x75,0x09,0xA8,0x02,0x74,0x03,0xE9,0x2C,0xFE, -0xF9,0xC3,0x50,0x53,0xE8,0xCB,0xFC,0x5B,0x58,0xA8,0x02,0x74,0x03,0xE9,0x1C,0xFE, -0xF8,0xC3,0x33,0xDB,0x8A,0xD8,0x8A,0x87,0x6C,0x12,0xE6,0xFE,0xC1,0xE3,0x02,0xE9, -0xD0,0xFB,0x96,0x1A,0xC2,0x1A,0x00,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x0E,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x06,0x00, -0x02,0x00,0x04,0x00,0x02,0x00,0xC3,0x90,0xD6,0x14,0x90,0x15,0x58,0x13,0xE2,0x13, -0xD6,0x1B,0xD6,0x1B,0xE2,0x13,0xD6,0x1B,0x8B,0x94,0x64,0x12,0xC1,0xE6,0x04,0xA8, -0x01,0x74,0x35,0x50,0x33,0xC0,0x8A,0xC2,0xE6,0xFE,0xE4,0xA0,0x85,0xC0,0x74,0x27, -0x8B,0xD8,0x2E,0x8A,0x9F,0xD6,0x1A,0x52,0x56,0x2E,0x8B,0xA8,0x44,0x00,0x8B,0x56, -0x28,0xEC,0xA8,0x01,0x75,0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,0x8A,0xD8,0x2E,0xFF, -0x97,0xD8,0x1B,0x5E,0x5A,0xEB,0xCD,0x58,0xA8,0x02,0x74,0x36,0x83,0xC6,0x10,0x33, -0xC0,0x8A,0xC6,0xE6,0xFE,0xE4,0xA0,0x85,0xC0,0x74,0x27,0x8B,0xD8,0x2E,0x8A,0x9F, -0xD6,0x1A,0x52,0x56,0x2E,0x8B,0xA8,0x44,0x00,0x8B,0x56,0x28,0xEC,0xA8,0x01,0x75, -0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,0x8A,0xD8,0x2E,0xFF,0x97,0xD8,0x1B,0x5E,0x5A, -0xEB,0xCD,0xC3,0x90,0x32,0xE4,0x8B,0xD8,0x8B,0xD0,0x2E,0x8A,0x9F,0x96,0x19,0x2E, -0x22,0x97,0x8E,0x19,0x56,0x52,0x8A,0xC3,0x24,0x03,0x03,0xC6,0x80,0xE3,0x04,0xD0, -0xEB,0x2E,0xFF,0x97,0xD2,0x1A,0x58,0x5E,0xA9,0x55,0x00,0x75,0xD9,0xC3,0x60,0x1E, -0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x08, -0x33,0xF6,0xE8,0xBF,0xFF,0xEB,0xEE,0x90,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00, -0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1, -0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x08,0xBE,0x04,0x00,0xE8,0x94,0xFF, -0xEB,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61, -0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00, -0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x6B,0xFF,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00, -0x22,0xC4,0x74,0xE5,0xBE,0x08,0x00,0xE8,0x5A,0xFF,0xEB,0xDD,0xA1,0x60,0x12,0xE6, -0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0xA1,0x5C,0x12,0xE6, -0xFE,0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90, -0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4, -0x74,0x19,0xBE,0x04,0x00,0xE8,0x1C,0xFF,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00,0x22, -0xC4,0x74,0xE4,0xBE,0x0C,0x00,0xE8,0x0B,0xFF,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE, -0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0xA1,0x5E,0x12,0xE6,0xFE, -0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E, -0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08, -0x33,0xF6,0xE8,0x53,0xFE,0xEB,0xEE,0x90,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07, -0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE, -0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x02,0x00,0xE8,0x2C,0xFE,0xEB,0xED,0xB8,0x00, +0xCC,0x04,0xD0,0x00,0xDA,0x20,0xDC,0x03,0xDE,0x01,0xD8,0x03,0xCC,0x03,0xCC,0x03, +0xCC,0x03,0xCC,0x00,0xD8,0x00,0xCC,0x00,0xD0,0x00,0x00,0x56,0x52,0x1E,0x0E,0x1F, +0xBE,0x2F,0x09,0x33,0xD2,0xFC,0xAD,0x85,0xC0,0x74,0x0D,0x8A,0xD4,0xEE,0xAD,0x85, +0xC0,0x74,0x05,0x8A,0xD4,0xEE,0xEB,0xEE,0x1F,0x5A,0x5E,0xC3,0xE4,0x80,0x84,0xC0, +0x74,0x16,0x78,0x14,0xB0,0x27,0xE6,0xFC,0xB0,0x11,0xE6,0x34,0xE4,0xFC,0x3C,0x27, +0x75,0x06,0xE4,0x11,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x83,0xC2,0x06,0xB0,0xBF,0xEE, +0x83,0xEA,0x02,0xB0,0x10,0xEE,0x88,0x86,0xAF,0x00,0xB0,0x11,0x83,0xC2,0x04,0xEE, +0x83,0xC2,0x02,0xEE,0xB0,0x13,0x83,0xC2,0x02,0xEE,0x83,0xC2,0x02,0xEE,0x2E,0xA1, +0x4C,0x2D,0x89,0x86,0x94,0x00,0x83,0xEA,0x0E,0xEE,0x83,0xC2,0x02,0x8A,0xC4,0xEE, +0x83,0xC2,0x04,0xB0,0x03,0xEE,0x88,0x86,0xA8,0x00,0x83,0xEA,0x04,0x32,0xC0,0xEE, +0x83,0xC2,0x02,0xB0,0x89,0xEE,0x88,0x86,0xA6,0x00,0x0C,0x06,0xEE,0xB0,0x40,0xB4, +0x38,0x89,0x46,0x1C,0xC7,0x46,0x36,0x38,0x00,0x83,0xC2,0x04,0x32,0xC0,0xEE,0x88, +0x86,0xA7,0x00,0xC3,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x83,0xEA,0x02,0xEC,0x3A,0x86, +0xAF,0x00,0x75,0x24,0x83,0xC2,0x04,0xEC,0x3C,0x11,0x75,0x1C,0x83,0xC2,0x06,0xEC, +0x3C,0x13,0x75,0x14,0x83,0xEA,0x08,0x8A,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x02,0xEC, +0x24,0xC0,0x3C,0xC0,0x75,0x02,0xF8,0xC3,0xF9,0xC3,0x33,0xC9,0x8B,0xD1,0x8B,0xF1, +0x8A,0x0E,0x94,0x12,0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00, +0x20,0x74,0x0E,0x8A,0x86,0x9E,0x00,0xE6,0xFE,0x32,0xC0,0xE6,0x80,0x42,0xE8,0xFA, +0xFE,0x83,0xC6,0x08,0xE2,0xE1,0x85,0xD2,0x74,0x03,0xE8,0x05,0x08,0xC3,0x33,0xC9, +0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00, +0x74,0x06,0xE8,0x73,0x16,0xE8,0x12,0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B, +0xF1,0x8A,0x0E,0x94,0x12,0xC1,0xE9,0x02,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38, +0x00,0x20,0x74,0x16,0xE8,0x46,0x16,0xE8,0xD2,0xFE,0x73,0x0E,0x6A,0x00,0x1F,0xC6, +0x06,0x93,0x12,0x1C,0x9C,0x0E,0xE8,0xE3,0x07,0x90,0x83,0xC6,0x08,0xE2,0xD9,0xC3, +0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38, +0x40,0x00,0x74,0x16,0xE8,0x21,0x16,0xE8,0x2A,0xFF,0x73,0x0E,0x6A,0x00,0x1F,0xC6, +0x06,0x93,0x12,0x1C,0x9C,0x0E,0xE8,0xB3,0x07,0x90,0x46,0x46,0xE2,0xDA,0xC3,0x0C, +0x00,0x00,0x10,0x00,0x13,0x12,0x00,0x00,0x14,0x00,0x28,0x3C,0x00,0x1B,0x3E,0x00, +0x00,0x2A,0x00,0x00,0x2C,0x00,0x00,0x42,0x00,0x14,0xD8,0x00,0x00,0xDA,0x00,0x00, +0x34,0x00,0x11,0x36,0x00,0x13,0x38,0x00,0x11,0x3A,0x00,0x13,0x00,0x00,0x56,0x50, +0x52,0xBE,0x2F,0x0B,0x2E,0xAD,0x85,0xC0,0x74,0x06,0x92,0x2E,0xAC,0xEE,0xEB,0xF4, +0x5A,0x58,0x5E,0xC3,0x53,0x2E,0xA1,0x60,0x22,0xE6,0xE4,0xE6,0xF0,0x8A,0xC4,0xE6, +0xEC,0xE6,0xF8,0xE8,0xD8,0xFF,0xB0,0x4B,0xE6,0x10,0xB0,0x50,0xE6,0x12,0xB0,0x38, +0xE6,0x14,0xE8,0xAE,0x15,0xB0,0x46,0xE6,0x0A,0xE8,0xA7,0x15,0xB0,0x1A,0xE6,0x0A, +0xE8,0xA0,0x15,0xB0,0x22,0xE6,0x0A,0xE8,0x99,0x15,0xE8,0xFD,0x06,0x8B,0xD8,0xE4, +0x16,0xA8,0x04,0x75,0x18,0xE8,0xF2,0x06,0x2B,0xC3,0x3D,0x32,0x00,0x72,0xF0,0x6A, +0x00,0x1F,0xC6,0x06,0x93,0x12,0x23,0x9C,0x0E,0xE8,0x10,0x07,0x90,0xE8,0xDA,0x06, +0x2B,0xC3,0x3D,0x24,0x00,0x77,0x1B,0xB0,0x31,0xE6,0xFC,0x56,0x51,0x55,0xB9,0x10, +0x00,0x2E,0x8B,0xAC,0x44,0x00,0x81,0x4E,0x38,0x80,0x00,0x46,0x46,0xE2,0xF2,0x5D, +0x59,0x5E,0xE8,0x69,0xFF,0xE8,0x4B,0x15,0xB0,0x46,0xE6,0x0A,0xE8,0x44,0x15,0x5B, +0xC3,0x33,0xF6,0x8B,0x0E,0x42,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00, +0x20,0x74,0x06,0xE8,0x17,0x15,0xE8,0x5B,0xFF,0x83,0xC6,0x20,0xE2,0xE9,0xC3,0x8B, +0xC2,0x05,0x04,0x00,0x89,0x46,0x28,0x2E,0xA1,0x4C,0x2D,0x89,0x86,0x8E,0x00,0x89, +0x86,0x90,0x00,0x89,0x86,0x92,0x00,0xC6,0x86,0xA3,0x00,0x0A,0xC6,0x86,0xC3,0x00, +0x03,0x52,0x83,0xC2,0x04,0x8A,0x86,0xA6,0x00,0x0C,0x06,0xEE,0x5A,0x83,0xC2,0x02, +0xB0,0x05,0xEE,0x88,0x86,0xA5,0x00,0xC3,0xE8,0x03,0xFF,0xE8,0xE5,0x14,0xB0,0x42, +0xE6,0x0A,0xF7,0x46,0x38,0x80,0x00,0x74,0x06,0x2E,0xA1,0x9C,0x22,0xEB,0x04,0x2E, +0xA1,0x6C,0x22,0xC7,0x46,0x1C,0x0C,0x00,0x89,0x86,0x94,0x00,0x89,0x86,0x96,0x00, +0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x89,0x86,0x92,0x00,0xE6,0xF0,0xE6,0xE4, +0x8A,0xC4,0xE6,0xF8,0xE6,0xEC,0xC6,0x86,0xC3,0x00,0x03,0xE8,0xA5,0x14,0xB0,0x1A, +0xE6,0x0A,0xB0,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0x33,0xC9,0x8B,0xF1,0x8A, +0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x40,0x00,0x74,0x06,0xE8, +0x76,0x14,0xE8,0x5A,0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x33,0xC9,0x8B,0xF1,0x8A,0x0E, +0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xF7,0x46,0x38,0x00,0x20,0x74,0x06,0xE8,0x4C, +0x14,0xE8,0x74,0xFF,0x46,0x46,0xE2,0xEA,0xC3,0x90,0x83,0x3E,0x44,0x12,0x00,0x75, +0x14,0xB0,0x01,0xBA,0x06,0x01,0xEE,0x2A,0xC0,0xEE,0xB0,0x02,0xEE,0xB0,0x04,0xEE, +0xB8,0x00,0x02,0xEB,0x0F,0xBA,0x06,0x01,0xB0,0x40,0xEE,0xB8,0x01,0x00,0x8A,0x0E, +0x0E,0x01,0xD3,0xE0,0xA3,0x88,0x12,0xC3,0xA1,0x88,0x12,0xA3,0x84,0x12,0x2D,0x20, +0x00,0xA3,0x8A,0x12,0x2D,0x20,0x00,0xA3,0x82,0x12,0xC7,0x06,0x86,0x12,0x20,0x00, +0xC7,0x06,0x80,0x12,0x32,0x00,0xC3,0x83,0x3E,0x44,0x12,0x00,0x74,0x76,0x8B,0x0E, +0x42,0x12,0x33,0xF6,0x8A,0xA4,0x54,0x12,0x84,0xE4,0x74,0x5F,0x8A,0x84,0x48,0x12, +0x0C,0x04,0xE6,0xFE,0xF6,0xC4,0x04,0x74,0x25,0xB0,0x1B,0xBA,0x00,0x00,0xEE,0xEB, +0x00,0x2A,0xC0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03,0xEE,0xEB,0x00,0x32,0xC0, +0xBA,0x02,0x00,0xEE,0xEB,0x00,0xBA,0x00,0x00,0xB0,0x00,0xEE,0xEB,0x2D,0xB0,0x1F, +0xBA,0x00,0x00,0xEE,0xEB,0x00,0x2A,0xC0,0xBA,0x02,0x00,0xEE,0xEB,0x00,0xB0,0x03, +0xEE,0xEB,0x00,0xD1,0xE6,0x8A,0x84,0x5D,0x12,0xD1,0xEE,0xF6,0xD0,0xBA,0x02,0x00, +0xEE,0xEB,0x00,0xBA,0x00,0x00,0xB0,0x0A,0xEE,0xEB,0x00,0xE4,0x04,0xEB,0x00,0xE4, +0x04,0x46,0xE2,0x90,0xC3,0x90,0xB8,0x14,0x00,0xBA,0x3E,0xFF,0xEF,0xB8,0x06,0x00, +0xBA,0x32,0xFF,0xEF,0xB8,0x0F,0x00,0xBA,0x34,0xFF,0xEF,0xBA,0x36,0xFF,0xEF,0x83, +0x3E,0x44,0x12,0x00,0x75,0x16,0xB8,0x11,0x00,0xBA,0x38,0xFF,0xEF,0xB8,0x12,0x00, +0xBA,0x3A,0xFF,0xEF,0xB8,0x1B,0x00,0xBA,0x3C,0xFF,0xEF,0xC3,0xB8,0x11,0x00,0xBA, +0x38,0xFF,0xEF,0xB8,0x12,0x00,0xBA,0x3A,0xFF,0xEF,0xB8,0x1B,0x00,0xBA,0x3C,0xFF, +0xEF,0xC3,0xB8,0xFC,0x00,0xBA,0x28,0xFF,0xEF,0xFB,0x83,0x3E,0x44,0x12,0x00,0x74, +0x07,0xB8,0xCC,0x00,0xBA,0x28,0xFF,0xEF,0xC3,0x00,0xFF,0xFF,0x20,0x24,0x28,0xFF, +0x2C,0xFF,0xFF,0x30,0x34,0x38,0xFF,0xFF,0x3C,0x90,0x3C,0x0F,0x77,0x0E,0xBB,0x19, +0x0E,0x2E,0xD7,0x3C,0xFF,0x74,0x05,0x8A,0xD8,0xF8,0xC3,0x90,0x2A,0xDB,0xF9,0xC3, +0x83,0x3E,0x44,0x12,0x00,0x74,0x27,0xA0,0x06,0x01,0x80,0x26,0x06,0x01,0x30,0x80, +0x3E,0x06,0x01,0x30,0x75,0x18,0xB9,0x02,0x00,0xBF,0xC4,0x13,0xBA,0x06,0x01,0xEC, +0xA8,0x20,0x75,0xF8,0xBA,0x04,0x01,0xED,0xAB,0xE2,0xF1,0xEB,0x16,0x90,0xB9,0x04, +0x00,0xBF,0xC4,0x13,0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xF8,0xBA,0x04,0x01,0xEC, +0xAA,0xE2,0xF1,0xFA,0x90,0xBE,0xC4,0x13,0xAD,0x80,0xE4,0x3F,0x80,0xFC,0x02,0x74, +0x0E,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x0A,0x9C,0x0E,0xE8,0x3E,0x04,0x90,0xAD, +0x3C,0x0F,0x75,0xED,0x8A,0xC4,0xE8,0x81,0xFF,0x72,0xE6,0x88,0x1E,0x1A,0x01,0xC6, +0x06,0x8E,0x12,0x00,0xB0,0x00,0x0A,0x06,0x1A,0x01,0xBA,0x00,0x01,0xEE,0xC6,0x06, +0x8F,0x12,0x40,0x83,0x3E,0x44,0x12,0x00,0x75,0x06,0xB8,0x0C,0x00,0xEB,0x04,0x90, +0xB8,0x4C,0x00,0xBA,0x28,0xFF,0xEF,0xC3,0x83,0x3E,0x44,0x12,0x00,0x75,0x01,0xC3, +0xA1,0x50,0x12,0x0B,0x06,0x52,0x12,0x0A,0xC4,0xA8,0x08,0x74,0xF2,0xA0,0x0F,0x01, +0x2A,0xE4,0x50,0xFF,0x36,0xBA,0x13,0x1F,0xE8,0x50,0x56,0x83,0xC4,0x02,0x6A,0x00, +0x1F,0x33,0xC0,0xA3,0xBC,0x13,0xA0,0x0F,0x01,0xA3,0xBE,0x13,0x8B,0x1E,0xBC,0x13, +0x8A,0x87,0x50,0x12,0xF6,0x87,0x50,0x12,0x08,0x74,0x0D,0x24,0x07,0x8A,0xE0,0xBE, +0xCC,0x00,0xA0,0xBC,0x13,0xE8,0x94,0x3D,0xFF,0x06,0xBC,0x13,0xFF,0x0E,0xBE,0x13, +0x75,0xDA,0xC3,0x90,0x1E,0x33,0xC0,0x8E,0xD8,0xB0,0x01,0xE8,0x54,0x3D,0x1F,0xC3, +0x33,0xC9,0x8B,0xF1,0x8A,0x0E,0x94,0x12,0x2E,0x8B,0xAC,0x44,0x00,0xC7,0x46,0x62, +0x38,0x44,0xC7,0x46,0x7C,0xFC,0x3B,0xC7,0x46,0x7E,0xE2,0x3B,0xC7,0x86,0x80,0x00, +0xEC,0x3C,0xE8,0xAB,0x16,0xC6,0x86,0xC0,0x00,0x11,0x83,0x7E,0x08,0x00,0x74,0x07, +0x51,0x56,0xE8,0x33,0x33,0x5E,0x59,0x46,0x46,0xE2,0xCD,0xC3,0x33,0xC9,0x8B,0xF1, +0x8B,0xF9,0x8A,0x0E,0x94,0x12,0xC1,0xE9,0x02,0xE3,0x13,0x2E,0x8B,0xAC,0x44,0x00, +0x8A,0x86,0x9E,0x00,0x88,0x85,0x6C,0x12,0x83,0xC6,0x08,0x47,0xE2,0xED,0xC3,0xFA, +0xFC,0xB0,0xC0,0xBA,0x00,0x01,0xEE,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8E,0xD0,0xBF, +0x16,0x01,0xB9,0xCC,0x77,0x2B,0xCF,0xD1,0xE9,0xF3,0xAB,0xBC,0x40,0x12,0xE8,0xD9, +0x02,0xE8,0x70,0x3C,0xBE,0xCC,0x0F,0xE8,0xF2,0x3C,0xF4,0x90,0x33,0xC0,0x8E,0xD8, +0x8E,0xC0,0x8E,0xD0,0xF6,0x06,0x0A,0x01,0x80,0x74,0x0B,0xBE,0x35,0x55,0xE8,0xDB, +0x3C,0xB0,0x01,0xE8,0xAC,0x3C,0xE8,0xB3,0x00,0xE8,0xF6,0xF5,0xE8,0x08,0xF8,0xE8, +0x0F,0xF9,0xE8,0x85,0xFA,0xE8,0xB6,0xFA,0xE8,0xEF,0xFC,0xE8,0xC2,0x10,0xE8,0x03, +0x3C,0xE8,0xB2,0xFD,0xE8,0x30,0xFD,0xE8,0x54,0x02,0xC6,0x06,0x8F,0x12,0xC0,0xE8, +0xBB,0xFA,0xE8,0xEB,0xFA,0xE8,0xE9,0xFB,0xE8,0xAF,0xFC,0xE8,0x8D,0xFC,0xE8,0x1F, +0xFF,0xE8,0x58,0xFF,0xE8,0xDB,0xFD,0xE8,0x16,0xFE,0x33,0xC0,0xBE,0x5A,0x05,0xE8, +0x8A,0x3C,0xE8,0xA3,0xFE,0xE8,0xE0,0xFC,0xFB,0xBE,0xA4,0x44,0xE8,0x7D,0x3C,0xE9, +0xCA,0x2D,0x56,0x98,0x8B,0xF0,0x8B,0x42,0x52,0x85,0xC0,0x75,0x27,0xC7,0x42,0x52, +0x01,0x00,0x53,0x36,0x8B,0x9C,0x2C,0x01,0xF6,0xC3,0x01,0x75,0x0C,0x36,0x89,0x68, +0x52,0x36,0x89,0xAC,0x2C,0x01,0x5B,0x5E,0xC3,0x36,0x89,0xAC,0x2C,0x01,0x36,0x89, +0xAC,0x1C,0x01,0x5B,0x5E,0xC3,0x56,0x98,0x8B,0xF0,0x33,0xED,0x36,0x8B,0x84,0x1C, +0x01,0xA8,0x01,0x75,0x15,0x8B,0xE8,0x33,0xC0,0x87,0x42,0x52,0x36,0x89,0x84,0x1C, +0x01,0xA8,0x01,0x74,0x05,0x36,0x89,0x84,0x2C,0x01,0x5E,0xC3,0x56,0x51,0x33,0xF6, +0xB8,0x01,0x00,0xB9,0x08,0x00,0x89,0x84,0x1C,0x01,0x89,0x84,0x2C,0x01,0x46,0x46, +0xE2,0xF4,0x59,0x5E,0xC3,0x90,0xBB,0x01,0x00,0x8B,0xE8,0xFF,0x4E,0x6E,0x74,0x0A, +0x8B,0xDD,0x8B,0x46,0x58,0xA8,0x01,0x74,0xF0,0xC3,0x8B,0x46,0x48,0xA9,0x08,0x00, +0x74,0x45,0xF7,0x46,0x38,0x40,0x00,0x74,0x27,0xE8,0x5C,0x10,0x80,0xC2,0x06,0x8A, +0x86,0xA8,0x00,0x24,0xBF,0x88,0x86,0xA8,0x00,0xEE,0x60,0xB0,0xFE,0xE8,0x86,0x32, +0x61,0xB0,0x02,0xE8,0x4C,0xFF,0x8B,0x46,0x48,0x24,0xF7,0x89,0x46,0x48,0xEB,0x17, +0xE8,0x2A,0x10,0x81,0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86, +0xA5,0x00,0xE6,0x0C,0x8B,0x46,0x48,0xA9,0x04,0x00,0x74,0x14,0xB0,0x02,0xE8,0x21, +0xFF,0x8B,0x46,0x48,0x24,0xFB,0x89,0x46,0x48,0x60,0xB0,0xDF,0xE8,0x47,0x32,0x61, +0x33,0xC0,0x87,0x46,0x58,0xF6,0xC3,0x01,0x75,0x0B,0x36,0x89,0x47,0x58,0xA8,0x01, +0x75,0x0D,0xE9,0x74,0xFF,0xA3,0x22,0x01,0xA8,0x01,0x75,0x03,0xE9,0x6A,0xFF,0x89, +0x1E,0x32,0x01,0xC3,0xBB,0x01,0x00,0x8B,0xE8,0xF7,0x46,0x38,0x40,0x00,0x74,0x15, +0xE8,0xD5,0x0F,0x80,0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x0A,0x8B,0xDD,0x8B,0x46,0x56, +0xA8,0x01,0x74,0xE3,0xC3,0x8B,0x46,0x26,0x80,0xE4,0xFE,0x80,0xCC,0x02,0x89,0x46, +0x26,0xB0,0x02,0xE8,0xBC,0xFE,0x33,0xC0,0x87,0x46,0x56,0xF6,0xC3,0x01,0x75,0x0A, +0x36,0x89,0x47,0x56,0xA8,0x01,0x75,0x0B,0xEB,0xBD,0xA3,0x20,0x01,0xA8,0x01,0x75, +0x02,0xEB,0xB4,0x89,0x1E,0x30,0x01,0xC3,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA0, +0x90,0x12,0x84,0xC0,0x75,0x49,0xA1,0x22,0x01,0xA8,0x01,0x75,0x03,0xE8,0xF6,0xFE, +0xA1,0x20,0x01,0xA8,0x01,0x75,0x03,0xE8,0x8A,0xFF,0xA1,0xAC,0x13,0x48,0x78,0x05, +0x74,0x45,0xA3,0xAC,0x13,0xA1,0xAE,0x13,0x48,0x78,0x05,0x74,0x51,0xA3,0xAE,0x13, +0xA1,0xB0,0x13,0x48,0x78,0x05,0x74,0x63,0xA3,0xB0,0x13,0xA1,0x7E,0x12,0x40,0x78, +0x03,0xA3,0x7E,0x12,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0xA0, +0x91,0x12,0x40,0x3C,0x02,0x72,0x0B,0x33,0xC0,0xA2,0x91,0x12,0xFF,0x16,0x7C,0x12, +0xEB,0xA4,0xA2,0x91,0x12,0xEB,0x9F,0xA0,0x8E,0x12,0x32,0x06,0x8F,0x12,0xA2,0x8E, +0x12,0x0A,0x06,0x1A,0x01,0xBA,0x00,0x01,0xEE,0xB8,0x2C,0x01,0xEB,0xA4,0x83,0x3E, +0x84,0x12,0x10,0x72,0x11,0xBA,0x28,0xFF,0xED,0x0C,0x81,0xEF,0xE8,0x53,0x37,0xBA, +0x28,0xFF,0xED,0x24,0x7E,0xEF,0xB8,0x04,0x00,0xEB,0x92,0xC6,0x06,0x8D,0x12,0x01, +0xE8,0x3F,0x37,0xC6,0x06,0x8D,0x12,0x00,0xA1,0xB2,0x13,0xEB,0x8B,0x90,0x8A,0x1E, +0x0B,0x01,0x2A,0xFF,0x6B,0xC3,0x19,0xBA,0x62,0xFF,0xEF,0xB8,0x0A,0x00,0xBA,0x60, +0xFF,0xEF,0xB8,0x01,0xE0,0xBA,0x66,0xFF,0xEF,0xB8,0xFF,0xFF,0xBA,0x52,0xFF,0xEF, +0xB8,0x09,0xC0,0xBA,0x56,0xFF,0xEF,0xC7,0x06,0xAC,0x13,0x2C,0x01,0xC7,0x06,0xAE, +0x13,0x04,0x00,0xC6,0x06,0x91,0x12,0x00,0xC3,0x90,0x8A,0x1E,0x0B,0x01,0x2A,0xFF, +0x6B,0xC3,0x05,0xD1,0xE8,0xA3,0x18,0x01,0xC3,0x90,0x52,0xBA,0x50,0xFF,0xED,0x5A, +0xC3,0x90,0x53,0x51,0x8B,0x1E,0x18,0x01,0xB9,0x32,0x05,0x90,0xE2,0xFE,0x4B,0x75, +0xF7,0x59,0x5B,0xC3,0xB0,0x80,0xBA,0x00,0x01,0x0A,0x06,0x1A,0x01,0xEE,0xC3,0x90, +0xB0,0x40,0xEB,0xF2,0xB0,0xC0,0xEB,0xEE,0xB0,0x00,0xEB,0xEA,0xFA,0x60,0x06,0x1E, +0x16,0x2B,0xDB,0x8E,0xDB,0x2E,0xA1,0xBA,0x4C,0x2E,0xA3,0x92,0x4C,0xA0,0x93,0x12, +0x98,0x8B,0xE8,0x89,0x26,0x2D,0x7A,0x80,0x3E,0xCA,0x13,0x00,0x74,0x03,0xE9,0x6B, +0x42,0xE8,0xC0,0xFF,0xE8,0xAB,0xFF,0xE8,0xA8,0xFF,0xB0,0x20,0xC6,0x06,0x90,0x12, +0x00,0xFF,0x16,0x7C,0x12,0x8B,0xFD,0x83,0xFF,0x0A,0x72,0x11,0xE8,0xB9,0xFF,0xE8, +0x90,0xFF,0xE8,0xAB,0xFF,0xE8,0x8A,0xFF,0x83,0xEF,0x0A,0xEB,0xEA,0x0B,0xFF,0x74, +0x0F,0xE8,0xA4,0xFF,0xE8,0x7B,0xFF,0xE8,0x9A,0xFF,0xE8,0x75,0xFF,0x4F,0x75,0xF1, +0xE8,0x95,0xFF,0xE8,0x6C,0xFF,0xEB,0xB9,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE,0x88, +0x86,0xA5,0x00,0xC3,0x8A,0x86,0xA6,0x00,0x0C,0x02,0xEE,0xC3,0x8B,0x76,0x38,0xF7, +0xC6,0x01,0x00,0x74,0xEF,0x8B,0x4E,0x36,0x8B,0x46,0x2E,0x3B,0xC1,0x73,0x02,0x8B, +0xC8,0x2B,0xC1,0x89,0x46,0x2E,0x01,0x4E,0x34,0xC4,0x7E,0x04,0x26,0x01,0x0D,0x8B, +0x7E,0x2C,0x83,0xEA,0x04,0xF3,0x6C,0x8E,0xC1,0x89,0x7E,0x2C,0x3B,0x46,0x3C,0x72, +0x12,0xF7,0xC6,0x20,0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76,0x38,0xB0,0x00,0xE8, +0xA0,0xFC,0xC3,0xF7,0xC6,0x04,0x00,0x74,0x1B,0x8B,0xD8,0x83,0xCE,0x10,0x89,0x76, +0x38,0x8A,0x86,0xA7,0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xC2,0x08,0xEE,0x83, +0xEA,0x08,0x8B,0xC3,0x3D,0x40,0x00,0x72,0x01,0xC3,0x81,0x4E,0x38,0x00,0x04,0x83, +0xC2,0x02,0x8A,0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0xC3,0x8A,0x86, +0xA6,0x00,0x0C,0x02,0xEE,0xC3,0xF7,0x46,0x38,0x01,0x00,0x74,0xF1,0x8B,0x4E,0x2E, +0x32,0xDB,0x8A,0xBE,0xA3,0x00,0x83,0xC2,0x06,0xC4,0x76,0x04,0x8B,0x7E,0x2C,0x83, +0xF9,0x08,0x72,0x2C,0xEC,0xA8,0x01,0x74,0x16,0x8A,0xE0,0x83,0xEA,0x0A,0xEC,0x83, +0xC2,0x0A,0x84,0xE7,0x75,0x51,0xAA,0xFE,0xC3,0x49,0x83,0xF9,0x08,0x73,0xE5,0x32, +0xFF,0x26,0x01,0x1C,0x01,0x5E,0x34,0x89,0x76,0x04,0x89,0x4E,0x2E,0x89,0x7E,0x2C, +0x3B,0x4E,0x3C,0x72,0x11,0xF6,0x46,0x38,0x20,0x74,0x01,0xC3,0x83,0x4E,0x38,0x20, +0xB0,0x00,0xE8,0xFD,0xFB,0xC3,0xF6,0x46,0x38,0x04,0x74,0x15,0x83,0x4E,0x38,0x10, +0x8A,0x86,0xA7,0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0x83,0xEA,0x02,0xEE,0x83,0xC2, +0x02,0x3D,0x40,0x00,0x72,0x5D,0xC3,0x32,0xFF,0x26,0x03,0x1C,0x85,0xDB,0x74,0x09, +0x26,0x89,0x1C,0x8B,0xF7,0x47,0x47,0x49,0x49,0x80,0xE4,0x1E,0x80,0xCC,0xC0,0x26, +0x89,0x04,0xF6,0xC4,0x10,0x74,0x27,0x8B,0x76,0x38,0xF7,0xC6,0x00,0x10,0x74,0x0B, +0x50,0xFE,0x86,0xB2,0x00,0xB0,0x0A,0xE8,0xA8,0xFB,0x58,0xF7,0xC6,0x00,0x01,0x74, +0x0D,0xE8,0x82,0x26,0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB,0x8B,0xF7, +0x33,0xC0,0xAB,0x32,0xDB,0x8A,0xBE,0xA3,0x00,0x49,0x49,0x83,0xF9,0x08,0x72,0x17, +0xE9,0x41,0xFF,0x81,0x4E,0x38,0x00,0x04,0x83,0xC2,0xF8,0x8A,0x86,0xA5,0x00,0x24, +0xFA,0x88,0x86,0xA5,0x00,0xEE,0xC3,0xE9,0x45,0xFF,0x83,0xC2,0x08,0xEC,0x88,0x86, +0xAA,0x00,0xC0,0xE8,0x04,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00,0x32,0xE0,0x8B, +0x5E,0x3E,0x84,0xE3,0x74,0x4F,0x8A,0xC1,0x8B,0x4E,0x26,0xF6,0xC5,0x04,0x74,0x0C, +0xA8,0x08,0x74,0x05,0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9,0x40,0xF6,0xC5,0x08,0x74, +0x0C,0xA8,0x02,0x74,0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80,0xC9,0x80,0x88,0x4E,0x26, +0x8B,0xF0,0x8A,0x86,0xA5,0x00,0x84,0xC9,0x74,0x08,0xA8,0x02,0x74,0x15,0x24,0xFD, +0xEB,0x06,0xA8,0x02,0x75,0x0D,0x0C,0x02,0x88,0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE, +0x83,0xC2,0x0A,0x8B,0xC6,0x84,0xE7,0x75,0x01,0xC3,0xC6,0x86,0xBA,0x00,0x01,0xB0, +0x0E,0xE8,0xEE,0xFA,0xF7,0x46,0x38,0x00,0x02,0x74,0xEE,0x83,0x7E,0x2E,0x06,0x72, +0xE8,0x8A,0xA6,0xAA,0x00,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0xB0,0xFF,0xAA,0xB0,0x02, +0xAB,0x26,0x83,0x07,0x03,0x83,0x6E,0x2E,0x03,0x89,0x7E,0x2C,0xF6,0x46,0x38,0x20, +0x74,0x01,0xC3,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xB6,0xFA,0xC3,0x90,0x83,0xEA, +0x08,0xE9,0xB4,0xFD,0x83,0xC2,0x06,0x8B,0x5E,0x26,0xF6,0xC3,0xC0,0x75,0xEF,0x8B, +0x4E,0x1C,0xEC,0x88,0x86,0xA4,0x00,0x83,0xEA,0x0A,0xA8,0x20,0x75,0x02,0x8A,0xCD, +0x32,0xED,0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x18,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46, +0x1A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20,0x00,0x72,0x30, +0xC3,0x85,0xC0,0x74,0x31,0x8B,0xC8,0x01,0x46,0x2A,0xC5,0x76,0x00,0xF3,0x6E,0x8E, +0xD9,0x80,0xCB,0x02,0x89,0x5E,0x26,0xE8,0x32,0xF1,0xF6,0xC7,0x01,0x75,0x16,0x83, +0xC2,0x02,0xE8,0x53,0xFD,0xF6,0xC7,0x10,0x75,0x0B,0xB0,0x02,0xE8,0x43,0xFA,0xC3, +0xF6,0xC7,0x01,0x74,0xF0,0xC3,0x80,0xCB,0x02,0x89,0x5E,0x26,0xF6,0xC7,0x01,0x74, +0xDE,0x83,0xC2,0x02,0xE8,0x31,0xFD,0xF6,0x86,0xA4,0x00,0x40,0x74,0x0B,0x80,0xE7, +0xFE,0x80,0xCF,0x02,0x89,0x5E,0x26,0xEB,0xCC,0xB0,0x04,0xE8,0x14,0xFA,0xC3,0xC0, +0xC2,0xC8,0xCA,0xC4,0xC6,0xCC,0xCE,0xD0,0xD2,0xD8,0xDA,0xD4,0xD6,0xDC,0xDE,0x90, +0xE9,0x0E,0x01,0xE4,0xC4,0x8A,0xE0,0xE4,0xC4,0x8B,0xD0,0x83,0xF9,0x08,0x72,0xF0, +0x26,0x83,0x3F,0x00,0x74,0x04,0x8B,0xDF,0x49,0x49,0x8B,0xFB,0x8A,0xDE,0x83,0xE3, +0x0F,0x2E,0x8A,0xA7,0x2F,0x16,0xAB,0xF6,0xC4,0x10,0x74,0x24,0xF7,0xC6,0x00,0x10, +0x74,0x0B,0x50,0xFE,0x86,0xB2,0x00,0xB0,0x0A,0xE8,0xC6,0xF9,0x58,0xF7,0xC6,0x00, +0x01,0x74,0x0D,0xE8,0xA0,0x24,0x8B,0x76,0x38,0x8B,0x4E,0x2E,0x8B,0x7E,0x04,0xAB, +0x89,0x7E,0x04,0x33,0xC0,0xAB,0x49,0x49,0x89,0x4E,0x2E,0x89,0x7E,0x2C,0x8B,0xC1, +0xEB,0x4E,0x90,0xEB,0x9E,0x90,0xE4,0xD6,0x84,0xC0,0x79,0x63,0xE6,0xD0,0x8A,0xC8, +0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00, +0x8B,0x4E,0x2E,0xC4,0x5E,0x04,0x8B,0x7E,0x2C,0x8B,0x76,0x38,0xE4,0x86,0x24,0x07, +0x3C,0x03,0x75,0xCF,0xE4,0x1C,0x91,0x3B,0xC1,0x73,0x02,0x8B,0xC8,0x2B,0xC1,0x89, +0x46,0x2E,0x01,0x4E,0x34,0x26,0x01,0x0F,0xBA,0xC4,0x00,0xF3,0x6C,0x89,0x7E,0x2C, +0x3B,0x46,0x3C,0x72,0x1C,0xF7,0xC6,0x20,0x00,0x75,0x0B,0x83,0xCE,0x20,0x89,0x76, +0x38,0xB0,0x00,0xE8,0x3C,0xF9,0x8A,0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD6,0xC3,0xF9, +0xC3,0xF7,0xC6,0x0A,0x00,0x74,0x35,0xF7,0xC6,0x10,0x00,0x75,0x2F,0x83,0xCE,0x10, +0x89,0x76,0x38,0xF7,0xC6,0x02,0x00,0x74,0x0E,0x50,0xE4,0xD8,0x24,0xFE,0xE6,0xD8, +0x58,0xF7,0xC6,0x08,0x00,0x74,0x15,0x50,0x51,0xB9,0xE8,0x03,0xE4,0x0A,0x84,0xC0, +0xE0,0xFA,0x84,0xC0,0x75,0x04,0xB0,0x24,0xE6,0x0A,0x59,0x58,0x3D,0x40,0x00,0x73, +0xB5,0x8A,0x86,0xA5,0x00,0x24,0xEF,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0xCE,0x10, +0x04,0x89,0x76,0x38,0xEB,0xA0,0x00,0x08,0x04,0x0C,0x01,0x09,0x05,0x0D,0x02,0x0A, +0x06,0x0E,0x03,0x0B,0x07,0x0F,0x00,0x40,0x80,0xC0,0x20,0x60,0xA0,0xE0,0x10,0x50, +0x90,0xD0,0x30,0x70,0xB0,0xF0,0xE4,0xD2,0xE6,0xD0,0x8A,0xC8,0x25,0x03,0x00,0x03, +0xD8,0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0x88,0x8E,0xAE,0x00,0xE4,0xD8,0xC0,0xE8, +0x04,0x8B,0xD8,0x2E,0x8A,0x87,0x66,0x17,0x8A,0xE0,0x8A,0xC8,0x86,0x86,0xA9,0x00, +0x32,0xE0,0xE4,0x98,0x8B,0x5E,0x3E,0x84,0xE3,0x74,0x54,0x8A,0xC1,0x8B,0x4E,0x26, +0xF6,0xC5,0x04,0x74,0x0C,0xA8,0x08,0x74,0x05,0x80,0xE1,0xBF,0xEB,0x03,0x80,0xC9, +0x40,0xF6,0xC5,0x08,0x74,0x0C,0xA8,0x02,0x74,0x05,0x80,0xE1,0x7F,0xEB,0x03,0x80, +0xC9,0x80,0x88,0x4E,0x26,0x8B,0xF0,0x8A,0x86,0xA5,0x00,0xF6,0xC1,0xFD,0x74,0x08, +0xA8,0x06,0x74,0x19,0x24,0xF9,0xEB,0x0F,0xA8,0x06,0x75,0x11,0xF6,0xC5,0x01,0x75, +0x04,0x0C,0x04,0xEB,0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x8B,0xC6,0x84, +0xE7,0x75,0x09,0x8A,0x86,0xAE,0x00,0x24,0x3F,0xE6,0xD2,0xC3,0xC6,0x86,0xBA,0x00, +0x01,0xB0,0x0E,0xE8,0x1C,0xF8,0xF7,0x46,0x38,0x00,0x02,0x74,0xE6,0x83,0x7E,0x2E, +0x06,0x72,0xE0,0x8A,0x86,0xA9,0x00,0x8A,0xE0,0x86,0x86,0xAA,0x00,0x8A,0xC8,0x32, +0xC4,0x80,0xC9,0x0B,0x22,0xC1,0xC0,0xE4,0x04,0x0A,0xE0,0xC4,0x5E,0x04,0x8B,0x7E, +0x2C,0xB0,0xFF,0xAA,0xB0,0x02,0xAB,0x26,0x83,0x07,0x03,0x83,0x6E,0x2E,0x03,0x89, +0x7E,0x2C,0xF6,0x46,0x38,0x20,0x75,0xAB,0x83,0x4E,0x38,0x20,0xB0,0x00,0xE8,0xD1, +0xF7,0xEB,0xA0,0x90,0xE4,0x12,0x24,0xDF,0xE6,0x12,0x81,0xE3,0xFE,0x9F,0x89,0x5E, +0x26,0x83,0x66,0x48,0xF7,0xEB,0x73,0x90,0xF6,0xC7,0x20,0x75,0xE7,0xE4,0x12,0x0C, +0x20,0xE6,0x12,0x32,0xC0,0xE6,0xC6,0xB0,0x83,0xE6,0xC6,0x80,0xCF,0x20,0x89,0x5E, +0x26,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xEB,0x74,0x90, +0xF6,0xC7,0x40,0x75,0xD3,0xE4,0x12,0x0C,0x20,0xE6,0x12,0x32,0xC0,0xE6,0xC6,0xB0, +0x81,0xE6,0xC6,0x80,0xE7,0xDF,0x80,0xCB,0x01,0x89,0x5E,0x26,0xB0,0x06,0xE8,0x71, +0xF7,0x90,0x8A,0x86,0xA5,0x00,0x24,0xF9,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB,0x43, +0xE4,0xD4,0xE6,0xD0,0x8B,0xF8,0x25,0x03,0x00,0x03,0xD8,0xD1,0xE3,0x2E,0x8B,0xAF, +0x44,0x00,0x8B,0x5E,0x26,0xF6,0xC7,0x60,0x75,0xB6,0xF6,0xC3,0xC0,0x75,0xD3,0xBA, +0xC6,0x00,0x8B,0x4E,0x1C,0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x1E,0x01,0x4E,0x2A,0x2B, +0xC1,0x89,0x46,0x1A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x89,0x76,0x00,0x3D,0x20, +0x00,0x72,0x3D,0x8B,0xC7,0x24,0x3F,0xE6,0xD4,0xC3,0x85,0xC0,0x74,0x39,0x8B,0xC8, +0x01,0x46,0x2A,0xC5,0x76,0x00,0xF3,0x6E,0x8E,0xD9,0x83,0xCB,0x02,0x89,0x5E,0x26, +0xE8,0xD9,0xED,0xF6,0xC7,0x01,0x75,0x39,0x8A,0x86,0xA5,0x00,0x24,0xF9,0xE6,0x0C, +0x88,0x86,0xA5,0x00,0xF6,0xC7,0x10,0x75,0xCA,0xB0,0x02,0xE8,0xE4,0xF6,0xEB,0xC3, +0xF6,0xC7,0x01,0x74,0xEF,0xEB,0xBC,0xF6,0xC7,0x01,0x74,0xDC,0x8A,0x86,0xA5,0x00, +0xA8,0x02,0x74,0x11,0x81,0xE3,0xFF,0xFE,0x81,0xCB,0x00,0x02,0x89,0x5E,0x26,0xEB, +0xC7,0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0xE6,0x0C,0x88,0x86,0xA5,0x00,0xEB, +0x92,0x90,0xFD,0xF7,0xDF,0x7F,0xFE,0xFB,0xEF,0xBF,0x00,0x04,0x00,0x04,0x05,0x04, +0x05,0x04,0x01,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04, +0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04, +0x05,0x04,0x01,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04, +0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04, +0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04, +0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04, +0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04, +0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x03,0x04,0x00,0x04,0x05,0x04, +0x05,0x04,0x01,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04, +0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x02,0x04,0x00,0x04,0x05,0x04, +0x05,0x04,0x01,0x04,0x00,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04, +0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04, +0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04, +0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04, +0x05,0x04,0x07,0x04,0x07,0x04,0x05,0x04,0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04, +0x05,0x04,0x06,0x04,0x06,0x04,0x05,0x04,0x05,0x04,0x33,0xDB,0x8A,0xD8,0x8A,0x87, +0x6C,0x12,0xE6,0xFE,0xC1,0xE3,0x02,0xE4,0xCE,0xA8,0x04,0x75,0x09,0xA8,0x02,0x74, +0x03,0xE9,0x2C,0xFE,0xF9,0xC3,0x50,0x53,0xE8,0xCB,0xFC,0x5B,0x58,0xA8,0x02,0x74, +0x03,0xE9,0x1C,0xFE,0xF8,0xC3,0x33,0xDB,0x8A,0xD8,0x8A,0x87,0x6C,0x12,0xE6,0xFE, +0xC1,0xE3,0x02,0xE9,0xD0,0xFB,0x9A,0x1A,0xC6,0x1A,0x00,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0E,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0C,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x0A,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x08,0x00,0x02,0x00,0x04,0x00, +0x02,0x00,0x06,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0xC3,0x90,0xDA,0x14,0x94,0x15, +0x5C,0x13,0xE6,0x13,0xDA,0x1B,0xDA,0x1B,0xE6,0x13,0xDA,0x1B,0x8B,0x94,0x64,0x12, +0xC1,0xE6,0x04,0xA8,0x01,0x74,0x35,0x50,0x33,0xC0,0x8A,0xC2,0xE6,0xFE,0xE4,0xA0, +0x85,0xC0,0x74,0x27,0x8B,0xD8,0x2E,0x8A,0x9F,0xDA,0x1A,0x52,0x56,0x2E,0x8B,0xA8, +0x44,0x00,0x8B,0x56,0x28,0xEC,0xA8,0x01,0x75,0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E, +0x8A,0xD8,0x2E,0xFF,0x97,0xDC,0x1B,0x5E,0x5A,0xEB,0xCD,0x58,0xA8,0x02,0x74,0x36, +0x83,0xC6,0x10,0x33,0xC0,0x8A,0xC6,0xE6,0xFE,0xE4,0xA0,0x85,0xC0,0x74,0x27,0x8B, +0xD8,0x2E,0x8A,0x9F,0xDA,0x1A,0x52,0x56,0x2E,0x8B,0xA8,0x44,0x00,0x8B,0x56,0x28, +0xEC,0xA8,0x01,0x75,0x0D,0x88,0x86,0xAD,0x00,0x24,0x0E,0x8A,0xD8,0x2E,0xFF,0x97, +0xDC,0x1B,0x5E,0x5A,0xEB,0xCD,0xC3,0x90,0x32,0xE4,0x8B,0xD8,0x8B,0xD0,0x2E,0x8A, +0x9F,0x9A,0x19,0x2E,0x22,0x97,0x92,0x19,0x56,0x52,0x8A,0xC3,0x24,0x03,0x03,0xC6, +0x80,0xE3,0x04,0xD0,0xEB,0x2E,0xFF,0x97,0xD6,0x1A,0x58,0x5E,0xA9,0x55,0x00,0x75, +0xD9,0xC3,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00, +0x22,0xC4,0x74,0x08,0x33,0xF6,0xE8,0xBF,0xFF,0xEB,0xEE,0x90,0xE4,0x04,0x07,0xE4, +0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B, +0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x08,0xBE,0x04, +0x00,0xE8,0x94,0xFF,0xEB,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA, +0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12, +0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x6B,0xFF,0xA1,0x60,0x12, +0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0xE5,0xBE,0x08,0x00,0xE8,0x5A,0xFF,0xEB,0xDD, +0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04, +0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF, +0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE, +0xE4,0x00,0x22,0xC4,0x74,0x19,0xBE,0x04,0x00,0xE8,0x1C,0xFF,0xA1,0x62,0x12,0xE6, +0xFE,0xE4,0x00,0x22,0xC4,0x74,0xE4,0xBE,0x0C,0x00,0xE8,0x0B,0xFF,0xEB,0xDC,0xA1, +0x62,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0xA1, +0x5E,0x12,0xE6,0xFE,0xE4,0x04,0x1F,0xE4,0x04,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF, +0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80, +0x84,0xC4,0x74,0x08,0x33,0xF6,0xE8,0x53,0xFE,0xEB,0xEE,0x90,0xB8,0x00,0x80,0xBA, +0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1, +0x5E,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x02,0x00,0xE8,0x2C,0xFE, +0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E, +0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08, +0xBE,0x04,0x00,0xE8,0x06,0xFE,0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07, +0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x62,0x12,0xE6,0xFE, +0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x06,0x00,0xE8,0xE0,0xFD,0xEB,0xED,0xB8,0x00, 0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E, -0xD8,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x08,0xBE,0x04,0x00,0xE8, -0x06,0xFE,0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90, -0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4, -0x74,0x08,0xBE,0x06,0x00,0xE8,0xE0,0xFD,0xEB,0xED,0xB8,0x00,0x80,0xBA,0x22,0xFF, -0xEF,0x07,0x1F,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12, -0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x37,0xFE,0xA1,0x60,0x12, -0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,0xAA,0xFD,0xEB,0xDD, -0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,0x5C,0x12,0xE6,0xFE, -0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90, -0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4, -0x74,0x19,0xBE,0x04,0x00,0xE8,0xEC,0xFD,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84, -0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x5F,0xFD,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE, -0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x04,0x07,0xE4,0x04, -0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E, -0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x27, -0xFD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0xE5,0xBE,0x08,0x00,0xE8, -0x92,0xFD,0xEB,0xDD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4, +0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x37, +0xFE,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8, +0xAA,0xFD,0xEB,0xDD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1, +0x5C,0x12,0xE6,0xFE,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF, +0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE, +0xE4,0x00,0x22,0xC4,0x74,0x19,0xBE,0x04,0x00,0xE8,0xEC,0xFD,0xA1,0x62,0x12,0xE6, +0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x5F,0xFD,0xEB,0xDC,0xA1, +0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0xA1,0x5E,0x12,0xE6,0xFE,0xE4, 0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E, -0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x19, -0xBE,0x02,0x00,0xE8,0xE2,0xFC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74, -0xE4,0xBE,0x0C,0x00,0xE8,0x4D,0xFD,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x00, -0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF, -0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE, -0xE4,0x80,0x84,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x9D,0xFC,0xA1,0x60,0x12,0xE6,0xFE, -0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,0x8C,0xFC,0xEB,0xDD,0xA1,0x60, -0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,0xB8,0x00,0x80,0xBA,0x22, -0xFF,0xEF,0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE, -0xE4,0x80,0x84,0xC4,0x74,0x19,0xBE,0x02,0x00,0xE8,0x5C,0xFC,0xA1,0x62,0x12,0xE6, -0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x4B,0xFC,0xEB,0xDC,0xA1, -0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,0xB8,0x00,0x80,0xBA, -0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0x90,0x2A,0xC0, -0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,0x14,0x33,0xDB,0xE8,0xD5,0xF6,0xEB,0xEF,0x90, -0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xF6,0x06,0x05,0x01, -0x01,0x75,0xED,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,0xE3,0xBB,0x04,0x00, -0xE8,0xAF,0xF6,0xEB,0xC9,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0x90,0xFB,0x90, -0xFA,0x2A,0xC0,0xE6,0xFE,0xE4,0xCE,0xA8,0x02,0x74,0x13,0x33,0xDB,0xE8,0xCC,0xF8, -0xEB,0xEC,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xA8,0x04, -0x74,0xF0,0x33,0xDB,0xE8,0x5B,0xF7,0xEB,0xD5,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E, -0xD8,0x90,0xFB,0x90,0xFA,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,0x02,0x74,0x15,0xBB, -0x04,0x00,0xE8,0x97,0xF8,0xEB,0xEB,0x90,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07, -0x1F,0x61,0xCF,0x90,0xA8,0x04,0x74,0xF0,0xBB,0x04,0x00,0xE8,0x24,0xF7,0xEB,0xD2, -0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x09,0x9C,0x0E,0xE8,0x6B,0xF2,0x90,0x6A,0x00, -0x1F,0xC6,0x06,0x93,0x12,0x29,0x9C,0x0E,0xE8,0x5D,0xF2,0x90,0x6E,0x20,0x6E,0x20, -0x6E,0x20,0xCA,0x1D,0x8E,0x1C,0xE2,0x1C,0x16,0x1E,0x6E,0x20,0x7E,0x1D,0xAA,0x1E, -0x34,0x1F,0x6E,0x20,0x7E,0x1D,0x6E,0x20,0x6E,0x20,0x34,0x1F,0x6E,0x20,0x6E,0x20, -0x6E,0x20,0xF0,0x1D,0xB8,0x1C,0x30,0x1D,0x60,0x1E,0x6E,0x20,0xA4,0x1D,0xEE,0x1E, -0x74,0x1F,0x6E,0x20,0xA4,0x1D,0x6E,0x20,0x6E,0x20,0x74,0x1F,0xFC,0xB9,0x40,0x00, -0x8C,0xCB,0xB8,0x60,0x20,0x2B,0xFF,0xAB,0x93,0xAB,0x93,0xE2,0xFA,0xC7,0x06,0x4C, -0x00,0xA4,0x11,0x83,0x3E,0x44,0x12,0x00,0x75,0x20,0xC7,0x06,0x3C,0x00,0xEA,0x4A, -0xC7,0x06,0x30,0x00,0xB6,0x1F,0xC7,0x06,0x34,0x00,0xF6,0x1F,0xF6,0x06,0x05,0x01, -0x01,0x75,0x06,0xC7,0x06,0x38,0x00,0x2A,0x20,0xC3,0xC7,0x06,0x3C,0x00,0x38,0x4B, -0x33,0xDB,0x8A,0x1E,0x54,0x12,0xC1,0xE3,0x02,0x02,0x1E,0x56,0x12,0x2E,0x8B,0x87, -0x7C,0x20,0xA3,0x30,0x00,0x8A,0x1E,0x55,0x12,0xC1,0xE3,0x02,0x02,0x1E,0x57,0x12, -0x2E,0x8B,0x87,0x9C,0x20,0xA3,0x34,0x00,0xC3,0x8B,0x86,0x9E,0x00,0xE6,0xFE,0x86, -0xC4,0xE6,0xD0,0xC3,0x8B,0x86,0x9E,0x00,0xE6,0xFE,0x33,0xD2,0x8A,0xD4,0xC3,0x51, -0xB9,0x10,0x27,0xE4,0x0A,0x90,0x90,0x84,0xC0,0x74,0x05,0xE2,0xF6,0x59,0xF9,0xC3, -0x59,0xF8,0xC3,0x84,0xC0,0x78,0x1E,0x51,0x8A,0xE8,0x8A,0xC8,0xB8,0x01,0x00,0xD3, -0xE0,0x09,0x86,0x98,0x00,0x3A,0xAE,0xA0,0x00,0x59,0x75,0x10,0xE8,0xA9,0xE5,0x83, -0x4E,0x26,0x02,0xF9,0xC3,0x98,0x89,0x86,0x98,0x00,0xEB,0xF0,0xF8,0xC3,0x84,0xC0, -0x78,0x12,0x51,0x8A,0xE0,0x8A,0xC8,0xB8,0x01,0x00,0xD3,0xE0,0x59,0xF7,0xD0,0x21, -0x86,0x98,0x00,0xC3,0xC7,0x86,0x98,0x00,0x00,0x00,0xC3,0x83,0xC2,0x04,0x8A,0x86, -0xA6,0x00,0x0C,0x04,0xEE,0x83,0xEA,0x04,0xC3,0xE8,0x93,0xFF,0x72,0x04,0xB0,0x82, -0xE6,0x0A,0xC3,0x8B,0x46,0x26,0xA8,0xFD,0x74,0x11,0x8A,0x86,0xA5,0x00,0xA8,0x06, -0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xF6,0xC4,0x01,0x74,0x0A, -0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0xEB,0x0C,0xA8,0x02,0x75,0x0F,0x8A,0x86, -0xA5,0x00,0x24,0xFD,0x0C,0x04,0x3A,0x86,0xA5,0x00,0x75,0xD8,0xC3,0x8A,0x86,0xA5, -0x00,0xEB,0xCF,0xE4,0xD8,0x33,0xDB,0x8A,0xD8,0xC0,0xEB,0x04,0x2E,0x8A,0x9F,0x62, -0x17,0x88,0x9E,0xA9,0x00,0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,0xC7,0x04,0x74,0x07, -0xA8,0x10,0x75,0x03,0x80,0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,0xA8,0x80,0x75,0x03, -0x80,0xCB,0x40,0x88,0x5E,0x26,0x8A,0x86,0xA5,0x00,0xF6,0xC3,0xFD,0x74,0x0D,0xA8, -0x06,0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xF6,0xC7,0x01,0x74, -0x04,0x0C,0x02,0xEB,0xF0,0xF6,0xC3,0x02,0x75,0xE9,0x0C,0x04,0xEB,0xE7,0xC4,0x04, -0xC4,0x04,0x85,0x04,0x59,0x04,0x48,0x04,0x41,0x04,0xC3,0x03,0x82,0x03,0x41,0x03, -0x82,0x02,0x57,0x02,0x41,0x02,0x82,0x01,0x41,0x01,0x82,0x00,0x41,0x00,0x4E,0x02, -0xAD,0x01,0x57,0x01,0x2D,0x00,0x2B,0x00,0x27,0x00,0x21,0x00,0x16,0x00,0xF4,0x04, -0xF4,0x04,0xA3,0x04,0x6F,0x04,0x5B,0x04,0x51,0x04,0xF4,0x03,0xA3,0x03,0x51,0x03, -0xA3,0x02,0x6D,0x02,0x51,0x02,0xA3,0x01,0x51,0x01,0xA3,0x00,0x51,0x00,0x62,0x02, -0xD9,0x01,0x6D,0x01,0x38,0x00,0x36,0x00,0x31,0x00,0x29,0x00,0x1B,0x00,0x51,0x57, -0xBF,0x02,0x00,0xEB,0x0F,0x90,0x51,0x56,0xBF,0x01,0x00,0xEB,0x07,0x90,0x51,0x56, -0xBF,0x03,0x00,0x90,0x3C,0x19,0x76,0x02,0xB0,0x17,0x98,0x8B,0xF0,0x8A,0x82,0xC4, -0x00,0x2A,0xE4,0x8B,0xF0,0x83,0xFE,0x18,0x73,0x46,0xD1,0xE6,0x2E,0x8B,0x8C,0x4E, -0x22,0xF7,0x46,0x38,0x80,0x00,0x74,0x05,0x2E,0x8B,0x8C,0x7E,0x22,0xF7,0xC7,0x02, -0x00,0x74,0x12,0x3B,0x8E,0x94,0x00,0x74,0x0C,0x89,0x8E,0x94,0x00,0x8A,0xC5,0xE6, -0xEC,0x8A,0xC1,0xE6,0xE4,0xF7,0xC7,0x01,0x00,0x74,0x12,0x3B,0x8E,0x96,0x00,0x74, -0x0C,0x89,0x8E,0x96,0x00,0x8A,0xC5,0xE6,0xF8,0x8A,0xC1,0xE6,0xF0,0x5E,0x59,0xC3, -0x77,0x06,0x8B,0x8E,0x8E,0x00,0xEB,0xC5,0x8B,0x8E,0x90,0x00,0xEB,0xBF,0xD5,0x03, -0xF6,0x00,0x3E,0x00,0x10,0x00,0x04,0x00,0xCA,0x04,0x33,0x01,0x4D,0x00,0x14,0x00, -0x05,0x00,0x01,0x03,0x05,0x07,0x09,0x00,0x01,0x02,0x03,0x04,0x80,0x84,0x1E,0x00, -0xA0,0x25,0x26,0x00,0x00,0x00,0x60,0x8B,0xF0,0x33,0xFF,0x2E,0xA1,0x4C,0x23,0x2E, -0x8B,0x16,0x4E,0x23,0xBB,0x2E,0x23,0xF7,0x46,0x38,0x80,0x00,0x74,0x0C,0x2E,0xA1, -0x50,0x23,0x2E,0x8B,0x16,0x52,0x23,0xBB,0x38,0x23,0xB9,0x05,0x00,0x2E,0x3B,0x31, -0x73,0x0A,0x47,0x47,0xE2,0xF7,0xB8,0xFF,0xFF,0xEB,0x1D,0x90,0xD1,0xEF,0x2E,0x8A, -0x8D,0x42,0x23,0x2A,0xED,0xD1,0xEA,0xD1,0xD8,0xE2,0xFA,0xF7,0xF6,0x05,0x02,0x00, -0xC1,0xE8,0x02,0x2E,0x8A,0xA5,0x47,0x23,0x2E,0xA3,0x54,0x23,0x61,0x2E,0xA1,0x54, -0x23,0xC3,0x08,0x00,0x20,0x00,0x80,0x00,0x00,0x02,0x60,0x09,0x08,0x00,0x20,0x00, -0x80,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00, -0x52,0x56,0x57,0x85,0xC0,0x74,0x05,0x3D,0x01,0x09,0x76,0x03,0xB8,0x01,0x09,0xBF, -0x5B,0x01,0xF7,0x46,0x38,0x80,0x00,0x74,0x03,0xBF,0xB2,0x01,0x33,0xF6,0x2E,0x3B, -0x84,0xB2,0x23,0x76,0x04,0x46,0x46,0xEB,0xF5,0xF7,0xE7,0x2E,0x8B,0xBC,0xBC,0x23, -0x03,0xC7,0x83,0xD2,0x00,0xD1,0xE7,0xF7,0xF7,0x2E,0x8A,0xA4,0xC6,0x23,0x5F,0x5E, -0x5A,0xC3,0xE4,0x3E,0x80,0xBE,0xC3,0x00,0x03,0x75,0x0C,0xF7,0x46,0x7A,0x20,0x00, -0x74,0x05,0x0C,0x80,0xE6,0x3E,0xC3,0x24,0x7F,0xE6,0x3E,0xC3,0x24,0x03,0x88,0x86, -0xC3,0x00,0x8A,0xE0,0xE4,0x10,0x24,0xFC,0x0A,0xC4,0xE6,0x10,0x80,0x8E,0xA1,0x00, -0x42,0xE8,0xCE,0xFF,0xC3,0x90,0x56,0x8B,0xF0,0x83,0xE6,0x07,0xD1,0xE6,0x2E,0xFF, -0xA4,0x54,0x24,0x90,0x64,0x24,0x68,0x24,0x6C,0x24,0x70,0x24,0x74,0x24,0x83,0x24, -0x83,0x24,0x83,0x24,0xB4,0x00,0xEB,0x0E,0xB4,0xC0,0xEB,0x0A,0xB4,0x40,0xEB,0x06, -0xB4,0x20,0xEB,0x02,0xB4,0xA0,0xE4,0x10,0x24,0x1F,0x0A,0xC4,0xE6,0x10,0x80,0x8E, -0xA1,0x00,0x42,0x5E,0xC3,0x90,0x3C,0x02,0x77,0x12,0x8A,0xE0,0xE4,0x10,0x24,0xF3, -0xC0,0xE4,0x02,0x0A,0xC4,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0xC3,0x90,0x8B,0x5E, -0x38,0x84,0xC0,0x74,0x1F,0x3C,0x02,0x74,0x20,0x83,0xCB,0x08,0x8B,0x46,0x2E,0x3B, -0x46,0x3C,0x77,0x0C,0xE8,0x88,0xFC,0x72,0x07,0xB0,0x24,0xE6,0x0A,0x83,0xCB,0x10, -0x89,0x5E,0x38,0xC3,0x83,0xE3,0xF7,0xEB,0xF7,0xF7,0xC3,0x10,0x00,0x74,0xF5,0xE8, -0x6D,0xFC,0x72,0xEC,0x8A,0x86,0xC0,0x00,0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xEB,0xE0, -0x8B,0x5E,0x38,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0xE4,0xD8,0x77,0x0B,0x24,0xFE,0x80, -0xCB,0x12,0xE6,0xD8,0x89,0x5E,0x38,0xC3,0x0C,0x01,0x80,0xCB,0x02,0xEB,0xF3,0x50, -0x33,0xDB,0xC1,0xE8,0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,0x87,0x62,0x17,0x8A, -0xDC,0x2E,0x8A,0xA7,0x62,0x17,0x09,0x46,0x3E,0x58,0xC3,0x50,0x33,0xDB,0xC1,0xE8, -0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,0x87,0x62,0x17,0x8A,0xDC,0x2E,0x8A,0xA7, -0x62,0x17,0xF7,0xD0,0x21,0x46,0x3E,0x58,0xC3,0x8B,0x46,0x3E,0x33,0xDB,0x8A,0xD8, -0x0A,0xDC,0x2E,0x8A,0x87,0x72,0x17,0xE6,0x2C,0x8A,0xE0,0xE4,0x2A,0x24,0x0F,0x0A, -0xC4,0xE6,0x2A,0x8A,0x86,0xA5,0x00,0x84,0xE4,0x75,0x0D,0xA8,0x80,0x74,0x11,0x24, -0x7F,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x80,0x75,0x04,0x0C,0x80,0xEB,0xF1, -0xC3,0x1E,0x60,0x33,0xC9,0x33,0xD2,0x33,0xF6,0x8E,0xD9,0x8D,0xBE,0xFD,0x00,0x57, -0x8B,0x05,0x84,0xC0,0x74,0x16,0x8B,0xD1,0x42,0x8B,0xFE,0x4F,0x78,0x09,0x38,0xA3, -0xE4,0x00,0x74,0x08,0x4F,0x79,0xF7,0x88,0xA2,0xE4,0x00,0x46,0x5F,0x83,0xC7,0x09, -0x41,0x83,0xF9,0x10,0x72,0xD9,0x89,0xB6,0x86,0x00,0x89,0x96,0x84,0x00,0x61,0x1F, -0xC3,0x53,0xC7,0x46,0x66,0x00,0x00,0x8B,0x46,0x64,0xA9,0x40,0x00,0x74,0x0D,0xB3, -0x00,0xA9,0x80,0x00,0x74,0x02,0xB3,0x7F,0x88,0x9E,0xC1,0x00,0x32,0xDB,0xA9,0x02, -0x00,0x74,0x03,0x80,0xCB,0x40,0xA9,0x00,0x40,0x74,0x03,0x80,0xCB,0x02,0xA9,0x00, -0x80,0x74,0x03,0x80,0xCB,0x01,0xA9,0x30,0x1E,0x74,0x03,0x80,0xCB,0xBC,0xA9,0x00, -0x20,0x74,0x03,0x80,0xCB,0x08,0xA9,0x04,0x01,0x74,0x03,0x80,0xCB,0x10,0xA9,0x08, -0x00,0x74,0x03,0x80,0xCB,0x20,0x88,0x9E,0xC2,0x00,0x5B,0xC3,0x06,0x51,0x57,0x50, -0x16,0x07,0x8D,0xBE,0xC4,0x00,0xB9,0x1F,0x00,0x33,0xC0,0xAA,0x40,0xE2,0xFC,0x8B, -0x86,0x92,0x00,0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x58,0x5F,0x59,0x07,0xC3, -0xE4,0xD8,0xC0,0xE8,0x04,0x53,0x25,0x0F,0x00,0x8B,0xD8,0x2E,0x8A,0x87,0x62,0x17, -0x88,0x86,0xA9,0x00,0x5A,0xC3,0x08,0x86,0xAC,0x00,0xC6,0x86,0xBA,0x00,0x01,0xB0, -0x0E,0xE8,0xEA,0xE9,0xC3,0xAD,0x36,0xA3,0xB4,0x13,0xAD,0x36,0xA3,0xB6,0x13,0xAD, -0x36,0xA3,0xB8,0x13,0x83,0xE9,0x06,0x36,0xF7,0x06,0xB6,0x13,0x0F,0x00,0xC3,0x8A, -0x46,0x26,0xF7,0x46,0x48,0x80,0x00,0x74,0x02,0x0C,0x10,0x88,0x86,0xBD,0x00,0x32, -0xC0,0x83,0x7E,0x1A,0x00,0x75,0x0E,0x8B,0x5E,0x40,0x43,0x80,0xE3,0xFE,0x3B,0x5E, -0x08,0x75,0x02,0x0C,0x01,0x83,0x7E,0x3A,0x00,0x75,0x0D,0x1E,0xC5,0x5E,0x14,0x8B, -0x1F,0x1F,0x85,0xDB,0x75,0x02,0x0C,0x02,0xF7,0x46,0x38,0x10,0x00,0x74,0x02,0x0C, -0x04,0xF7,0x46,0x7A,0x02,0x00,0x74,0x02,0x0C,0x08,0x88,0x86,0xBF,0x00,0xC3,0x90, -0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x0D,0x9C,0x0E,0xE8,0x0B,0xEC,0x90,0xB0,0x02, -0xE6,0xDA,0xF8,0xC3,0x33,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x01,0xE6,0xD8,0xF8,0xC3, -0x33,0xC0,0xE6,0xD8,0xF8,0xC3,0xB0,0xFF,0xE8,0x68,0xFA,0xE8,0xBB,0xFA,0xF8,0xC3, -0xAC,0x49,0xE8,0xC9,0xFB,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x2F,0xFD,0xF8,0xC3,0x90, -0xAC,0x49,0xE8,0x81,0xFD,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x39,0xFD,0xF8,0xC3,0x90, -0xAC,0x49,0xE6,0x34,0xF8,0xC3,0xAC,0x49,0xE6,0x36,0xF8,0xC3,0xAC,0x49,0x3C,0x02, -0x77,0x1F,0x84,0xC0,0x75,0x1D,0xE4,0x14,0x24,0xEF,0xE6,0x14,0xE4,0x12,0x24,0x3F, -0xE6,0x12,0xE4,0x16,0xA8,0x04,0x74,0x09,0xE8,0x04,0xFA,0x72,0x04,0xB0,0x18,0xE6, -0x0A,0xF8,0xC3,0x8A,0xE0,0xE4,0x14,0x0C,0x10,0xE6,0x14,0xE4,0x12,0x0C,0xC0,0xF6, -0xC4,0x01,0x74,0x02,0x24,0x7F,0xE6,0x12,0xF8,0xC3,0xAC,0x49,0xE8,0x3F,0xFD,0xF8, -0xC3,0x90,0xB8,0x00,0x40,0xE8,0x97,0xFD,0xE8,0xCE,0xFD,0xE8,0xC2,0xFE,0xB0,0x01, -0xE8,0xD3,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x9F,0xFD,0xE8,0xBA,0xFD,0xF8, -0xC3,0x90,0xB8,0x00,0x10,0xE8,0x77,0xFD,0xE8,0xAE,0xFD,0xE8,0xA2,0xFE,0xB0,0x08, -0xE8,0xB3,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x7F,0xFD,0xE8,0x9A,0xFD,0xF8, -0xC3,0x90,0xB8,0x00,0x80,0xE8,0x57,0xFD,0xE8,0x8E,0xFD,0xE8,0x82,0xFE,0xB0,0x02, -0xE8,0x93,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x5F,0xFD,0xE8,0x7A,0xFD,0xF8, -0xC3,0x90,0xB8,0x00,0x20,0xE8,0x37,0xFD,0xE8,0x6E,0xFD,0xE8,0x62,0xFE,0xB0,0x04, -0xE8,0x73,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x3F,0xFD,0xE8,0x5A,0xFD,0xF8, -0xC3,0x90,0xAC,0x49,0xE8,0x48,0x14,0xE4,0x3C,0x24,0xE7,0x0A,0xC4,0xE6,0x3C,0xF8, -0xC3,0x90,0xB8,0xDE,0x3B,0x89,0x46,0x7C,0xE4,0x3C,0x0C,0x18,0xE6,0x3C,0xF8,0xC3, -0xE4,0x12,0x0C,0x02,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFD,0xEB,0xF6,0xE8,0xCF, -0xFC,0xF8,0xC3,0x90,0x83,0x66,0x38,0xFD,0xF8,0xC3,0xAC,0x49,0xA8,0x01,0x74,0x06, -0x83,0x4E,0x7A,0x20,0xEB,0x04,0x83,0x66,0x7A,0xDF,0xE8,0xE5,0xFB,0xF8,0xC3,0x90, +0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x18, +0x33,0xF6,0xE8,0x27,0xFD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x74,0xE5, +0xBE,0x08,0x00,0xE8,0x92,0xFD,0xEB,0xDD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x00,0x22, +0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF, +0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1,0x5E,0x12,0xE6,0xFE,0xE4,0x80, +0x84,0xC4,0x74,0x19,0xBE,0x02,0x00,0xE8,0xE2,0xFC,0xA1,0x62,0x12,0xE6,0xFE,0xE4, +0x00,0x22,0xC4,0x74,0xE4,0xBE,0x0C,0x00,0xE8,0x4D,0xFD,0xEB,0xDC,0xA1,0x62,0x12, +0xE6,0xFE,0xE4,0x00,0x22,0xC4,0x75,0xED,0xE4,0x04,0x07,0xE4,0x04,0x1F,0xB8,0x00, +0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1, +0x5C,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x18,0x33,0xF6,0xE8,0x9D,0xFC,0xA1, +0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE5,0xBE,0x04,0x00,0xE8,0x8C,0xFC, +0xEB,0xDD,0xA1,0x60,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F,0xB8, +0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x60,0x1E,0x06,0x2B,0xC0,0x8E,0xD8,0xA1, +0x5E,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0x19,0xBE,0x02,0x00,0xE8,0x5C,0xFC, +0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x74,0xE4,0xBE,0x06,0x00,0xE8,0x4B, +0xFC,0xEB,0xDC,0xA1,0x62,0x12,0xE6,0xFE,0xE4,0x80,0x84,0xC4,0x75,0xED,0x07,0x1F, +0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x61,0xCF,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E, +0xD8,0x90,0x2A,0xC0,0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74,0x14,0x33,0xDB,0xE8,0xD5, +0xF6,0xEB,0xEF,0x90,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90, +0xF6,0x06,0x05,0x01,0x01,0x75,0xED,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8,0x01,0x74, +0xE3,0xBB,0x04,0x00,0xE8,0xAF,0xF6,0xEB,0xC9,0x90,0x60,0x1E,0x06,0x2B,0xC0,0x8E, +0xD8,0x90,0xFB,0x90,0xFA,0x2A,0xC0,0xE6,0xFE,0xE4,0xCE,0xA8,0x02,0x74,0x13,0x33, +0xDB,0xE8,0xCC,0xF8,0xEB,0xEC,0xB8,0x00,0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61, +0xCF,0x90,0xA8,0x04,0x74,0xF0,0x33,0xDB,0xE8,0x5B,0xF7,0xEB,0xD5,0x90,0x60,0x1E, +0x06,0x2B,0xC0,0x8E,0xD8,0x90,0xFB,0x90,0xFA,0xB0,0x01,0xE6,0xFE,0xE4,0xCE,0xA8, +0x02,0x74,0x15,0xBB,0x04,0x00,0xE8,0x97,0xF8,0xEB,0xEB,0x90,0xB8,0x00,0x80,0xBA, +0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xA8,0x04,0x74,0xF0,0xBB,0x04,0x00,0xE8, +0x24,0xF7,0xEB,0xD2,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x09,0x9C,0x0E,0xE8,0x6B, +0xF2,0x90,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x29,0x9C,0x0E,0xE8,0x5D,0xF2,0x90, +0x72,0x20,0x72,0x20,0x72,0x20,0xCE,0x1D,0x92,0x1C,0xE6,0x1C,0x1A,0x1E,0x72,0x20, +0x82,0x1D,0xAE,0x1E,0x38,0x1F,0x72,0x20,0x82,0x1D,0x72,0x20,0x72,0x20,0x38,0x1F, +0x72,0x20,0x72,0x20,0x72,0x20,0xF4,0x1D,0xBC,0x1C,0x34,0x1D,0x64,0x1E,0x72,0x20, +0xA8,0x1D,0xF2,0x1E,0x78,0x1F,0x72,0x20,0xA8,0x1D,0x72,0x20,0x72,0x20,0x78,0x1F, +0xFC,0xB9,0x40,0x00,0x8C,0xCB,0xB8,0x64,0x20,0x2B,0xFF,0xAB,0x93,0xAB,0x93,0xE2, +0xFA,0xC7,0x06,0x4C,0x00,0xA8,0x11,0x83,0x3E,0x44,0x12,0x00,0x75,0x20,0xC7,0x06, +0x3C,0x00,0x08,0x4B,0xC7,0x06,0x30,0x00,0xBA,0x1F,0xC7,0x06,0x34,0x00,0xFA,0x1F, +0xF6,0x06,0x05,0x01,0x01,0x75,0x06,0xC7,0x06,0x38,0x00,0x2E,0x20,0xC3,0xC7,0x06, +0x3C,0x00,0x56,0x4B,0x33,0xDB,0x8A,0x1E,0x54,0x12,0xC1,0xE3,0x02,0x02,0x1E,0x56, +0x12,0x2E,0x8B,0x87,0x80,0x20,0xA3,0x30,0x00,0x8A,0x1E,0x55,0x12,0xC1,0xE3,0x02, +0x02,0x1E,0x57,0x12,0x2E,0x8B,0x87,0xA0,0x20,0xA3,0x34,0x00,0xC3,0x8B,0x86,0x9E, +0x00,0xE6,0xFE,0x86,0xC4,0xE6,0xD0,0xC3,0x8B,0x86,0x9E,0x00,0xE6,0xFE,0x33,0xD2, +0x8A,0xD4,0xC3,0x51,0xB9,0x10,0x27,0xE4,0x0A,0x90,0x90,0x84,0xC0,0x74,0x05,0xE2, +0xF6,0x59,0xF9,0xC3,0x59,0xF8,0xC3,0x84,0xC0,0x78,0x1E,0x51,0x8A,0xE8,0x8A,0xC8, +0xB8,0x01,0x00,0xD3,0xE0,0x09,0x86,0x98,0x00,0x3A,0xAE,0xA0,0x00,0x59,0x75,0x10, +0xE8,0xA9,0xE5,0x83,0x4E,0x26,0x02,0xF9,0xC3,0x98,0x89,0x86,0x98,0x00,0xEB,0xF0, +0xF8,0xC3,0x84,0xC0,0x78,0x12,0x51,0x8A,0xE0,0x8A,0xC8,0xB8,0x01,0x00,0xD3,0xE0, +0x59,0xF7,0xD0,0x21,0x86,0x98,0x00,0xC3,0xC7,0x86,0x98,0x00,0x00,0x00,0xC3,0x83, +0xC2,0x04,0x8A,0x86,0xA6,0x00,0x0C,0x04,0xEE,0x83,0xEA,0x04,0xC3,0xE8,0x93,0xFF, +0x72,0x04,0xB0,0x82,0xE6,0x0A,0xC3,0x8B,0x46,0x26,0xA8,0xFD,0x74,0x11,0x8A,0x86, +0xA5,0x00,0xA8,0x06,0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xF6, +0xC4,0x01,0x74,0x0A,0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0xEB,0x0C,0xA8,0x02, +0x75,0x0F,0x8A,0x86,0xA5,0x00,0x24,0xFD,0x0C,0x04,0x3A,0x86,0xA5,0x00,0x75,0xD8, +0xC3,0x8A,0x86,0xA5,0x00,0xEB,0xCF,0xE4,0xD8,0x33,0xDB,0x8A,0xD8,0xC0,0xEB,0x04, +0x2E,0x8A,0x9F,0x66,0x17,0x88,0x9E,0xA9,0x00,0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6, +0xC7,0x04,0x74,0x07,0xA8,0x10,0x75,0x03,0x80,0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07, +0xA8,0x80,0x75,0x03,0x80,0xCB,0x40,0x88,0x5E,0x26,0x8A,0x86,0xA5,0x00,0xF6,0xC3, +0xFD,0x74,0x0D,0xA8,0x06,0x74,0x08,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3, +0xF6,0xC7,0x01,0x74,0x04,0x0C,0x02,0xEB,0xF0,0xF6,0xC3,0x02,0x75,0xE9,0x0C,0x04, +0xEB,0xE7,0xC4,0x04,0xC4,0x04,0x85,0x04,0x59,0x04,0x48,0x04,0x41,0x04,0xC3,0x03, +0x82,0x03,0x41,0x03,0x82,0x02,0x57,0x02,0x41,0x02,0x82,0x01,0x41,0x01,0x82,0x00, +0x41,0x00,0x4E,0x02,0xAD,0x01,0x57,0x01,0x2D,0x00,0x2B,0x00,0x27,0x00,0x21,0x00, +0x16,0x00,0xF4,0x04,0xF4,0x04,0xA3,0x04,0x6F,0x04,0x5B,0x04,0x51,0x04,0xF4,0x03, +0xA3,0x03,0x51,0x03,0xA3,0x02,0x6D,0x02,0x51,0x02,0xA3,0x01,0x51,0x01,0xA3,0x00, +0x51,0x00,0x62,0x02,0xD9,0x01,0x6D,0x01,0x38,0x00,0x36,0x00,0x31,0x00,0x29,0x00, +0x1B,0x00,0x51,0x57,0xBF,0x02,0x00,0xEB,0x0F,0x90,0x51,0x56,0xBF,0x01,0x00,0xEB, +0x07,0x90,0x51,0x56,0xBF,0x03,0x00,0x90,0x3C,0x19,0x76,0x02,0xB0,0x17,0x98,0x8B, +0xF0,0x8A,0x82,0xC4,0x00,0x2A,0xE4,0x8B,0xF0,0x83,0xFE,0x18,0x73,0x46,0xD1,0xE6, +0x2E,0x8B,0x8C,0x52,0x22,0xF7,0x46,0x38,0x80,0x00,0x74,0x05,0x2E,0x8B,0x8C,0x82, +0x22,0xF7,0xC7,0x02,0x00,0x74,0x12,0x3B,0x8E,0x94,0x00,0x74,0x0C,0x89,0x8E,0x94, +0x00,0x8A,0xC5,0xE6,0xEC,0x8A,0xC1,0xE6,0xE4,0xF7,0xC7,0x01,0x00,0x74,0x12,0x3B, +0x8E,0x96,0x00,0x74,0x0C,0x89,0x8E,0x96,0x00,0x8A,0xC5,0xE6,0xF8,0x8A,0xC1,0xE6, +0xF0,0x5E,0x59,0xC3,0x77,0x06,0x8B,0x8E,0x8E,0x00,0xEB,0xC5,0x8B,0x8E,0x90,0x00, +0xEB,0xBF,0xD5,0x03,0xF6,0x00,0x3E,0x00,0x10,0x00,0x04,0x00,0xCA,0x04,0x33,0x01, +0x4D,0x00,0x14,0x00,0x05,0x00,0x01,0x03,0x05,0x07,0x09,0x00,0x01,0x02,0x03,0x04, +0x80,0x84,0x1E,0x00,0xA0,0x25,0x26,0x00,0x00,0x00,0x60,0x8B,0xF0,0x33,0xFF,0x2E, +0xA1,0x50,0x23,0x2E,0x8B,0x16,0x52,0x23,0xBB,0x32,0x23,0xF7,0x46,0x38,0x80,0x00, +0x74,0x0C,0x2E,0xA1,0x54,0x23,0x2E,0x8B,0x16,0x56,0x23,0xBB,0x3C,0x23,0xB9,0x05, +0x00,0x2E,0x3B,0x31,0x73,0x0A,0x47,0x47,0xE2,0xF7,0xB8,0xFF,0xFF,0xEB,0x1D,0x90, +0xD1,0xEF,0x2E,0x8A,0x8D,0x46,0x23,0x2A,0xED,0xD1,0xEA,0xD1,0xD8,0xE2,0xFA,0xF7, +0xF6,0x05,0x02,0x00,0xC1,0xE8,0x02,0x2E,0x8A,0xA5,0x4B,0x23,0x2E,0xA3,0x58,0x23, +0x61,0x2E,0xA1,0x58,0x23,0xC3,0x08,0x00,0x20,0x00,0x80,0x00,0x00,0x02,0x60,0x09, +0x08,0x00,0x20,0x00,0x80,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x01,0x00,0x02,0x00, +0x03,0x00,0x04,0x00,0x52,0x56,0x57,0x85,0xC0,0x74,0x05,0x3D,0x01,0x09,0x76,0x03, +0xB8,0x01,0x09,0xBF,0x5B,0x01,0xF7,0x46,0x38,0x80,0x00,0x74,0x03,0xBF,0xB2,0x01, +0x33,0xF6,0x2E,0x3B,0x84,0xB6,0x23,0x76,0x04,0x46,0x46,0xEB,0xF5,0xF7,0xE7,0x2E, +0x8B,0xBC,0xC0,0x23,0x03,0xC7,0x83,0xD2,0x00,0xD1,0xE7,0xF7,0xF7,0x2E,0x8A,0xA4, +0xCA,0x23,0x5F,0x5E,0x5A,0xC3,0xE4,0x3E,0x80,0xBE,0xC3,0x00,0x03,0x75,0x0C,0xF7, +0x46,0x7A,0x20,0x00,0x74,0x05,0x0C,0x80,0xE6,0x3E,0xC3,0x24,0x7F,0xE6,0x3E,0xC3, +0x24,0x03,0x88,0x86,0xC3,0x00,0x8A,0xE0,0xE4,0x10,0x24,0xFC,0x0A,0xC4,0xE6,0x10, +0x80,0x8E,0xA1,0x00,0x42,0xE8,0xCE,0xFF,0xC3,0x90,0x56,0x8B,0xF0,0x83,0xE6,0x07, +0xD1,0xE6,0x2E,0xFF,0xA4,0x58,0x24,0x90,0x68,0x24,0x6C,0x24,0x70,0x24,0x74,0x24, +0x78,0x24,0x87,0x24,0x87,0x24,0x87,0x24,0xB4,0x00,0xEB,0x0E,0xB4,0xC0,0xEB,0x0A, +0xB4,0x40,0xEB,0x06,0xB4,0x20,0xEB,0x02,0xB4,0xA0,0xE4,0x10,0x24,0x1F,0x0A,0xC4, +0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0x5E,0xC3,0x90,0x3C,0x02,0x77,0x12,0x8A,0xE0, +0xE4,0x10,0x24,0xF3,0xC0,0xE4,0x02,0x0A,0xC4,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42, +0xC3,0x90,0x8B,0x5E,0x38,0x84,0xC0,0x74,0x1F,0x3C,0x02,0x74,0x20,0x83,0xCB,0x08, +0x8B,0x46,0x2E,0x3B,0x46,0x3C,0x77,0x0C,0xE8,0x88,0xFC,0x72,0x07,0xB0,0x24,0xE6, +0x0A,0x83,0xCB,0x10,0x89,0x5E,0x38,0xC3,0x83,0xE3,0xF7,0xEB,0xF7,0xF7,0xC3,0x10, +0x00,0x74,0xF5,0xE8,0x6D,0xFC,0x72,0xEC,0x8A,0x86,0xC0,0x00,0xE6,0x38,0xB0,0x23, +0xE6,0x0A,0xEB,0xE0,0x8B,0x5E,0x38,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0xE4,0xD8,0x77, +0x0B,0x24,0xFE,0x80,0xCB,0x12,0xE6,0xD8,0x89,0x5E,0x38,0xC3,0x0C,0x01,0x80,0xCB, +0x02,0xEB,0xF3,0x50,0x33,0xDB,0xC1,0xE8,0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A, +0x87,0x66,0x17,0x8A,0xDC,0x2E,0x8A,0xA7,0x66,0x17,0x09,0x46,0x3E,0x58,0xC3,0x50, +0x33,0xDB,0xC1,0xE8,0x04,0x25,0x0F,0x0F,0x8A,0xD8,0x2E,0x8A,0x87,0x66,0x17,0x8A, +0xDC,0x2E,0x8A,0xA7,0x66,0x17,0xF7,0xD0,0x21,0x46,0x3E,0x58,0xC3,0x8B,0x46,0x3E, +0x33,0xDB,0x8A,0xD8,0x0A,0xDC,0x2E,0x8A,0x87,0x76,0x17,0xE6,0x2C,0x8A,0xE0,0xE4, +0x2A,0x24,0x0F,0x0A,0xC4,0xE6,0x2A,0x8A,0x86,0xA5,0x00,0x84,0xE4,0x75,0x0D,0xA8, +0x80,0x74,0x11,0x24,0x7F,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x80,0x75,0x04, +0x0C,0x80,0xEB,0xF1,0xC3,0x1E,0x60,0x33,0xC9,0x33,0xD2,0x33,0xF6,0x8E,0xD9,0x8D, +0xBE,0xFD,0x00,0x57,0x8B,0x05,0x84,0xC0,0x74,0x16,0x8B,0xD1,0x42,0x8B,0xFE,0x4F, +0x78,0x09,0x38,0xA3,0xE4,0x00,0x74,0x08,0x4F,0x79,0xF7,0x88,0xA2,0xE4,0x00,0x46, +0x5F,0x83,0xC7,0x09,0x41,0x83,0xF9,0x10,0x72,0xD9,0x89,0xB6,0x86,0x00,0x89,0x96, +0x84,0x00,0x61,0x1F,0xC3,0x53,0xC7,0x46,0x66,0x00,0x00,0x8B,0x46,0x64,0xA9,0x40, +0x00,0x74,0x0D,0xB3,0x00,0xA9,0x80,0x00,0x74,0x02,0xB3,0x7F,0x88,0x9E,0xC1,0x00, +0x32,0xDB,0xA9,0x02,0x00,0x74,0x03,0x80,0xCB,0x40,0xA9,0x00,0x40,0x74,0x03,0x80, +0xCB,0x02,0xA9,0x00,0x80,0x74,0x03,0x80,0xCB,0x01,0xA9,0x30,0x1E,0x74,0x03,0x80, +0xCB,0xBC,0xA9,0x00,0x20,0x74,0x03,0x80,0xCB,0x08,0xA9,0x04,0x01,0x74,0x03,0x80, +0xCB,0x10,0xA9,0x08,0x00,0x74,0x03,0x80,0xCB,0x20,0x88,0x9E,0xC2,0x00,0x5B,0xC3, +0x06,0x51,0x57,0x50,0x16,0x07,0x8D,0xBE,0xC4,0x00,0xB9,0x1F,0x00,0x33,0xC0,0xAA, +0x40,0xE2,0xFC,0x8B,0x86,0x92,0x00,0x89,0x86,0x8E,0x00,0x89,0x86,0x90,0x00,0x58, +0x5F,0x59,0x07,0xC3,0xE4,0xD8,0xC0,0xE8,0x04,0x53,0x25,0x0F,0x00,0x8B,0xD8,0x2E, +0x8A,0x87,0x66,0x17,0x88,0x86,0xA9,0x00,0x5A,0xC3,0x08,0x86,0xAC,0x00,0xC6,0x86, +0xBA,0x00,0x01,0xB0,0x0E,0xE8,0xEA,0xE9,0xC3,0xAD,0x36,0xA3,0xB4,0x13,0xAD,0x36, +0xA3,0xB6,0x13,0xAD,0x36,0xA3,0xB8,0x13,0x83,0xE9,0x06,0x36,0xF7,0x06,0xB6,0x13, +0x0F,0x00,0xC3,0x8A,0x46,0x26,0xF7,0x46,0x48,0x80,0x00,0x74,0x02,0x0C,0x10,0x88, +0x86,0xBD,0x00,0x32,0xC0,0x83,0x7E,0x1A,0x00,0x75,0x0E,0x8B,0x5E,0x40,0x43,0x80, +0xE3,0xFE,0x3B,0x5E,0x08,0x75,0x02,0x0C,0x01,0x83,0x7E,0x3A,0x00,0x75,0x0D,0x1E, +0xC5,0x5E,0x14,0x8B,0x1F,0x1F,0x85,0xDB,0x75,0x02,0x0C,0x02,0xF7,0x46,0x38,0x10, +0x00,0x74,0x02,0x0C,0x04,0x8B,0x5E,0x7A,0xF7,0xC3,0x02,0x00,0x74,0x02,0x0C,0x08, +0xF7,0xC3,0x04,0x00,0x74,0x02,0x0C,0x10,0xF7,0xC3,0x08,0x00,0x74,0x02,0x0C,0x20, +0xF7,0xC3,0x40,0x00,0x74,0x02,0x0C,0x40,0x88,0x86,0xBF,0x00,0xC3,0x90,0x6A,0x00, +0x1F,0xC6,0x06,0x93,0x12,0x0D,0x9C,0x0E,0xE8,0xF1,0xEB,0x90,0xB0,0x02,0xE6,0xDA, +0xF8,0xC3,0x33,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x01,0xE6,0xD8,0xF8,0xC3,0x33,0xC0, +0xE6,0xD8,0xF8,0xC3,0xB0,0xFF,0xE8,0x4E,0xFA,0xE8,0xA1,0xFA,0xF8,0xC3,0xAC,0x49, +0xE8,0xAF,0xFB,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x15,0xFD,0xF8,0xC3,0x90,0xAC,0x49, +0xE8,0x67,0xFD,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x1F,0xFD,0xF8,0xC3,0x90,0xAC,0x49, +0xE6,0x34,0xF8,0xC3,0xAC,0x49,0xE6,0x36,0xF8,0xC3,0xAC,0x49,0x3C,0x02,0x77,0x1F, +0x84,0xC0,0x75,0x1D,0xE4,0x14,0x24,0xEF,0xE6,0x14,0xE4,0x12,0x24,0x3F,0xE6,0x12, +0xE4,0x16,0xA8,0x04,0x74,0x09,0xE8,0xEA,0xF9,0x72,0x04,0xB0,0x18,0xE6,0x0A,0xF8, +0xC3,0x8A,0xE0,0xE4,0x14,0x0C,0x10,0xE6,0x14,0xE4,0x12,0x0C,0xC0,0xF6,0xC4,0x01, +0x74,0x02,0x24,0x7F,0xE6,0x12,0xF8,0xC3,0xAC,0x49,0xE8,0x25,0xFD,0xF8,0xC3,0x90, +0xB8,0x00,0x40,0xE8,0x7D,0xFD,0xE8,0xB4,0xFD,0xE8,0xA8,0xFE,0xB0,0x01,0xE8,0xB9, +0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x85,0xFD,0xE8,0xA0,0xFD,0xF8,0xC3,0x90, +0xB8,0x00,0x10,0xE8,0x5D,0xFD,0xE8,0x94,0xFD,0xE8,0x88,0xFE,0xB0,0x08,0xE8,0x99, +0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x65,0xFD,0xE8,0x80,0xFD,0xF8,0xC3,0x90, +0xB8,0x00,0x80,0xE8,0x3D,0xFD,0xE8,0x74,0xFD,0xE8,0x68,0xFE,0xB0,0x02,0xE8,0x79, +0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x45,0xFD,0xE8,0x60,0xFD,0xF8,0xC3,0x90, +0xB8,0x00,0x20,0xE8,0x1D,0xFD,0xE8,0x54,0xFD,0xE8,0x48,0xFE,0xB0,0x04,0xE8,0x59, +0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x25,0xFD,0xE8,0x40,0xFD,0xF8,0xC3,0x90, +0xAC,0x49,0xE8,0x48,0x14,0xE4,0x3C,0x24,0xE7,0x0A,0xC4,0xE6,0x3C,0xF8,0xC3,0x90, +0xB8,0xFC,0x3B,0x89,0x46,0x7C,0xE4,0x3C,0x0C,0x18,0xE6,0x3C,0xF8,0xC3,0xE4,0x12, +0x0C,0x02,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFD,0xEB,0xF6,0xE8,0xB5,0xFC,0xF8, +0xC3,0x90,0x83,0x66,0x38,0xFD,0xF8,0xC3,0xAC,0x49,0xA8,0x01,0x74,0x06,0x83,0x4E, +0x7A,0x20,0xEB,0x04,0x83,0x66,0x7A,0xDF,0xE8,0xCB,0xFB,0xF8,0xC3,0x90,0x8A,0x86, +0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0x4E,0x26,0x01, +0x20,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x48,0x08,0x49,0x46,0xF9,0xC3, 0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x81,0x4E, -0x26,0x01,0x20,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x48,0x08,0x49,0x46, -0xF9,0xC3,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C, -0x81,0x4E,0x26,0x01,0x20,0xAC,0xB4,0x0A,0xF6,0xE4,0xEB,0xD8,0xE8,0xFA,0x13,0xE4, -0x3C,0x24,0xF8,0x0A,0xC4,0xE6,0x3C,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89,0x46,0x64, -0xA9,0x01,0x00,0x74,0x1B,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x1A,0xA9,0x04,0x00,0x74, -0x0F,0xE4,0x3E,0x0C,0x02,0xE6,0x3E,0xB8,0x1A,0x44,0x89,0x46,0x62,0xF8,0xC3,0x90, -0xE4,0x3E,0x24,0xFC,0xEB,0xEF,0xE4,0x3E,0x24,0xFC,0xE6,0x3E,0xE8,0x02,0xFD,0xB8, -0x8C,0x40,0xEB,0xE6,0xE8,0x88,0xF8,0x72,0x05,0xB0,0x18,0xE6,0x0A,0xF8,0xC3,0x90, -0xAC,0x49,0xE8,0xE9,0xF9,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0xE9,0xF9,0xF8,0xC3,0x90, -0xE8,0x82,0xFD,0x75,0x06,0x32,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x02,0xE6,0xDA,0x36, -0xA0,0xB4,0x13,0x24,0x10,0x34,0x10,0xE8,0x16,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01, -0x00,0x74,0x05,0xE8,0xFC,0xFE,0xEB,0x0E,0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB, -0x02,0xB0,0x01,0xE8,0xDE,0xFE,0x36,0xA1,0xB4,0x13,0xE8,0xB5,0x13,0xE4,0x3C,0x24, -0xF8,0x0A,0xC4,0xE6,0x3C,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01,0x00,0xE8, -0xFA,0xFE,0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x73,0xFB,0x32,0xC0,0x36,0x8A,0x26, +0x26,0x01,0x20,0xAC,0xB4,0x0A,0xF6,0xE4,0xEB,0xD8,0xE8,0xFA,0x13,0xE4,0x3C,0x24, +0xF8,0x0A,0xC4,0xE6,0x3C,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89,0x46,0x64,0xA9,0x01, +0x00,0x74,0x1B,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x1A,0xA9,0x04,0x00,0x74,0x0F,0xE4, +0x3E,0x0C,0x02,0xE6,0x3E,0xB8,0x38,0x44,0x89,0x46,0x62,0xF8,0xC3,0x90,0xE4,0x3E, +0x24,0xFC,0xEB,0xEF,0xE4,0x3E,0x24,0xFC,0xE6,0x3E,0xE8,0xE8,0xFC,0xB8,0xAA,0x40, +0xEB,0xE6,0xE8,0x6E,0xF8,0x72,0x05,0xB0,0x18,0xE6,0x0A,0xF8,0xC3,0x90,0xAC,0x49, +0xE8,0xCF,0xF9,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0xCF,0xF9,0xF8,0xC3,0x90,0xE8,0x68, +0xFD,0x75,0x06,0x32,0xC0,0xE6,0xDA,0xF8,0xC3,0xB0,0x02,0xE6,0xDA,0x36,0xA0,0xB4, +0x13,0x24,0x10,0x34,0x10,0xE8,0x16,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01,0x00,0x74, +0x05,0xE8,0xFC,0xFE,0xEB,0x0E,0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB,0x02,0xB0, +0x01,0xE8,0xDE,0xFE,0x36,0xA1,0xB4,0x13,0xE8,0xB5,0x13,0xE4,0x3C,0x24,0xF8,0x0A, +0xC4,0xE6,0x3C,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01,0x00,0xE8,0xFA,0xFE, +0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x59,0xFB,0x32,0xC0,0x36,0x8A,0x26,0xB5,0x13, +0xF6,0xC4,0x04,0x74,0x09,0xFE,0xC0,0xF6,0xC4,0x08,0x74,0x02,0xFE,0xC0,0xE8,0xDB, +0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x57,0xF9,0x36,0xA1,0xB6,0x13,0xC1, +0xE8,0x04,0x25,0x03,0x00,0xE8,0xB8,0xFA,0x36,0xA1,0xB6,0x13,0xC1,0xE8,0x05,0x25, +0x02,0x00,0xE8,0x05,0xFB,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01,0x75,0x04,0x32,0xC0, +0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8,0xAC,0xFA,0x36,0xF6, +0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x83,0xFE,0xEB,0x03,0xE8,0x84,0xFE,0x36,0xF6, +0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x65,0xFE,0xEB,0x03,0xE8,0x68,0xFE,0xF8,0xC3, +0xE4,0x12,0x0C,0x01,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFE,0xEB,0xF6,0xE4,0x14, +0x24,0xF0,0x0C,0x05,0xE6,0x14,0xE4,0x2A,0x24,0xF0,0x0C,0x06,0xE6,0x2A,0xF8,0xC3, +0xE4,0x2A,0x24,0xF0,0xE6,0x2A,0xE4,0x14,0x24,0xF0,0x0C,0x07,0xE6,0x14,0xF8,0xC3, +0xAD,0x49,0x49,0xE8,0x64,0xF9,0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49,0x49,0xE8, +0x58,0xF9,0x89,0x86,0x90,0x00,0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0xA8,0xF7,0xF8, +0xC3,0x90,0x83,0x66,0x26,0xFB,0xE8,0x9E,0xF7,0xF8,0xC3,0x90,0xAC,0x49,0x84,0xC0, +0x75,0x0D,0xE4,0x10,0x24,0xEF,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0xF8,0xC3,0xE4, +0x10,0x0C,0x10,0xEB,0xF1,0x90,0xAC,0x49,0x3C,0x02,0x76,0x02,0x32,0xC0,0xC0,0xE0, +0x04,0xA8,0x20,0x74,0x02,0x0C,0x08,0x24,0x18,0x8A,0xE0,0xE4,0x12,0x24,0xE7,0x0A, +0xC4,0xE6,0x12,0x80,0x8E,0xA1,0x00,0x44,0xF8,0xC3,0xAC,0x49,0x88,0x86,0xC0,0x00, +0xF8,0xC3,0xAC,0x49,0xE6,0x3A,0xF8,0xC3,0xAC,0x49,0x84,0xC0,0x74,0x08,0xE4,0x12, +0x0C,0x04,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFB,0xEB,0xF6,0xAC,0x49,0xE8,0xD6, +0xF6,0x73,0x03,0xE8,0x27,0xF7,0xF8,0xC3,0xE4,0x12,0xA8,0x02,0x74,0x04,0x24,0xFD, +0xE6,0x12,0xB8,0xF0,0x00,0xE8,0x87,0xFA,0x81,0x66,0x26,0xFF,0xF3,0xE8,0x57,0xF7, +0xE8,0x9A,0xFA,0xF8,0xC3,0x90,0xB8,0x80,0x00,0xE8,0x57,0xFA,0x80,0x4E,0x27,0x08, +0xE8,0x44,0xF7,0xE8,0x87,0xFA,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x61,0xFA,0x81,0x66, +0x26,0xFF,0xF7,0xE8,0x31,0xF7,0xE8,0x74,0xFA,0xF8,0xC3,0x90,0xB8,0x10,0x00,0xE8, +0x31,0xFA,0x80,0x4E,0x27,0x04,0xE8,0x1E,0xF7,0xE8,0x61,0xFA,0xF8,0xC3,0xB8,0x10, +0x00,0xE8,0x3B,0xFA,0x81,0x66,0x26,0xFF,0xFB,0xE8,0x0B,0xF7,0xE8,0x4E,0xFA,0xF8, +0xC3,0x90,0x33,0xC0,0xAC,0x49,0x3C,0x01,0x73,0x04,0xB0,0x01,0xEB,0x06,0x3C,0x0C, +0x76,0x02,0xB0,0x0C,0x89,0x46,0x1C,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00,0x20,0x8A, +0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x83,0x4E,0x26, +0x01,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88, +0x86,0xA5,0x00,0xE6,0x0C,0xF8,0xC3,0x90,0xAC,0x49,0x50,0xE8,0x05,0xF6,0x58,0x72, +0x08,0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xF8,0xC3,0xF9,0xC3,0x90,0xAC,0x50,0xAD,0xE8, +0x82,0xF8,0x5A,0xF6,0xC2,0x01,0x74,0x12,0x39,0x86,0x96,0x00,0x74,0x0C,0x89,0x86, +0x96,0x00,0xE6,0xF0,0x86,0xE0,0xE6,0xF8,0x86,0xE0,0xF6,0xC2,0x02,0x74,0x10,0x39, +0x86,0x94,0x00,0x74,0x0A,0x89,0x86,0x94,0x00,0xE6,0xE4,0x86,0xE0,0xE6,0xEC,0x83, +0xE9,0x03,0xC3,0x90,0xE4,0x16,0x88,0x86,0xBC,0x00,0xE8,0xE6,0xFA,0x33,0xDB,0xE4, +0x0C,0xA8,0x06,0x74,0x03,0x80,0xCB,0x01,0xA8,0x10,0x74,0x03,0x80,0xCB,0x02,0xA8, +0x80,0x74,0x03,0x80,0xCB,0x04,0xE4,0x12,0x8A,0xE0,0x24,0x18,0x0A,0xD8,0xE4,0xDA, +0xF6,0xC4,0x02,0x74,0x07,0xA8,0x40,0x75,0x03,0x80,0xCB,0x20,0xA8,0x02,0x75,0x09, +0xE4,0x2A,0xA8,0x0F,0x74,0x03,0x80,0xCB,0x40,0xF7,0x46,0x38,0x02,0x00,0x74,0x09, +0xE4,0xD8,0xA8,0x01,0x75,0x03,0x80,0xCB,0x80,0x88,0x9E,0xBE,0x00,0xFE,0x86,0xB4, +0x00,0xB0,0x0A,0xE8,0x5C,0xE4,0xF8,0xC3,0xAC,0x49,0x3C,0x02,0x74,0x41,0x77,0x1F, +0x50,0xE8,0x4F,0xF5,0x58,0x72,0x0C,0x84,0xC0,0x74,0x0A,0xB0,0x12,0xE6,0x0A,0x80, +0x4E,0x38,0x01,0xF8,0xC3,0xB0,0x11,0xE6,0x0A,0x80,0x66,0x38,0xFE,0xF8,0xC3,0x8B, +0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9,0x00,0x04,0x75,0xE6,0x8A,0x86,0xA5, +0x00,0xA8,0x10,0x75,0xDE,0x0C,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xF8,0xC3,0x81, +0x4E,0x38,0x00,0x08,0x8A,0x86,0xA5,0x00,0xA8,0x10,0x74,0xC7,0x24,0xEF,0xEB,0xE7, +0xAD,0x49,0x49,0x3C,0x01,0x72,0x11,0x3C,0x0C,0x77,0x0D,0x50,0x8A,0xE0,0xE4,0x14, +0x25,0xF0,0x0F,0x0A,0xC4,0xE6,0x14,0x58,0x8A,0xC4,0x84,0xC0,0x74,0x02,0xE6,0x42, +0xF8,0xC3,0xE8,0xCF,0xF9,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0xD4,0xE3,0xF8,0xC3, +0x3A,0x86,0xAF,0x00,0x74,0x1F,0x88,0x86,0xAF,0x00,0x8A,0xE0,0x80,0xC2,0x06,0xB0, +0xBF,0xEE,0x80,0xEA,0x02,0x8A,0xC4,0xEE,0x8A,0x86,0xA8,0x00,0x80,0xC2,0x02,0xEE, +0x80,0xEA,0x06,0x8A,0xC4,0xC3,0x8B,0x46,0x3E,0x85,0xC0,0x8A,0x86,0xA5,0x00,0x74, +0x12,0xA8,0x08,0x75,0x0D,0x0C,0x08,0x88,0x86,0xA5,0x00,0x80,0xC2,0x02,0xEE,0x80, +0xEA,0x02,0xC3,0xA8,0x08,0x74,0xFB,0x24,0xF7,0xEB,0xEC,0x8B,0x46,0x26,0x84,0xC0, +0x74,0x16,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,0x0D,0x24,0xFD,0x88,0x86,0xA5,0x00, +0x83,0xC2,0x02,0xEE,0x83,0xEA,0x02,0xC3,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x75,0xF7, +0x0C,0x02,0xEB,0xE8,0x52,0x83,0xC2,0x0C,0xEC,0xC0,0xE8,0x04,0x88,0x86,0xA9,0x00, +0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,0xC7,0x04,0x74,0x07,0xA8,0x08,0x75,0x03,0x80, +0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,0xA8,0x02,0x75,0x03,0x80,0xCB,0x80,0x88,0x5E, +0x26,0x8A,0x86,0xA5,0x00,0x84,0xDB,0x74,0x10,0xA8,0x02,0x74,0x0A,0x24,0xFD,0x88, +0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,0x5A,0xC3,0xA8,0x02,0x75,0xFA,0x0C,0x02,0xEB, +0xEE,0x90,0xFF,0xFF,0x00,0x48,0x00,0x30,0xBA,0x20,0xC4,0x1A,0x00,0x18,0x00,0x12, +0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x02,0x80,0x01,0xC0,0x00,0x60,0x00,0x30,0x00, +0x18,0x00,0xCD,0x01,0x00,0x01,0x80,0x00,0x10,0x00,0x10,0x00,0x0E,0x00,0x0C,0x00, +0x08,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x04,0x00,0x03,0x00,0x02,0x00,0x01,0x00, +0x52,0x51,0x56,0x3C,0x1E,0x77,0x47,0x98,0x8B,0xF0,0x8A,0x82,0xC4,0x00,0x32,0xE4, +0x83,0xFE,0x18,0x74,0x3D,0x83,0xFE,0x19,0x74,0x3E,0x83,0xFE,0x1E,0x77,0x2F,0xD1, +0xE6,0x2E,0x8B,0x8C,0x32,0x2D,0x3B,0x8E,0x94,0x00,0x74,0x22,0x89,0x8E,0x94,0x00, +0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA,0x06,0x8A, +0xC1,0xEE,0x83,0xC2,0x02,0x8A,0xC5,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE,0x5E,0x59, +0x5A,0xC3,0x8B,0x8E,0x8E,0x00,0xEB,0xCE,0x8B,0x8E,0x90,0x00,0xEB,0xC8,0x52,0x51, +0x3D,0x05,0x00,0x77,0x03,0xB8,0x05,0x00,0x8B,0xC8,0xBA,0x02,0x00,0xB8,0x00,0xD0, +0xF7,0xF1,0x05,0x01,0x00,0xD1,0xE8,0x59,0x5A,0xC3,0x8B,0x46,0x7A,0xA8,0x20,0x74, +0x0B,0x80,0xBE,0xC3,0x00,0x03,0x75,0x04,0x0C,0x01,0xEB,0x02,0x24,0xFE,0x89,0x46, +0x7A,0xC3,0x24,0x03,0x88,0x86,0xC3,0x00,0x8A,0xA6,0xA8,0x00,0x8A,0xDC,0x80,0xE4, +0xFC,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,0x06,0xEE,0x83, +0xEA,0x06,0xE8,0xC5,0xFF,0xC3,0x00,0x08,0x18,0x38,0x28,0x90,0x3C,0x04,0x77,0x23, +0x32,0xE4,0x8B,0xD8,0x2E,0x8A,0x87,0x26,0x2E,0x8A,0xA6,0xA8,0x00,0x8A,0xDC,0x80, +0xE4,0xC7,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,0x06,0xEE, +0x83,0xEA,0x06,0xC3,0x84,0xC0,0x74,0x02,0xB0,0x04,0x8A,0xA6,0xA8,0x00,0x8A,0xDC, +0x80,0xE4,0xFB,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,0x06, +0xEE,0x83,0xEA,0x06,0xC3,0x90,0x8B,0x5E,0x38,0x84,0xC0,0x74,0x34,0x3C,0x02,0x74, +0x3B,0x8A,0x86,0xAF,0x00,0x0C,0x04,0xE8,0xE6,0xFD,0x8B,0x46,0x2E,0x3B,0x46,0x3C, +0x77,0x1B,0xF7,0xC3,0x00,0x04,0x75,0x15,0x81,0xCB,0x00,0x04,0x83,0xC2,0x02,0x8A, +0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0x89,0x5E,0x38, +0xC3,0x8A,0x86,0xAF,0x00,0x24,0xFB,0xE8,0xB6,0xFD,0xEB,0xF1,0xF7,0xC3,0x10,0x00, +0x74,0xEF,0xEB,0xED,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8,0x04,0x88,0x86, +0xA9,0x00,0xC3,0x90,0x8A,0x86,0xA7,0x00,0x0C,0x01,0x88,0x86,0xA7,0x00,0x8B,0xDA, +0x80,0xC2,0x08,0xEE,0x8B,0xD3,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x24,0xFE,0xEB,0xEA, +0x8A,0x86,0xA7,0x00,0x0C,0x02,0xEB,0xE2,0x8A,0x86,0xA7,0x00,0x24,0xFD,0xEB,0xDA, +0xB0,0xFF,0xE8,0x52,0xF2,0xE8,0x97,0xF2,0xF8,0xC3,0xAC,0x49,0xE8,0x61,0xFE,0xF8, +0xC3,0x90,0xAC,0x49,0xE8,0xEB,0xFE,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x35,0xFF,0xF8, +0xC3,0x90,0xAC,0x49,0xE8,0x05,0xFF,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF, +0xEE,0x52,0x83,0xC2,0x02,0xAC,0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE,0x5A,0xF8, +0xC3,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x06,0xEB,0xE6,0x90, +0xAC,0x49,0x3C,0x02,0x77,0x0D,0x84,0xC0,0x75,0x0B,0x8A,0x86,0xAF,0x00,0x24,0xFD, +0xE8,0x0D,0xFD,0xF8,0xC3,0x50,0x8A,0x86,0xAF,0x00,0x0C,0x02,0xE8,0x01,0xFD,0x5B, +0x83,0xC2,0x08,0x8A,0x86,0xA7,0x00,0xF6,0xC3,0x01,0x74,0x0C,0x24,0xDF,0x88,0x86, +0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x0C,0x20,0xEB,0xF2,0xAC,0x49,0xE8,0xE5, +0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x69,0xF5,0xE8,0xF9,0xFC,0xE8,0x24,0xFF, +0xB0,0x01,0xE8,0xA5,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x71,0xF5,0xE8,0xE5, +0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x49,0xF5,0xE8,0xD9,0xFC,0xE8,0x04,0xFF, +0xB0,0x08,0xE8,0x85,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x51,0xF5,0xE8,0xC5, +0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x29,0xF5,0xE8,0xB9,0xFC,0xE8,0xE4,0xFE, +0xB0,0x02,0xE8,0x65,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x31,0xF5,0xE8,0xA5, +0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x09,0xF5,0xE8,0x99,0xFC,0xE8,0xC4,0xFE, +0xB0,0x04,0xE8,0x45,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x11,0xF5,0xE8,0x85, +0xFC,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x34,0x0C,0xF8,0xC3,0x90,0xB8,0xFC,0x3B,0x89, +0x46,0x7C,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0x0C,0x80,0xE8,0x43,0xFC,0xF8,0xC3,0x90, +0x8A,0x86,0xAF,0x00,0x24,0x7F,0xEB,0xF2,0x8A,0x86,0xAF,0x00,0x0C,0x40,0xE8,0x2F, +0xFC,0xF8,0xC3,0x90,0x8A,0x86,0xAF,0x00,0x24,0xBF,0xEB,0xF2,0xAC,0x49,0xA8,0x01, +0x74,0x07,0x83,0x4E,0x7A,0x20,0xEB,0x05,0x90,0x83,0x66,0x7A,0xDF,0xE8,0x8A,0xFD, +0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,0x00,0xEE, +0x83,0xEA,0x06,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x26,0x01,0x83,0x4E, +0x48,0x08,0xB0,0x06,0xE8,0xBB,0xDF,0x49,0x46,0xF9,0xC3,0x90,0x83,0xC2,0x06,0x8A, +0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x06,0xAC,0xB4,0x0A, +0xF6,0xE4,0xEB,0xD0,0xE8,0xE0,0x0B,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89,0x46,0x64, +0xA9,0x01,0x00,0x74,0x19,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x0A,0xA9,0x04,0x00,0x74, +0x0D,0xB8,0xE2,0x3F,0xEB,0x0B,0xE8,0xEC,0xF4,0xB8,0xAA,0x40,0xEB,0x03,0xB8,0x38, +0x44,0x89,0x46,0x62,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0xA8,0x02,0x74,0x0A,0x24,0xFD, +0xE8,0x8D,0xFB,0x0C,0x02,0xE8,0x88,0xFB,0xF8,0xC3,0xAC,0x49,0xE8,0x81,0xFC,0xF8, +0xC3,0x90,0xAC,0x49,0xE8,0x79,0xFC,0xF8,0xC3,0x90,0xE8,0x5C,0xF5,0x75,0x05,0xE8, +0xE6,0xFD,0xF8,0xC3,0xE8,0xCD,0xFD,0x36,0xA0,0xB4,0x13,0x24,0x10,0x34,0x10,0xE8, +0x26,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01,0x00,0x74,0x05,0xE8,0xFE,0xFE,0xEB,0x0E, +0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB,0x02,0xB0,0x01,0xE8,0xE8,0xFE,0x36,0xA1, +0xB4,0x13,0xE8,0xAB,0x0B,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01,0x00,0xE8, +0x0C,0xFF,0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x2B,0xFD,0x32,0xC0,0x36,0x8A,0x26, 0xB5,0x13,0xF6,0xC4,0x04,0x74,0x09,0xFE,0xC0,0xF6,0xC4,0x08,0x74,0x02,0xFE,0xC0, -0xE8,0xDB,0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x71,0xF9,0x36,0xA1,0xB6, -0x13,0xC1,0xE8,0x04,0x25,0x03,0x00,0xE8,0xD2,0xFA,0x36,0xA1,0xB6,0x13,0xC1,0xE8, -0x05,0x25,0x02,0x00,0xE8,0x1F,0xFB,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01,0x75,0x04, -0x32,0xC0,0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8,0xC6,0xFA, -0x36,0xF6,0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x83,0xFE,0xEB,0x03,0xE8,0x84,0xFE, -0x36,0xF6,0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x65,0xFE,0xEB,0x03,0xE8,0x68,0xFE, -0xF8,0xC3,0xE4,0x12,0x0C,0x01,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFE,0xEB,0xF6, -0xE4,0x14,0x24,0xF0,0x0C,0x05,0xE6,0x14,0xE4,0x2A,0x24,0xF0,0x0C,0x06,0xE6,0x2A, -0xF8,0xC3,0xE4,0x2A,0x24,0xF0,0xE6,0x2A,0xE4,0x14,0x24,0xF0,0x0C,0x07,0xE6,0x14, -0xF8,0xC3,0xAD,0x49,0x49,0xE8,0x7E,0xF9,0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49, -0x49,0xE8,0x72,0xF9,0x89,0x86,0x90,0x00,0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0xC2, -0xF7,0xF8,0xC3,0x90,0x83,0x66,0x26,0xFB,0xE8,0xB8,0xF7,0xF8,0xC3,0x90,0xAC,0x49, -0x84,0xC0,0x75,0x0D,0xE4,0x10,0x24,0xEF,0xE6,0x10,0x80,0x8E,0xA1,0x00,0x42,0xF8, -0xC3,0xE4,0x10,0x0C,0x10,0xEB,0xF1,0x90,0xAC,0x49,0x3C,0x02,0x76,0x02,0x32,0xC0, -0xC0,0xE0,0x04,0xA8,0x20,0x74,0x02,0x0C,0x08,0x24,0x18,0x8A,0xE0,0xE4,0x12,0x24, -0xE7,0x0A,0xC4,0xE6,0x12,0x80,0x8E,0xA1,0x00,0x44,0xF8,0xC3,0xAC,0x49,0x88,0x86, -0xC0,0x00,0xF8,0xC3,0xAC,0x49,0xE6,0x3A,0xF8,0xC3,0xAC,0x49,0x84,0xC0,0x74,0x08, -0xE4,0x12,0x0C,0x04,0xE6,0x12,0xF8,0xC3,0xE4,0x12,0x24,0xFB,0xEB,0xF6,0xAC,0x49, -0xE8,0xF0,0xF6,0x73,0x03,0xE8,0x41,0xF7,0xF8,0xC3,0xE4,0x12,0xA8,0x02,0x74,0x04, -0x24,0xFD,0xE6,0x12,0xB8,0xF0,0x00,0xE8,0xA1,0xFA,0x81,0x66,0x26,0xFF,0xF3,0xE8, -0x71,0xF7,0xE8,0xB4,0xFA,0xF8,0xC3,0x90,0xB8,0x80,0x00,0xE8,0x71,0xFA,0x80,0x4E, -0x27,0x08,0xE8,0x5E,0xF7,0xE8,0xA1,0xFA,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x7B,0xFA, -0x81,0x66,0x26,0xFF,0xF7,0xE8,0x4B,0xF7,0xE8,0x8E,0xFA,0xF8,0xC3,0x90,0xB8,0x10, -0x00,0xE8,0x4B,0xFA,0x80,0x4E,0x27,0x04,0xE8,0x38,0xF7,0xE8,0x7B,0xFA,0xF8,0xC3, -0xB8,0x10,0x00,0xE8,0x55,0xFA,0x81,0x66,0x26,0xFF,0xFB,0xE8,0x25,0xF7,0xE8,0x68, -0xFA,0xF8,0xC3,0x90,0x33,0xC0,0xAC,0x49,0x3C,0x01,0x73,0x04,0xB0,0x01,0xEB,0x06, -0x3C,0x0C,0x76,0x02,0xB0,0x0C,0x89,0x46,0x1C,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00, -0x20,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x24,0xFB,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x83, -0x4E,0x26,0x01,0xF8,0xC3,0x90,0x81,0x4E,0x26,0x00,0x40,0x8A,0x86,0xA5,0x00,0x0C, -0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xF8,0xC3,0x90,0xAC,0x49,0x50,0xE8,0x1F,0xF6, -0x58,0x72,0x08,0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xF8,0xC3,0xF9,0xC3,0x90,0xAC,0x50, -0xAD,0xE8,0x9C,0xF8,0x5A,0xF6,0xC2,0x01,0x74,0x12,0x39,0x86,0x96,0x00,0x74,0x0C, -0x89,0x86,0x96,0x00,0xE6,0xF0,0x86,0xE0,0xE6,0xF8,0x86,0xE0,0xF6,0xC2,0x02,0x74, -0x10,0x39,0x86,0x94,0x00,0x74,0x0A,0x89,0x86,0x94,0x00,0xE6,0xE4,0x86,0xE0,0xE6, -0xEC,0x83,0xE9,0x03,0xC3,0x90,0xE4,0x16,0x88,0x86,0xBC,0x00,0xE8,0x00,0xFB,0x33, -0xDB,0xE4,0x0C,0xA8,0x06,0x74,0x03,0x80,0xCB,0x01,0xA8,0x10,0x74,0x03,0x80,0xCB, -0x02,0xA8,0x80,0x74,0x03,0x80,0xCB,0x04,0xE4,0x12,0x8A,0xE0,0x24,0x18,0x0A,0xD8, -0xE4,0xDA,0xF6,0xC4,0x02,0x74,0x07,0xA8,0x40,0x75,0x03,0x80,0xCB,0x20,0xA8,0x02, -0x75,0x09,0xE4,0x2A,0xA8,0x0F,0x74,0x03,0x80,0xCB,0x40,0xF7,0x46,0x38,0x02,0x00, -0x74,0x09,0xE4,0xD8,0xA8,0x01,0x75,0x03,0x80,0xCB,0x80,0x88,0x9E,0xBE,0x00,0xFE, -0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x76,0xE4,0xF8,0xC3,0xAC,0x49,0x3C,0x02,0x74,0x41, -0x77,0x1F,0x50,0xE8,0x69,0xF5,0x58,0x72,0x0C,0x84,0xC0,0x74,0x0A,0xB0,0x12,0xE6, -0x0A,0x80,0x4E,0x38,0x01,0xF8,0xC3,0xB0,0x11,0xE6,0x0A,0x80,0x66,0x38,0xFE,0xF8, -0xC3,0x8B,0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9,0x00,0x04,0x75,0xE6,0x8A, -0x86,0xA5,0x00,0xA8,0x10,0x75,0xDE,0x0C,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xF8, -0xC3,0x81,0x4E,0x38,0x00,0x08,0x8A,0x86,0xA5,0x00,0xA8,0x10,0x74,0xC7,0x24,0xEF, -0xEB,0xE7,0xAD,0x49,0x49,0x3C,0x01,0x72,0x11,0x3C,0x0C,0x77,0x0D,0x50,0x8A,0xE0, -0xE4,0x14,0x25,0xF0,0x0F,0x0A,0xC4,0xE6,0x14,0x58,0x8A,0xC4,0x84,0xC0,0x74,0x02, -0xE6,0x42,0xF8,0xC3,0xE8,0xE9,0xF9,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0xEE,0xE3, -0xF8,0xC3,0x3A,0x86,0xAF,0x00,0x74,0x1F,0x88,0x86,0xAF,0x00,0x8A,0xE0,0x80,0xC2, -0x06,0xB0,0xBF,0xEE,0x80,0xEA,0x02,0x8A,0xC4,0xEE,0x8A,0x86,0xA8,0x00,0x80,0xC2, -0x02,0xEE,0x80,0xEA,0x06,0x8A,0xC4,0xC3,0x8B,0x46,0x3E,0x85,0xC0,0x8A,0x86,0xA5, -0x00,0x74,0x12,0xA8,0x08,0x75,0x0D,0x0C,0x08,0x88,0x86,0xA5,0x00,0x80,0xC2,0x02, -0xEE,0x80,0xEA,0x02,0xC3,0xA8,0x08,0x74,0xFB,0x24,0xF7,0xEB,0xEC,0x8B,0x46,0x26, -0x84,0xC0,0x74,0x16,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74,0x0D,0x24,0xFD,0x88,0x86, -0xA5,0x00,0x83,0xC2,0x02,0xEE,0x83,0xEA,0x02,0xC3,0x8A,0x86,0xA5,0x00,0xA8,0x02, -0x75,0xF7,0x0C,0x02,0xEB,0xE8,0x52,0x83,0xC2,0x0C,0xEC,0xC0,0xE8,0x04,0x88,0x86, -0xA9,0x00,0x8B,0x5E,0x26,0x80,0xE3,0x3F,0xF6,0xC7,0x04,0x74,0x07,0xA8,0x08,0x75, -0x03,0x80,0xCB,0x40,0xF6,0xC7,0x08,0x74,0x07,0xA8,0x02,0x75,0x03,0x80,0xCB,0x80, -0x88,0x5E,0x26,0x8A,0x86,0xA5,0x00,0x84,0xDB,0x74,0x10,0xA8,0x02,0x74,0x0A,0x24, -0xFD,0x88,0x86,0xA5,0x00,0x83,0xEA,0x0A,0xEE,0x5A,0xC3,0xA8,0x02,0x75,0xFA,0x0C, -0x02,0xEB,0xEE,0x90,0xFF,0xFF,0x00,0x48,0x00,0x30,0xBA,0x20,0xC4,0x1A,0x00,0x18, -0x00,0x12,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x02,0x80,0x01,0xC0,0x00,0x60,0x00, -0x30,0x00,0x18,0x00,0xCD,0x01,0x00,0x01,0x80,0x00,0x10,0x00,0x10,0x00,0x0E,0x00, -0x0C,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x04,0x00,0x03,0x00,0x02,0x00, -0x01,0x00,0x52,0x51,0x56,0x3C,0x1E,0x77,0x47,0x98,0x8B,0xF0,0x8A,0x82,0xC4,0x00, -0x32,0xE4,0x83,0xFE,0x18,0x74,0x3D,0x83,0xFE,0x19,0x74,0x3E,0x83,0xFE,0x1E,0x77, -0x2F,0xD1,0xE6,0x2E,0x8B,0x8C,0x14,0x2D,0x3B,0x8E,0x94,0x00,0x74,0x22,0x89,0x8E, -0x94,0x00,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA, -0x06,0x8A,0xC1,0xEE,0x83,0xC2,0x02,0x8A,0xC5,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE, -0x5E,0x59,0x5A,0xC3,0x8B,0x8E,0x8E,0x00,0xEB,0xCE,0x8B,0x8E,0x90,0x00,0xEB,0xC8, -0x52,0x51,0x3D,0x05,0x00,0x77,0x03,0xB8,0x05,0x00,0x8B,0xC8,0xBA,0x02,0x00,0xB8, -0x00,0xD0,0xF7,0xF1,0x05,0x01,0x00,0xD1,0xE8,0x59,0x5A,0xC3,0x8B,0x46,0x7A,0xA8, -0x20,0x74,0x0B,0x80,0xBE,0xC3,0x00,0x03,0x75,0x04,0x0C,0x01,0xEB,0x02,0x24,0xFE, -0x89,0x46,0x7A,0xC3,0x24,0x03,0x88,0x86,0xC3,0x00,0x8A,0xA6,0xA8,0x00,0x8A,0xDC, -0x80,0xE4,0xFC,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2,0x06, -0xEE,0x83,0xEA,0x06,0xE8,0xC5,0xFF,0xC3,0x00,0x08,0x18,0x38,0x28,0x90,0x3C,0x04, -0x77,0x23,0x32,0xE4,0x8B,0xD8,0x2E,0x8A,0x87,0x08,0x2E,0x8A,0xA6,0xA8,0x00,0x8A, -0xDC,0x80,0xE4,0xC7,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83,0xC2, -0x06,0xEE,0x83,0xEA,0x06,0xC3,0x84,0xC0,0x74,0x02,0xB0,0x04,0x8A,0xA6,0xA8,0x00, -0x8A,0xDC,0x80,0xE4,0xFB,0x0A,0xC4,0x3A,0xC3,0x74,0x0B,0x88,0x86,0xA8,0x00,0x83, -0xC2,0x06,0xEE,0x83,0xEA,0x06,0xC3,0x90,0x8B,0x5E,0x38,0x84,0xC0,0x74,0x34,0x3C, -0x02,0x74,0x3B,0x8A,0x86,0xAF,0x00,0x0C,0x04,0xE8,0xE6,0xFD,0x8B,0x46,0x2E,0x3B, -0x46,0x3C,0x77,0x1B,0xF7,0xC3,0x00,0x04,0x75,0x15,0x81,0xCB,0x00,0x04,0x83,0xC2, -0x02,0x8A,0x86,0xA5,0x00,0x24,0xFA,0x88,0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0x89, -0x5E,0x38,0xC3,0x8A,0x86,0xAF,0x00,0x24,0xFB,0xE8,0xB6,0xFD,0xEB,0xF1,0xF7,0xC3, -0x10,0x00,0x74,0xEF,0xEB,0xED,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8,0x04, -0x88,0x86,0xA9,0x00,0xC3,0x90,0x8A,0x86,0xA7,0x00,0x0C,0x01,0x88,0x86,0xA7,0x00, -0x8B,0xDA,0x80,0xC2,0x08,0xEE,0x8B,0xD3,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x24,0xFE, -0xEB,0xEA,0x8A,0x86,0xA7,0x00,0x0C,0x02,0xEB,0xE2,0x8A,0x86,0xA7,0x00,0x24,0xFD, -0xEB,0xDA,0xB0,0xFF,0xE8,0x6C,0xF2,0xE8,0xB1,0xF2,0xF8,0xC3,0xAC,0x49,0xE8,0x61, -0xFE,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0xEB,0xFE,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x35, -0xFF,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x05,0xFF,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06, -0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x02,0xAC,0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE, -0x5A,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x06,0xEB, -0xE6,0x90,0xAC,0x49,0x3C,0x02,0x77,0x0D,0x84,0xC0,0x75,0x0B,0x8A,0x86,0xAF,0x00, -0x24,0xFD,0xE8,0x0D,0xFD,0xF8,0xC3,0x50,0x8A,0x86,0xAF,0x00,0x0C,0x02,0xE8,0x01, -0xFD,0x5B,0x83,0xC2,0x08,0x8A,0x86,0xA7,0x00,0xF6,0xC3,0x01,0x74,0x0C,0x24,0xDF, -0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x0C,0x20,0xEB,0xF2,0xAC,0x49, -0xE8,0xE5,0xFE,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x83,0xF5,0xE8,0xF9,0xFC,0xE8, -0x24,0xFF,0xB0,0x01,0xE8,0xBF,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x40,0xE8,0x8B,0xF5, -0xE8,0xE5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x63,0xF5,0xE8,0xD9,0xFC,0xE8, -0x04,0xFF,0xB0,0x08,0xE8,0x9F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x10,0xE8,0x6B,0xF5, -0xE8,0xC5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x43,0xF5,0xE8,0xB9,0xFC,0xE8, -0xE4,0xFE,0xB0,0x02,0xE8,0x7F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x80,0xE8,0x4B,0xF5, -0xE8,0xA5,0xFC,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x23,0xF5,0xE8,0x99,0xFC,0xE8, -0xC4,0xFE,0xB0,0x04,0xE8,0x5F,0xF6,0xF8,0xC3,0x90,0xB8,0x00,0x20,0xE8,0x2B,0xF5, -0xE8,0x85,0xFC,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x34,0x0C,0xF8,0xC3,0x90,0xB8,0xDE, -0x3B,0x89,0x46,0x7C,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0x0C,0x80,0xE8,0x43,0xFC,0xF8, -0xC3,0x90,0x8A,0x86,0xAF,0x00,0x24,0x7F,0xEB,0xF2,0x8A,0x86,0xAF,0x00,0x0C,0x40, -0xE8,0x2F,0xFC,0xF8,0xC3,0x90,0x8A,0x86,0xAF,0x00,0x24,0xBF,0xEB,0xF2,0xAC,0x49, -0xA8,0x01,0x74,0x07,0x83,0x4E,0x7A,0x20,0xEB,0x05,0x90,0x83,0x66,0x7A,0xDF,0xE8, -0x8A,0xFD,0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8, -0x00,0xEE,0x83,0xEA,0x06,0xAC,0x49,0x32,0xE4,0x89,0x46,0x6E,0x83,0x4E,0x26,0x01, -0x83,0x4E,0x48,0x08,0xB0,0x06,0xE8,0xD5,0xDF,0x49,0x46,0xF9,0xC3,0x90,0x83,0xC2, -0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,0x00,0xEE,0x83,0xEA,0x06,0xAC, -0xB4,0x0A,0xF6,0xE4,0xEB,0xD0,0xE8,0xE0,0x0B,0xF8,0xC3,0x90,0xAD,0x49,0x49,0x89, -0x46,0x64,0xA9,0x01,0x00,0x74,0x19,0x8B,0xD8,0x83,0xE3,0xFA,0x75,0x0A,0xA9,0x04, -0x00,0x74,0x0D,0xB8,0xC4,0x3F,0xEB,0x0B,0xE8,0x06,0xF5,0xB8,0x8C,0x40,0xEB,0x03, -0xB8,0x1A,0x44,0x89,0x46,0x62,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0xA8,0x02,0x74,0x0A, -0x24,0xFD,0xE8,0x8D,0xFB,0x0C,0x02,0xE8,0x88,0xFB,0xF8,0xC3,0xAC,0x49,0xE8,0x81, -0xFC,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x79,0xFC,0xF8,0xC3,0x90,0xE8,0x76,0xF5,0x75, -0x05,0xE8,0xE6,0xFD,0xF8,0xC3,0xE8,0xCD,0xFD,0x36,0xA0,0xB4,0x13,0x24,0x10,0x34, -0x10,0xE8,0x26,0x01,0x36,0xA1,0xB4,0x13,0xA9,0x01,0x00,0x74,0x05,0xE8,0xFE,0xFE, -0xEB,0x0E,0xA9,0x02,0x00,0x74,0x04,0x32,0xC0,0xEB,0x02,0xB0,0x01,0xE8,0xE8,0xFE, -0x36,0xA1,0xB4,0x13,0xE8,0xAB,0x0B,0x36,0xA1,0xB4,0x13,0xC1,0xE8,0x05,0x25,0x01, -0x00,0xE8,0x0C,0xFF,0x36,0xA0,0xB5,0x13,0x24,0x10,0xE8,0x2B,0xFD,0x32,0xC0,0x36, -0x8A,0x26,0xB5,0x13,0xF6,0xC4,0x04,0x74,0x09,0xFE,0xC0,0xF6,0xC4,0x08,0x74,0x02, -0xFE,0xC0,0xE8,0xEF,0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x03,0xFC,0x36, -0xA1,0xB6,0x13,0xC1,0xE8,0x04,0x25,0x03,0x00,0xE8,0x88,0xFC,0x36,0xA1,0xB6,0x13, -0xC1,0xE8,0x05,0x25,0x02,0x00,0xE8,0xCD,0xFC,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01, -0x75,0x04,0x32,0xC0,0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8, -0x8C,0xFC,0x36,0xF6,0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x8D,0xFE,0xEB,0x03,0xE8, -0x94,0xFE,0x36,0xF6,0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x69,0xFE,0xEB,0x03,0xE8, -0x70,0xFE,0xF8,0xC3,0xF8,0xC3,0x8B,0x46,0x38,0xA9,0x04,0x00,0x75,0x23,0x0D,0x04, -0x00,0x89,0x46,0x38,0x83,0xC2,0x08,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0x73,0x14,0x83, -0x4E,0x38,0x10,0x8A,0x86,0xA7,0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA, -0x08,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEB,0xEE,0x90,0x8B,0x46,0x38,0xA9, -0x04,0x00,0x74,0x06,0x25,0xFB,0xFF,0x89,0x46,0x38,0xF8,0xC3,0xAD,0x49,0x49,0xE8, -0xBE,0xFB,0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49,0x49,0xE8,0xB2,0xFB,0x89,0x86, -0x90,0x00,0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0x92,0xFA,0xF8,0xC3,0x90,0x83,0x66, -0x26,0xFB,0xE8,0x88,0xFA,0xF8,0xC3,0x90,0xAC,0x49,0x84,0xC0,0x75,0x07,0x80,0x8E, -0xA3,0x00,0x04,0xF8,0xC3,0x80,0xA6,0xA3,0x00,0xFB,0xF8,0xC3,0xAC,0x49,0x83,0xC2, -0x08,0x3C,0x02,0x76,0x02,0x32,0xC0,0x3C,0x01,0x74,0x12,0x77,0x0B,0x8A,0x86,0xA7, -0x00,0x24,0xEF,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x8A,0x86,0xA7, -0x00,0x0C,0x10,0xEB,0xEE,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2, -0x04,0xAC,0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE,0x5A,0xF8,0xC3,0x90,0x52,0x83, -0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x08,0xEB,0xE6,0x90,0xAC,0x49,0xF8,0xC3, -0xAC,0x49,0xE8,0xCE,0xEE,0x73,0x03,0xE8,0x11,0xEF,0xF8,0xC3,0x8A,0x86,0xAF,0x00, -0x24,0x7F,0xE8,0xBD,0xF9,0xB8,0xF0,0x00,0xE8,0x80,0xF2,0x81,0x66,0x26,0xFF,0xF3, -0xE8,0x23,0xFA,0xE8,0xD2,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x51,0xF2,0x80,0x4E, -0x27,0x08,0xE8,0x11,0xFA,0xE8,0xC0,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x5B,0xF2, -0x81,0x66,0x26,0xFF,0xF7,0xE8,0xFE,0xF9,0xE8,0xAD,0xF9,0xF8,0xC3,0x90,0xB8,0x10, -0x00,0xE8,0x2B,0xF2,0x80,0x4E,0x27,0x04,0xE8,0xEB,0xF9,0xE8,0x9A,0xF9,0xF8,0xC3, -0xB8,0x10,0x00,0xE8,0x19,0xF2,0x81,0x66,0x26,0xFF,0xFB,0xE8,0xD8,0xF9,0xF8,0xC3, -0xAC,0x49,0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8, -0x00,0xEE,0x83,0xEA,0x06,0xF8,0xC3,0x90,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x24, -0xBF,0xEB,0xEA,0x90,0xAC,0x49,0x8A,0xE0,0x80,0xC2,0x0A,0xEC,0x80,0xEA,0x0A,0xA8, -0x20,0x74,0x05,0x8A,0xC4,0xEE,0xF8,0xC3,0x06,0x51,0x57,0x8B,0x4E,0x24,0xE3,0x34, -0x49,0x89,0x4E,0x24,0xFF,0x46,0x1A,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x8A,0xC4,0xAA, -0x89,0x7E,0x22,0x8B,0x46,0x26,0x24,0xFD,0x89,0x46,0x26,0x75,0x29,0x8A,0x86,0xA5, -0x00,0xA8,0x02,0x75,0x21,0x80,0xC2,0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x80, -0xEA,0x02,0xEB,0x12,0xC4,0x7E,0x00,0x3B,0x7E,0x1E,0x76,0x0A,0x4F,0x26,0x88,0x25, -0x89,0x7E,0x00,0xFF,0x46,0x1A,0x5F,0x59,0x07,0xF8,0xC3,0x90,0xAC,0xAD,0x83,0xE9, -0x03,0x85,0xC0,0x74,0x05,0x3D,0x00,0x20,0x72,0x05,0xB8,0xFF,0xFF,0xEB,0x03,0xC1, -0xE0,0x03,0x3B,0x86,0x94,0x00,0x74,0x26,0x89,0x86,0x94,0x00,0x8B,0xD8,0x52,0x83, -0xC2,0x06,0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA,0x06,0x8A,0xC3, -0xEE,0x83,0xC2,0x02,0x8A,0xC7,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE,0x5A,0xF8,0xC3, -0xB0,0x88,0x88,0x86,0xBC,0x00,0xE8,0xA6,0xF2,0x33,0xDB,0x8A,0x86,0xA5,0x00,0xA8, -0x02,0x74,0x03,0x80,0xCB,0x01,0xA8,0x05,0x74,0x03,0x80,0xCB,0x02,0xA8,0x08,0x74, -0x03,0x80,0xCB,0x04,0xF6,0x86,0xA7,0x00,0x10,0x74,0x03,0x80,0xCB,0x10,0x8A,0x86, -0xA9,0x00,0xF6,0xC3,0x04,0x75,0x0A,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8, -0x04,0x8A,0xE0,0x8A,0x86,0xAF,0x00,0xA8,0x80,0x74,0x08,0xF6,0xC4,0x01,0x75,0x03, -0x80,0xCB,0x20,0xF6,0x86,0xA7,0x00,0x02,0x75,0x0A,0xF7,0x46,0x38,0x04,0x00,0x74, -0x03,0x80,0xCB,0x40,0x88,0x9E,0xBE,0x00,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x0D, -0xDC,0xF8,0xC3,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0x02,0xDC,0xF8,0xC3,0xAC,0x49, -0x3C,0x02,0x74,0x37,0x77,0x10,0x84,0xC0,0x74,0x06,0x80,0x4E,0x38,0x01,0xF8,0xC3, -0x80,0x66,0x38,0xFE,0xF8,0xC3,0x8B,0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9, -0x00,0x04,0x75,0xEA,0x8A,0x86,0xA5,0x00,0xA8,0x01,0x75,0xE2,0x0C,0x05,0x83,0xC2, -0x02,0x88,0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0xF8,0xC3,0x81,0x4E,0x38,0x00,0x08, -0x8A,0x86,0xA5,0x00,0xA8,0x01,0x74,0xC6,0x24,0xFA,0xEB,0xE2,0xAD,0x49,0x49,0xF8, -0xC3,0x90,0xE8,0x11,0xFA,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0xA0,0xDB,0xF8,0xC3, -0xB0,0xFF,0xE8,0xD9,0xEC,0xF8,0xC3,0x90,0x83,0x66,0x7A,0xFB,0xB0,0x00,0xE8,0x8D, -0xDB,0xF8,0xC3,0x90,0xAC,0x49,0xE8,0x6D,0xD9,0x72,0x11,0x36,0x88,0x1E,0x1A,0x01, -0x36,0xA0,0x8E,0x12,0x0A,0xC3,0x52,0xBA,0x00,0x01,0xEE,0x5A,0xF8,0xC3,0xAC,0x49, -0x32,0xE4,0x36,0xA3,0x86,0x12,0x05,0x06,0x00,0x36,0x8B,0x1E,0x88,0x12,0x2B,0xD8, -0x36,0x89,0x1E,0x8A,0x12,0xF8,0xC3,0x90,0xAD,0x8B,0xD8,0xAD,0x83,0xE9,0x04,0x03, -0xC3,0x2B,0x46,0x76,0x89,0x46,0x78,0xF7,0x46,0x7A,0x02,0x00,0x74,0x0A,0x83,0x66, -0x7A,0xFD,0xB8,0x00,0x00,0xE8,0x36,0xDB,0xF8,0xC3,0x06,0x16,0x07,0xAC,0x49,0x25, -0x0F,0x00,0x6B,0xC0,0x09,0x8D,0xBE,0xFD,0x00,0x03,0xF8,0xAC,0x49,0x25,0x0F,0x00, -0xAA,0x85,0xC0,0x74,0x08,0x2B,0xC8,0x51,0x8B,0xC8,0xF3,0xA4,0x59,0xE8,0x41,0xF0, -0xE8,0x44,0x03,0x07,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0xB2,0x13,0x36,0xA3, -0xB0,0x13,0xF8,0xC3,0x83,0x66,0x7A,0xEF,0xE8,0x2C,0x03,0xF8,0xC3,0x90,0x83,0x4E, -0x7A,0x10,0xEB,0xF4,0xE8,0xB5,0xF0,0xF8,0xC3,0x90,0xAD,0x3C,0x19,0x77,0x0E,0x3C, -0x19,0x77,0x0A,0x8B,0xF8,0x81,0xE7,0xFF,0x00,0x88,0xA6,0xC4,0x00,0xF8,0xC3,0x90, -0x83,0x4E,0x26,0x20,0xAC,0x49,0x32,0xE4,0xD1,0xE0,0x8B,0xD8,0xC1,0xE3,0x02,0x03, -0xC3,0x89,0x46,0x6E,0x83,0x4E,0x48,0x04,0xB0,0x06,0xE8,0xB1,0xDA,0x49,0x46,0xF9, -0xC3,0x90,0xFE,0x86,0xB3,0x00,0xB0,0x0A,0xE8,0xA3,0xDA,0xF8,0xC3,0x90,0x33,0xC0, -0xAC,0x49,0x6B,0xC0,0x0A,0x89,0x86,0x8A,0x00,0xF8,0xC3,0x90,0xAC,0x49,0x32,0xE4, -0x3D,0x0A,0x00,0x77,0x05,0xB8,0x0A,0x00,0xEB,0x08,0x3D,0x5A,0x00,0x72,0x03,0xB8, -0x5A,0x00,0x51,0xF7,0xD8,0x05,0x64,0x00,0x8B,0xC8,0x8B,0x46,0x44,0xF7,0xE1,0xB9, -0x64,0x00,0xF7,0xF1,0x89,0x46,0x46,0x59,0xF8,0xC3,0xAC,0x49,0xE8,0x9F,0xEB,0xF8, -0xC3,0x90,0xAC,0x49,0x84,0xC0,0x75,0x07,0x81,0x66,0x38,0xFF,0xFD,0xF8,0xC3,0x81, -0x4E,0x38,0x00,0x02,0xF7,0x46,0x38,0x40,0x00,0x75,0x08,0x8A,0x86,0xA9,0x00,0x88, -0x86,0xAA,0x00,0xF8,0xC3,0x90,0x51,0x56,0xE8,0x7F,0x0C,0x5E,0x59,0xF8,0xC3,0x90, -0xFE,0x86,0xB6,0x00,0xB0,0x0A,0xE8,0x25,0xDA,0xF8,0xC3,0x90,0xFE,0x86,0xB7,0x00, -0xB0,0x0A,0xE8,0x19,0xDA,0xF8,0xC3,0x90,0xFE,0x86,0xB8,0x00,0xB0,0x0A,0xE8,0x0D, -0xDA,0xF8,0xC3,0x90,0x00,0x90,0x51,0x55,0xAC,0x2E,0xA2,0x34,0x36,0x33,0xC9,0xAD, -0x8B,0xF9,0xC1,0xE7,0x05,0xA9,0x01,0x00,0x74,0x23,0x2E,0x8B,0xAD,0x44,0x00,0x83, -0x7E,0x08,0x00,0x74,0x18,0x2E,0x80,0x3E,0x34,0x36,0x01,0x74,0x09,0x60,0xB0,0x04, -0xE8,0xBB,0x0C,0x61,0xEB,0x07,0x60,0xB0,0xFB,0xE8,0xEC,0x0C,0x61,0x47,0x47,0xD1, -0xE8,0x75,0xD2,0x41,0x83,0xF9,0x04,0x72,0xC6,0x5D,0x59,0x83,0xE9,0x05,0xF7,0x46, -0x38,0x40,0x00,0x74,0x05,0xE8,0xA1,0xEA,0xF8,0xC3,0xE8,0xA7,0xEA,0xF8,0xC3,0x90, -0x36,0xC6,0x06,0xC8,0x13,0x01,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0x80,0x12, -0xAC,0x49,0x36,0x2B,0x06,0x88,0x12,0xF7,0xD8,0x36,0xA3,0x82,0x12,0xF8,0xC3,0x90, -0xC0,0x26,0xC0,0x26,0xCE,0x26,0xD4,0x26,0xDA,0x26,0xE0,0x26,0xE6,0x26,0xF0,0x26, -0xF8,0x26,0x00,0x27,0x08,0x27,0x10,0x27,0x16,0x27,0xA0,0x34,0xA8,0x34,0xB4,0x34, -0x1C,0x27,0x5A,0x27,0x62,0x27,0x76,0x27,0x82,0x27,0x96,0x27,0xA2,0x27,0xB6,0x27, -0xC2,0x27,0xD6,0x27,0xE2,0x27,0xF2,0x27,0xCE,0x34,0xC0,0x26,0x00,0x28,0x08,0x28, -0x0E,0x28,0x14,0x28,0x1A,0x28,0x30,0x28,0x6C,0x28,0xE8,0x34,0x0A,0x35,0x7A,0x28, -0xA0,0x28,0xB4,0x28,0xC0,0x28,0xC8,0x28,0x36,0x35,0x44,0x35,0x4E,0x35,0xD0,0x28, -0xA2,0x29,0xAA,0x29,0xB0,0x29,0xC2,0x29,0x54,0x35,0x5A,0x35,0xD2,0x29,0xDE,0x29, -0x70,0x35,0xEA,0x29,0xF4,0x29,0xFE,0x29,0x92,0x35,0x18,0x2A,0x9E,0x35,0x3C,0x2A, -0x44,0x2A,0x4A,0x2A,0xAC,0x35,0x5E,0x2A,0xDA,0x35,0x6A,0x2A,0x88,0x2A,0x9A,0x2A, -0xAE,0x2A,0xC0,0x2A,0xD4,0x2A,0xE2,0x35,0xEC,0x2A,0x06,0x2B,0x06,0x36,0x1A,0x2B, -0x2E,0x2B,0x66,0x2B,0x10,0x36,0x1C,0x36,0x28,0x36,0x36,0x36,0xCA,0x2B,0x90,0x36, -0x22,0x2C,0x44,0x2C,0x98,0x36,0x52,0x28,0xC0,0x26,0xC0,0x26,0xB6,0x2E,0xCA,0x2E, -0xD2,0x2E,0xDA,0x2E,0xE2,0x2E,0xEC,0x2E,0xF4,0x2E,0xFC,0x2E,0x04,0x2F,0x0C,0x2F, -0x24,0x2F,0xA0,0x34,0xA8,0x34,0xB4,0x34,0x32,0x2F,0x6E,0x2F,0x76,0x2F,0x8A,0x2F, -0x96,0x2F,0xAA,0x2F,0xB6,0x2F,0xCA,0x2F,0xD6,0x2F,0xEA,0x2F,0xF6,0x2F,0xFE,0x2F, -0xCE,0x34,0xC0,0x26,0x06,0x30,0x12,0x30,0x1A,0x30,0x26,0x30,0x2E,0x30,0x44,0x30, -0x86,0x30,0xE8,0x34,0x0A,0x35,0x8C,0x30,0xB0,0x30,0xB8,0x30,0xCC,0x30,0xD4,0x30, -0x36,0x35,0x44,0x35,0x4E,0x35,0xDC,0x30,0xA4,0x31,0xA4,0x31,0xA6,0x31,0xDC,0x31, -0x54,0x35,0x5A,0x35,0xEC,0x31,0xF8,0x31,0x70,0x35,0x04,0x32,0x0E,0x32,0x18,0x32, -0x92,0x35,0x2C,0x32,0x9E,0x35,0x56,0x32,0x6E,0x32,0x7C,0x32,0xAC,0x35,0x80,0x32, -0xDA,0x35,0x8C,0x32,0xA8,0x32,0xBA,0x32,0xCE,0x32,0xE0,0x32,0xF0,0x32,0xE2,0x35, -0xF4,0x32,0x08,0x33,0x06,0x36,0x14,0x33,0x7C,0x33,0xC0,0x33,0x10,0x36,0x1C,0x36, -0x28,0x36,0x36,0x36,0x3E,0x34,0x90,0x36,0x8C,0x34,0x92,0x34,0x98,0x36,0x6E,0x30, -0xE3,0x28,0xF7,0x46,0x38,0x40,0x00,0x75,0x32,0xE8,0xFD,0xE8,0x33,0xC0,0xAC,0x49, -0x3D,0x5B,0x00,0x77,0x19,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0xB0,0x36,0x72,0x0B, -0x85,0xC9,0x75,0xE8,0x8B,0x46,0x48,0xE8,0x1A,0x0C,0xC3,0x4E,0x41,0xC3,0x6A,0x00, -0x1F,0xC6,0x06,0x93,0x12,0x0C,0x9C,0x0E,0xE8,0x7D,0xDA,0xE8,0xD6,0xE8,0x33,0xC0, -0xAC,0x49,0x3D,0x5B,0x00,0x77,0xE7,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0x68,0x37, -0x72,0xD9,0x85,0xC9,0x75,0xE8,0xC3,0xF7,0x46,0x7A,0x10,0x00,0x75,0x0F,0x83,0xBE, -0x84,0x00,0x00,0x74,0x08,0xB8,0x2A,0x3A,0x89,0x86,0x80,0x00,0xC3,0x81,0xBE,0x80, -0x00,0xCE,0x3C,0x74,0xF7,0x83,0xBE,0x88,0x00,0x00,0x75,0x05,0xB8,0xCE,0x3C,0xEB, -0xE7,0xF7,0x46,0x7A,0x08,0x00,0x75,0x40,0x1E,0x60,0x8B,0x8E,0x88,0x00,0x3B,0x4E, -0x74,0x77,0x33,0x3B,0x4E,0x78,0x77,0x2E,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D, -0x47,0x47,0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xF4,0x00,0x8B,0xC1,0xF7,0x46,0x7A,0x01, -0x00,0x75,0x1D,0xF3,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46, -0x74,0xB0,0x0C,0xE8,0x58,0xD7,0x61,0x1F,0xC7,0x86,0x88,0x00,0x00,0x00,0xEB,0xAC, -0xE3,0xE3,0x50,0x90,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB,0xD8,0x90,0x8B,0x8E, -0x88,0x00,0xE3,0x46,0x8B,0x9E,0x8A,0x00,0x85,0xDB,0x74,0x3E,0xBA,0x50,0xFF,0xED, -0x2B,0x86,0x82,0x00,0x3B,0xC3,0x72,0x37,0x8D,0xB6,0xF4,0x00,0xC4,0x7E,0x10,0x8B, -0xDF,0x26,0x03,0x3D,0x47,0x47,0x8B,0xC1,0x16,0x1F,0xF7,0x46,0x7A,0x01,0x00,0x75, -0x24,0xF3,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC7, -0x86,0x88,0x00,0x00,0x00,0xB0,0x0C,0xE8,0xF4,0xD6,0x83,0x66,0x7A,0xF7,0xC3,0xB0, -0x00,0xE8,0xEA,0xD6,0xC3,0xE3,0xDC,0x50,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB, -0xD2,0x90,0x1E,0x60,0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xFD,0x00,0x8B,0x86,0x88,0x00, -0x8B,0x96,0x84,0x00,0x3A,0x04,0x75,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D,0xBE,0xF4, -0x00,0xF3,0xA6,0x74,0x66,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6,0x8D,0xB6, -0xFD,0x00,0x8B,0x96,0x84,0x00,0x3A,0x04,0x73,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D, -0xBE,0xF4,0x00,0xF3,0xA6,0x74,0x76,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6, -0x8D,0xB6,0xF4,0x00,0xAC,0xF7,0x46,0x7A,0x01,0x00,0x74,0x02,0x24,0x7F,0x1E,0xC5, -0x5E,0x10,0x8B,0x37,0x88,0x40,0x02,0x46,0x89,0x37,0xFF,0x4E,0x78,0xFF,0x46,0x76, -0xFF,0x4E,0x74,0x1F,0x8B,0x8E,0x88,0x00,0x49,0x89,0x8E,0x88,0x00,0xE3,0x43,0x8D, -0xB6,0xF4,0x00,0x8B,0xFE,0x46,0xF3,0xA4,0xE9,0x7D,0xFF,0xC5,0x76,0x10,0x8B,0x1C, -0x85,0xDB,0x74,0x08,0x03,0xF3,0x83,0xC6,0x03,0x83,0xE6,0xFE,0x8B,0x86,0x84,0x00, -0x2B,0xC2,0xB4,0x80,0x89,0x04,0x46,0x46,0xC7,0x04,0x00,0x00,0x89,0x76,0x10,0x83, -0x4E,0x7A,0x04,0xC7,0x86,0x88,0x00,0x00,0x00,0x61,0x1F,0xF9,0xC3,0x33,0xC0,0x61, -0x1F,0xC3,0xB0,0x80,0x84,0xC0,0x61,0x1F,0xC3,0x90,0x8B,0x4E,0x78,0x2B,0x8E,0x88, -0x00,0x76,0x27,0x89,0xB6,0x8C,0x00,0x8B,0x5E,0x74,0x3B,0xCB,0x72,0x02,0x8B,0xCB, -0x3B,0xC8,0x72,0x02,0x8B,0xC8,0x8B,0xC1,0xE3,0x44,0x33,0xD2,0x8E,0xC2,0x8B,0xD1, -0x83,0xBE,0x88,0x00,0x00,0x74,0x06,0xE9,0x8E,0x00,0x33,0xC0,0xC3,0x8B,0x5E,0x10, -0x03,0x1F,0x43,0x43,0x52,0xF7,0x46,0x7A,0x01,0x00,0x75,0x2A,0xAC,0x8D,0xBE,0xE4, -0x00,0x8B,0x8E,0x86,0x00,0xF2,0xAE,0x74,0x34,0x88,0x07,0x43,0x4A,0x75,0xED,0x58, -0x8B,0x5E,0x10,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x8B,0xC6, -0x2B,0x86,0x8C,0x00,0xC3,0x90,0xAC,0x8D,0xBE,0xE4,0x00,0x8B,0x8E,0x86,0x00,0xF2, -0xAE,0x74,0x0A,0x24,0x7F,0x88,0x07,0x43,0x4A,0x75,0xEB,0xEB,0xD2,0x88,0x86,0xF4, -0x00,0xC7,0x86,0x88,0x00,0x01,0x00,0x58,0x2B,0xC2,0x74,0x0E,0x8B,0x5E,0x10,0x01, -0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x40,0xE8,0x94,0xFE,0x72,0xBE, -0x4A,0x75,0x15,0x83,0xBE,0x8A,0x00,0x00,0x74,0xB4,0xBA,0x50,0xFF,0xED,0x89,0x86, -0x82,0x00,0x83,0x4E,0x7A,0x08,0xEB,0xA6,0x8D,0xBE,0xF4,0x00,0x03,0xBE,0x88,0x00, -0xA4,0xFF,0x86,0x88,0x00,0xE8,0x6A,0xFE,0x72,0x94,0x79,0x06,0x4A,0x74,0x8F,0xE9, -0x5B,0xFF,0x4A,0x74,0xCE,0xEB,0xE1,0x90,0x50,0xE8,0x2B,0xCC,0x8B,0x46,0x74,0x39, -0x46,0x72,0x74,0x27,0x1E,0x56,0x51,0x33,0xC9,0xC5,0x76,0x0C,0xAD,0x74,0x10,0x78, -0x09,0x03,0xC8,0x05,0x01,0x00,0x24,0xFE,0x03,0xF0,0x3B,0x76,0x10,0x76,0xED,0x29, -0x4E,0x76,0x01,0x4E,0x78,0xE8,0x51,0xCC,0x59,0x5E,0x1F,0x58,0xC3,0x90,0xC4,0x7E, -0x10,0x26,0x8B,0x1D,0x83,0xC3,0x03,0x26,0x89,0x1D,0x4B,0x03,0xFB,0xAB,0x91,0xAA, -0xB8,0x03,0x00,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC3,0x90,0xC4,0x7E, -0x10,0x26,0x8B,0x1D,0x43,0x26,0x89,0x1D,0x43,0x03,0xFB,0xAA,0xFF,0x4E,0x78,0xFF, -0x46,0x76,0xFF,0x4E,0x74,0xC3,0xE8,0xE5,0xFF,0xC3,0x80,0x81,0x84,0x85,0x82,0x83, -0x86,0x87,0x50,0x53,0x8A,0xDC,0x83,0xE3,0x0E,0xD1,0xEB,0x2E,0x8A,0x87,0x7A,0x3B, -0x08,0x86,0xB0,0x00,0xFE,0x86,0xB1,0x00,0xB0,0x0A,0xE8,0xA1,0xD4,0x5B,0x58,0xC3, -0x50,0x8A,0xC8,0xB8,0xFF,0x00,0xE8,0x95,0xFF,0x58,0xC3,0x90,0x8A,0x86,0xBB,0x00, -0xE8,0xAB,0xFF,0xC3,0xE8,0xCB,0xFF,0xE8,0xF2,0xFF,0xC3,0x90,0xE8,0xC3,0xFF,0xE8, -0xB4,0xFF,0xC3,0x90,0x33,0xC0,0xE8,0x95,0xFF,0xC3,0xB8,0xFF,0x00,0x33,0xC9,0xE8, -0x6C,0xFF,0xC3,0x90,0xB8,0xFF,0x01,0xB1,0x10,0xE8,0x62,0xFF,0xC3,0x90,0xC3,0xDE, -0x3B,0xC4,0x3B,0xD4,0x3B,0xD4,0x3B,0xDE,0x3B,0xC4,0x3B,0xCA,0x3B,0xCA,0x3B,0xDE, -0x3B,0xC4,0x3B,0xCA,0x3B,0xCA,0x3B,0xDE,0x3B,0xC4,0x3B,0xC4,0x3B,0xC4,0x3B,0x00, -0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00, -0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00, -0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x51, -0x53,0x8B,0x4E,0x38,0x81,0xE1,0xFF,0xEE,0xA8,0x04,0x74,0x04,0x81,0xC9,0x00,0x01, -0x8A,0xE0,0x80,0xE4,0x03,0x24,0x18,0xD0,0xE4,0x0A,0xC4,0x33,0xDB,0x8A,0xD8,0x2E, -0x8B,0x87,0xDF,0x3B,0x89,0x46,0x7C,0x2E,0x0B,0x8F,0xFF,0x3B,0x89,0x4E,0x38,0xD1, -0xEB,0x2E,0x8A,0xA7,0x1F,0x3C,0x5B,0x59,0xC3,0xAC,0x49,0x3C,0x01,0x72,0x1D,0x74, -0x20,0x3C,0x03,0x72,0x23,0x74,0x28,0x3C,0x08,0x72,0x2B,0x74,0x30,0x3C,0x20,0x72, -0x37,0x74,0x3A,0xBB,0xBC,0x3B,0x32,0xE4,0x89,0x5E,0x7E,0xC3,0xBB,0x82,0x3B,0xEB, -0xF5,0xBB,0x76,0x3B,0xB4,0x01,0xEB,0xF0,0xBB,0xDE,0x3B,0xB4,0x02,0xEB,0xE9,0xBB, -0xC4,0x3B,0xB4,0x03,0xEB,0xE2,0xBB,0xA0,0x3B,0xB4,0x04,0xEB,0xDB,0xBB,0xAC,0x3B, -0xAC,0x49,0x88,0x86,0xBB,0x00,0xEB,0xCE,0xBB,0xB4,0x3B,0xEB,0xF3,0xBB,0xDE,0x3B, -0xEB,0xC4,0xA9,0x04,0x00,0x75,0xD1,0xA9,0x08,0x00,0x75,0xDA,0xEB,0xD1,0x8B,0x5E, -0x74,0x8B,0x4E,0x78,0x3B,0xCB,0x72,0x02,0x8B,0xCB,0x3B,0xC8,0x72,0x02,0x8B,0xC8, -0x8B,0xC1,0xE3,0x2C,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D,0x47,0x47,0xF7,0x46, -0x7A,0x01,0x00,0x75,0x1C,0xF7,0xC7,0x01,0x00,0x74,0x02,0x49,0xA4,0xD1,0xE9,0xF3, -0xA5,0x73,0x01,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74, -0xC3,0x50,0x53,0xBB,0x7F,0x7F,0xF7,0xC7,0x01,0x00,0x74,0x05,0x49,0xAC,0x22,0xC3, -0xAA,0xD1,0xE9,0xE3,0x1D,0x9C,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x14,0xAD,0x23,0xC3, -0xAB,0x49,0x74,0x0D,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x06,0xAD,0x23,0xC3,0xAB,0xE2, -0xE5,0x9D,0x73,0x04,0xAC,0x22,0xC3,0xAB,0x5B,0x58,0xEB,0xB8,0xE8,0xE8,0xC9,0x8B, -0x5E,0x38,0xF7,0xC3,0x10,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x40,0x00,0x74,0x05,0xE8, -0xD2,0xE3,0xEB,0x03,0xE8,0xC2,0xE3,0x81,0x66,0x38,0xEF,0xFB,0xF6,0xC3,0x10,0x74, -0x3C,0xF6,0xC3,0x02,0x74,0x06,0xE4,0xD8,0x0C,0x01,0xE6,0xD8,0xF6,0xC3,0x04,0x74, -0x11,0x83,0xC2,0x08,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEE,0x88,0x86,0xA7,0x00,0x83, -0xEA,0x08,0xF6,0xC3,0x08,0x74,0x0F,0xE8,0xA5,0xE3,0x72,0x0A,0x8A,0x86,0xC0,0x00, -0xE6,0x38,0xB0,0x23,0xE6,0x0A,0xF7,0xC3,0x00,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x00, -0x08,0x75,0xF9,0x8A,0x86,0xA5,0x00,0xF6,0xC3,0x40,0x75,0x0D,0xA8,0x10,0x75,0xEC, -0x0C,0x10,0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x01,0x75,0xDF,0x83,0xC2,0x02, -0x0C,0x05,0xEE,0x88,0x86,0xA5,0x00,0xC3,0xB0,0x00,0xE8,0x61,0xD2,0xEB,0x0F,0xB0, -0x02,0xE8,0x90,0x0E,0xEB,0x08,0x83,0x66,0x38,0xDF,0x83,0x4E,0x7A,0x02,0x33,0xC0, -0x8E,0xD8,0xFA,0xA0,0x92,0x12,0x40,0xA2,0x92,0x12,0x3C,0x05,0x72,0x1E,0xC6,0x06, -0x92,0x12,0x00,0xFB,0xB0,0x01,0xE8,0x6B,0x0E,0xFA,0xA1,0x26,0x01,0x23,0x06,0x2A, -0x01,0xA8,0x01,0x75,0x07,0xE8,0xE2,0x07,0xE8,0x61,0x09,0x90,0xB0,0x00,0xE8,0x51, -0xD2,0xFB,0x85,0xED,0x74,0xB9,0xFA,0xF7,0x46,0x7A,0x46,0x00,0x75,0xC0,0x8B,0x46, -0x78,0x3D,0x0A,0x00,0x72,0xB0,0x8B,0x4E,0x74,0x83,0xF9,0x50,0x72,0x9A,0x83,0x66, -0x38,0xDF,0xC5,0x76,0x14,0x8B,0x46,0x3A,0x85,0xC0,0x75,0x58,0xAD,0x85,0xC0,0x75, -0x0F,0xE8,0xF8,0xFE,0xF7,0x46,0x7A,0x08,0x00,0x74,0x93,0xE8,0xA0,0xFA,0xEB,0x8E, -0x3B,0x76,0x04,0x76,0x21,0xB9,0x02,0x00,0x39,0x4E,0x2E,0x77,0x05,0xC7,0x46,0x2E, -0x00,0x00,0x56,0x8B,0x76,0x2C,0x89,0x76,0x04,0xC7,0x04,0x00,0x00,0x46,0x46,0x89, -0x76,0x2C,0x29,0x4E,0x2E,0x5E,0x85,0xC0,0x79,0x17,0xF6,0xC4,0x10,0x74,0x05,0xFF, -0x56,0x7C,0xEB,0x03,0xFF,0x56,0x7E,0x89,0x76,0x14,0xB0,0x0C,0xE8,0x9F,0xD1,0xEB, -0x86,0x89,0x46,0x3A,0xFF,0x96,0x80,0x00,0x29,0x46,0x3A,0x89,0x76,0x14,0xB0,0x0C, -0xE8,0x8B,0xD1,0xE9,0x71,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04, -0x10,0x02,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0xE8,0xEF,0xFD,0x36,0xA1,0xB6,0x13,0x25,0x0F,0x00,0xE8,0x03,0xFC,0x36,0xA1,0xB6, +0x13,0xC1,0xE8,0x04,0x25,0x03,0x00,0xE8,0x88,0xFC,0x36,0xA1,0xB6,0x13,0xC1,0xE8, +0x05,0x25,0x02,0x00,0xE8,0xCD,0xFC,0x36,0xA1,0xB6,0x13,0xF6,0xC4,0x01,0x75,0x04, +0x32,0xC0,0xEB,0x09,0x80,0xE4,0x02,0xD0,0xEC,0xB0,0x02,0x2A,0xC4,0xE8,0x8C,0xFC, +0x36,0xF6,0x06,0xB7,0x13,0x40,0x74,0x05,0xE8,0x8D,0xFE,0xEB,0x03,0xE8,0x94,0xFE, +0x36,0xF6,0x06,0xB7,0x13,0x20,0x74,0x05,0xE8,0x69,0xFE,0xEB,0x03,0xE8,0x70,0xFE, +0xF8,0xC3,0xF8,0xC3,0x8B,0x46,0x38,0xA9,0x04,0x00,0x75,0x23,0x0D,0x04,0x00,0x89, +0x46,0x38,0x83,0xC2,0x08,0x8B,0x46,0x2E,0x3B,0x46,0x3C,0x73,0x14,0x83,0x4E,0x38, +0x10,0x8A,0x86,0xA7,0x00,0x24,0xFE,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8, +0xC3,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEB,0xEE,0x90,0x8B,0x46,0x38,0xA9,0x04,0x00, +0x74,0x06,0x25,0xFB,0xFF,0x89,0x46,0x38,0xF8,0xC3,0xAD,0x49,0x49,0xE8,0xBE,0xFB, +0x89,0x86,0x8E,0x00,0xF8,0xC3,0xAD,0x49,0x49,0xE8,0xB2,0xFB,0x89,0x86,0x90,0x00, +0xF8,0xC3,0x83,0x4E,0x26,0x04,0xE8,0x92,0xFA,0xF8,0xC3,0x90,0x83,0x66,0x26,0xFB, +0xE8,0x88,0xFA,0xF8,0xC3,0x90,0xAC,0x49,0x84,0xC0,0x75,0x07,0x80,0x8E,0xA3,0x00, +0x04,0xF8,0xC3,0x80,0xA6,0xA3,0x00,0xFB,0xF8,0xC3,0xAC,0x49,0x83,0xC2,0x08,0x3C, +0x02,0x76,0x02,0x32,0xC0,0x3C,0x01,0x74,0x12,0x77,0x0B,0x8A,0x86,0xA7,0x00,0x24, +0xEF,0x88,0x86,0xA7,0x00,0xEE,0x83,0xEA,0x08,0xF8,0xC3,0x8A,0x86,0xA7,0x00,0x0C, +0x10,0xEB,0xEE,0x90,0x52,0x83,0xC2,0x06,0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x04,0xAC, +0x49,0xEE,0x5A,0x8A,0x86,0xA8,0x00,0xEE,0x5A,0xF8,0xC3,0x90,0x52,0x83,0xC2,0x06, +0xB0,0xBF,0xEE,0x52,0x83,0xC2,0x08,0xEB,0xE6,0x90,0xAC,0x49,0xF8,0xC3,0xAC,0x49, +0xE8,0xB4,0xEE,0x73,0x03,0xE8,0xF7,0xEE,0xF8,0xC3,0x8A,0x86,0xAF,0x00,0x24,0x7F, +0xE8,0xBD,0xF9,0xB8,0xF0,0x00,0xE8,0x66,0xF2,0x81,0x66,0x26,0xFF,0xF3,0xE8,0x23, +0xFA,0xE8,0xD2,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x37,0xF2,0x80,0x4E,0x27,0x08, +0xE8,0x11,0xFA,0xE8,0xC0,0xF9,0xF8,0xC3,0xB8,0x80,0x00,0xE8,0x41,0xF2,0x81,0x66, +0x26,0xFF,0xF7,0xE8,0xFE,0xF9,0xE8,0xAD,0xF9,0xF8,0xC3,0x90,0xB8,0x10,0x00,0xE8, +0x11,0xF2,0x80,0x4E,0x27,0x04,0xE8,0xEB,0xF9,0xE8,0x9A,0xF9,0xF8,0xC3,0xB8,0x10, +0x00,0xE8,0xFF,0xF1,0x81,0x66,0x26,0xFF,0xFB,0xE8,0xD8,0xF9,0xF8,0xC3,0xAC,0x49, +0xF8,0xC3,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x0C,0x40,0x88,0x86,0xA8,0x00,0xEE, +0x83,0xEA,0x06,0xF8,0xC3,0x90,0x83,0xC2,0x06,0x8A,0x86,0xA8,0x00,0x24,0xBF,0xEB, +0xEA,0x90,0xAC,0x49,0x8A,0xE0,0x80,0xC2,0x0A,0xEC,0x80,0xEA,0x0A,0xA8,0x20,0x74, +0x05,0x8A,0xC4,0xEE,0xF8,0xC3,0x06,0x51,0x57,0x8B,0x4E,0x24,0xE3,0x34,0x49,0x89, +0x4E,0x24,0xFF,0x46,0x1A,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x8A,0xC4,0xAA,0x89,0x7E, +0x22,0x8B,0x46,0x26,0x24,0xFD,0x89,0x46,0x26,0x75,0x29,0x8A,0x86,0xA5,0x00,0xA8, +0x02,0x75,0x21,0x80,0xC2,0x02,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x80,0xEA,0x02, +0xEB,0x12,0xC4,0x7E,0x00,0x3B,0x7E,0x1E,0x76,0x0A,0x4F,0x26,0x88,0x25,0x89,0x7E, +0x00,0xFF,0x46,0x1A,0x5F,0x59,0x07,0xF8,0xC3,0x90,0xAC,0xAD,0x83,0xE9,0x03,0x85, +0xC0,0x74,0x05,0x3D,0x00,0x20,0x72,0x05,0xB8,0xFF,0xFF,0xEB,0x03,0xC1,0xE0,0x03, +0x3B,0x86,0x94,0x00,0x74,0x26,0x89,0x86,0x94,0x00,0x8B,0xD8,0x52,0x83,0xC2,0x06, +0x8A,0x86,0xA8,0x00,0x8A,0xE0,0x0C,0x80,0xEE,0x83,0xEA,0x06,0x8A,0xC3,0xEE,0x83, +0xC2,0x02,0x8A,0xC7,0xEE,0x83,0xC2,0x04,0x8A,0xC4,0xEE,0x5A,0xF8,0xC3,0xB0,0x88, +0x88,0x86,0xBC,0x00,0xE8,0x8C,0xF2,0x33,0xDB,0x8A,0x86,0xA5,0x00,0xA8,0x02,0x74, +0x03,0x80,0xCB,0x01,0xA8,0x05,0x74,0x03,0x80,0xCB,0x02,0xA8,0x08,0x74,0x03,0x80, +0xCB,0x04,0xF6,0x86,0xA7,0x00,0x10,0x74,0x03,0x80,0xCB,0x10,0x8A,0x86,0xA9,0x00, +0xF6,0xC3,0x04,0x75,0x0A,0x83,0xC2,0x0C,0xEC,0x83,0xEA,0x0C,0xC0,0xE8,0x04,0x8A, +0xE0,0x8A,0x86,0xAF,0x00,0xA8,0x80,0x74,0x08,0xF6,0xC4,0x01,0x75,0x03,0x80,0xCB, +0x20,0xF6,0x86,0xA7,0x00,0x02,0x75,0x0A,0xF7,0x46,0x38,0x04,0x00,0x74,0x03,0x80, +0xCB,0x40,0x88,0x9E,0xBE,0x00,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0xF3,0xDB,0xF8, +0xC3,0xFE,0x86,0xB4,0x00,0xB0,0x0A,0xE8,0xE8,0xDB,0xF8,0xC3,0xAC,0x49,0x3C,0x02, +0x74,0x37,0x77,0x10,0x84,0xC0,0x74,0x06,0x80,0x4E,0x38,0x01,0xF8,0xC3,0x80,0x66, +0x38,0xFE,0xF8,0xC3,0x8B,0x46,0x38,0x25,0xFF,0xF7,0x89,0x46,0x38,0xA9,0x00,0x04, +0x75,0xEA,0x8A,0x86,0xA5,0x00,0xA8,0x01,0x75,0xE2,0x0C,0x05,0x83,0xC2,0x02,0x88, +0x86,0xA5,0x00,0xEE,0x83,0xEA,0x02,0xF8,0xC3,0x81,0x4E,0x38,0x00,0x08,0x8A,0x86, +0xA5,0x00,0xA8,0x01,0x74,0xC6,0x24,0xFA,0xEB,0xE2,0xAD,0x49,0x49,0xF8,0xC3,0x90, +0xE8,0x11,0xFA,0xFE,0x86,0xB9,0x00,0xB0,0x0E,0xE8,0x86,0xDB,0xF8,0xC3,0xB0,0xFF, +0xE8,0xBF,0xEC,0xF8,0xC3,0x90,0x83,0x66,0x7A,0xFB,0xB0,0x00,0xE8,0x73,0xDB,0xF8, +0xC3,0x90,0xAC,0x49,0xE8,0x53,0xD9,0x72,0x11,0x36,0x88,0x1E,0x1A,0x01,0x36,0xA0, +0x8E,0x12,0x0A,0xC3,0x52,0xBA,0x00,0x01,0xEE,0x5A,0xF8,0xC3,0xAC,0x49,0x32,0xE4, +0x36,0xA3,0x86,0x12,0x05,0x06,0x00,0x36,0x8B,0x1E,0x88,0x12,0x2B,0xD8,0x36,0x89, +0x1E,0x8A,0x12,0xF8,0xC3,0x90,0xAD,0x8B,0xD8,0xAD,0x83,0xE9,0x04,0x03,0xC3,0x2B, +0x46,0x76,0x89,0x46,0x78,0xF7,0x46,0x7A,0x02,0x00,0x74,0x0A,0x83,0x66,0x7A,0xFD, +0xB8,0x00,0x00,0xE8,0x1C,0xDB,0xF8,0xC3,0x06,0x16,0x07,0xAC,0x49,0x25,0x0F,0x00, +0x6B,0xC0,0x09,0x8D,0xBE,0xFD,0x00,0x03,0xF8,0xAC,0x49,0x25,0x0F,0x00,0xAA,0x85, +0xC0,0x74,0x08,0x2B,0xC8,0x51,0x8B,0xC8,0xF3,0xA4,0x59,0xE8,0x27,0xF0,0xE8,0x44, +0x03,0x07,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0xB2,0x13,0x36,0xA3,0xB0,0x13, +0xF8,0xC3,0x83,0x66,0x7A,0xEF,0xE8,0x2C,0x03,0xF8,0xC3,0x90,0x83,0x4E,0x7A,0x10, +0xEB,0xF4,0xE8,0x9B,0xF0,0xF8,0xC3,0x90,0xAD,0x3C,0x19,0x77,0x0E,0x3C,0x19,0x77, +0x0A,0x8B,0xF8,0x81,0xE7,0xFF,0x00,0x88,0xA6,0xC4,0x00,0xF8,0xC3,0x90,0x83,0x4E, +0x26,0x20,0xAC,0x49,0x32,0xE4,0xD1,0xE0,0x8B,0xD8,0xC1,0xE3,0x02,0x03,0xC3,0x89, +0x46,0x6E,0x83,0x4E,0x48,0x04,0xB0,0x06,0xE8,0x97,0xDA,0x49,0x46,0xF9,0xC3,0x90, +0xFE,0x86,0xB3,0x00,0xB0,0x0A,0xE8,0x89,0xDA,0xF8,0xC3,0x90,0x33,0xC0,0xAC,0x49, +0x6B,0xC0,0x0A,0x89,0x86,0x8A,0x00,0xF8,0xC3,0x90,0xAC,0x49,0x32,0xE4,0x3D,0x0A, +0x00,0x77,0x05,0xB8,0x0A,0x00,0xEB,0x08,0x3D,0x5A,0x00,0x72,0x03,0xB8,0x5A,0x00, +0x51,0xF7,0xD8,0x05,0x64,0x00,0x8B,0xC8,0x8B,0x46,0x44,0xF7,0xE1,0xB9,0x64,0x00, +0xF7,0xF1,0x89,0x46,0x46,0x59,0xF8,0xC3,0xAC,0x49,0xE8,0x85,0xEB,0xF8,0xC3,0x90, +0xAC,0x49,0x84,0xC0,0x75,0x07,0x81,0x66,0x38,0xFF,0xFD,0xF8,0xC3,0x81,0x4E,0x38, +0x00,0x02,0xF7,0x46,0x38,0x40,0x00,0x75,0x08,0x8A,0x86,0xA9,0x00,0x88,0x86,0xAA, +0x00,0xF8,0xC3,0x90,0x51,0x56,0xE8,0x7F,0x0C,0x5E,0x59,0xF8,0xC3,0x90,0xFE,0x86, +0xB6,0x00,0xB0,0x0A,0xE8,0x0B,0xDA,0xF8,0xC3,0x90,0xFE,0x86,0xB7,0x00,0xB0,0x0A, +0xE8,0xFF,0xD9,0xF8,0xC3,0x90,0xFE,0x86,0xB8,0x00,0xB0,0x0A,0xE8,0xF3,0xD9,0xF8, +0xC3,0x90,0x00,0x90,0x51,0x55,0xAC,0x2E,0xA2,0x52,0x36,0x33,0xC9,0xAD,0x8B,0xF9, +0xC1,0xE7,0x05,0xA9,0x01,0x00,0x74,0x23,0x2E,0x8B,0xAD,0x44,0x00,0x83,0x7E,0x08, +0x00,0x74,0x18,0x2E,0x80,0x3E,0x52,0x36,0x01,0x74,0x09,0x60,0xB0,0x04,0xE8,0xBB, +0x0C,0x61,0xEB,0x07,0x60,0xB0,0xFB,0xE8,0xEC,0x0C,0x61,0x47,0x47,0xD1,0xE8,0x75, +0xD2,0x41,0x83,0xF9,0x04,0x72,0xC6,0x5D,0x59,0x83,0xE9,0x05,0xF7,0x46,0x38,0x40, +0x00,0x74,0x05,0xE8,0x87,0xEA,0xF8,0xC3,0xE8,0x8D,0xEA,0xF8,0xC3,0x90,0x36,0xC6, +0x06,0xC8,0x13,0x01,0xF8,0xC3,0x33,0xC0,0xAC,0x49,0x36,0xA3,0x80,0x12,0xAC,0x49, +0x36,0x2B,0x06,0x88,0x12,0xF7,0xD8,0x36,0xA3,0x82,0x12,0xF8,0xC3,0x90,0xDE,0x26, +0xDE,0x26,0xEC,0x26,0xF2,0x26,0xF8,0x26,0xFE,0x26,0x04,0x27,0x0E,0x27,0x16,0x27, +0x1E,0x27,0x26,0x27,0x2E,0x27,0x34,0x27,0xBE,0x34,0xC6,0x34,0xD2,0x34,0x3A,0x27, +0x78,0x27,0x80,0x27,0x94,0x27,0xA0,0x27,0xB4,0x27,0xC0,0x27,0xD4,0x27,0xE0,0x27, +0xF4,0x27,0x00,0x28,0x10,0x28,0xEC,0x34,0xDE,0x26,0x1E,0x28,0x26,0x28,0x2C,0x28, +0x32,0x28,0x38,0x28,0x4E,0x28,0x8A,0x28,0x06,0x35,0x28,0x35,0x98,0x28,0xBE,0x28, +0xD2,0x28,0xDE,0x28,0xE6,0x28,0x54,0x35,0x62,0x35,0x6C,0x35,0xEE,0x28,0xC0,0x29, +0xC8,0x29,0xCE,0x29,0xE0,0x29,0x72,0x35,0x78,0x35,0xF0,0x29,0xFC,0x29,0x8E,0x35, +0x08,0x2A,0x12,0x2A,0x1C,0x2A,0xB0,0x35,0x36,0x2A,0xBC,0x35,0x5A,0x2A,0x62,0x2A, +0x68,0x2A,0xCA,0x35,0x7C,0x2A,0xF8,0x35,0x88,0x2A,0xA6,0x2A,0xB8,0x2A,0xCC,0x2A, +0xDE,0x2A,0xF2,0x2A,0x00,0x36,0x0A,0x2B,0x24,0x2B,0x24,0x36,0x38,0x2B,0x4C,0x2B, +0x84,0x2B,0x2E,0x36,0x3A,0x36,0x46,0x36,0x54,0x36,0xE8,0x2B,0xAE,0x36,0x40,0x2C, +0x62,0x2C,0xB6,0x36,0x70,0x28,0xDE,0x26,0xDE,0x26,0xD4,0x2E,0xE8,0x2E,0xF0,0x2E, +0xF8,0x2E,0x00,0x2F,0x0A,0x2F,0x12,0x2F,0x1A,0x2F,0x22,0x2F,0x2A,0x2F,0x42,0x2F, +0xBE,0x34,0xC6,0x34,0xD2,0x34,0x50,0x2F,0x8C,0x2F,0x94,0x2F,0xA8,0x2F,0xB4,0x2F, +0xC8,0x2F,0xD4,0x2F,0xE8,0x2F,0xF4,0x2F,0x08,0x30,0x14,0x30,0x1C,0x30,0xEC,0x34, +0xDE,0x26,0x24,0x30,0x30,0x30,0x38,0x30,0x44,0x30,0x4C,0x30,0x62,0x30,0xA4,0x30, +0x06,0x35,0x28,0x35,0xAA,0x30,0xCE,0x30,0xD6,0x30,0xEA,0x30,0xF2,0x30,0x54,0x35, +0x62,0x35,0x6C,0x35,0xFA,0x30,0xC2,0x31,0xC2,0x31,0xC4,0x31,0xFA,0x31,0x72,0x35, +0x78,0x35,0x0A,0x32,0x16,0x32,0x8E,0x35,0x22,0x32,0x2C,0x32,0x36,0x32,0xB0,0x35, +0x4A,0x32,0xBC,0x35,0x74,0x32,0x8C,0x32,0x9A,0x32,0xCA,0x35,0x9E,0x32,0xF8,0x35, +0xAA,0x32,0xC6,0x32,0xD8,0x32,0xEC,0x32,0xFE,0x32,0x0E,0x33,0x00,0x36,0x12,0x33, +0x26,0x33,0x24,0x36,0x32,0x33,0x9A,0x33,0xDE,0x33,0x2E,0x36,0x3A,0x36,0x46,0x36, +0x54,0x36,0x5C,0x34,0xAE,0x36,0xAA,0x34,0xB0,0x34,0xB6,0x36,0x8C,0x30,0xE3,0x28, +0xF7,0x46,0x38,0x40,0x00,0x75,0x32,0xE8,0xE3,0xE8,0x33,0xC0,0xAC,0x49,0x3D,0x5B, +0x00,0x77,0x19,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0xCE,0x36,0x72,0x0B,0x85,0xC9, +0x75,0xE8,0x8B,0x46,0x48,0xE8,0x1A,0x0C,0xC3,0x4E,0x41,0xC3,0x6A,0x00,0x1F,0xC6, +0x06,0x93,0x12,0x0C,0x9C,0x0E,0xE8,0x63,0xDA,0xE8,0xBC,0xE8,0x33,0xC0,0xAC,0x49, +0x3D,0x5B,0x00,0x77,0xE7,0x8B,0xD8,0xD1,0xE3,0x2E,0xFF,0x97,0x86,0x37,0x72,0xD9, +0x85,0xC9,0x75,0xE8,0xC3,0xF7,0x46,0x7A,0x10,0x00,0x75,0x0F,0x83,0xBE,0x84,0x00, +0x00,0x74,0x08,0xB8,0x48,0x3A,0x89,0x86,0x80,0x00,0xC3,0x81,0xBE,0x80,0x00,0xEC, +0x3C,0x74,0xF7,0x83,0xBE,0x88,0x00,0x00,0x75,0x05,0xB8,0xEC,0x3C,0xEB,0xE7,0xF7, +0x46,0x7A,0x08,0x00,0x75,0x40,0x1E,0x60,0x8B,0x8E,0x88,0x00,0x3B,0x4E,0x74,0x77, +0x33,0x3B,0x4E,0x78,0x77,0x2E,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D,0x47,0x47, +0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xF4,0x00,0x8B,0xC1,0xF7,0x46,0x7A,0x01,0x00,0x75, +0x1D,0xF3,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xB0, +0x0C,0xE8,0x3E,0xD7,0x61,0x1F,0xC7,0x86,0x88,0x00,0x00,0x00,0xEB,0xAC,0xE3,0xE3, +0x50,0x90,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB,0xD8,0x90,0x8B,0x8E,0x88,0x00, +0xE3,0x46,0x8B,0x9E,0x8A,0x00,0x85,0xDB,0x74,0x3E,0xBA,0x50,0xFF,0xED,0x2B,0x86, +0x82,0x00,0x3B,0xC3,0x72,0x37,0x8D,0xB6,0xF4,0x00,0xC4,0x7E,0x10,0x8B,0xDF,0x26, +0x03,0x3D,0x47,0x47,0x8B,0xC1,0x16,0x1F,0xF7,0x46,0x7A,0x01,0x00,0x75,0x24,0xF3, +0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC7,0x86,0x88, +0x00,0x00,0x00,0xB0,0x0C,0xE8,0xDA,0xD6,0x83,0x66,0x7A,0xF7,0xC3,0xB0,0x00,0xE8, +0xD0,0xD6,0xC3,0xE3,0xDC,0x50,0xAC,0x24,0x7F,0xAA,0xE2,0xFA,0x58,0xEB,0xD2,0x90, +0x1E,0x60,0x33,0xC0,0x8E,0xD8,0x8D,0xB6,0xFD,0x00,0x8B,0x86,0x88,0x00,0x8B,0x96, +0x84,0x00,0x3A,0x04,0x75,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D,0xBE,0xF4,0x00,0xF3, +0xA6,0x74,0x66,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6,0x8D,0xB6,0xFD,0x00, +0x8B,0x96,0x84,0x00,0x3A,0x04,0x73,0x10,0x8B,0xDE,0x46,0x8B,0xC8,0x8D,0xBE,0xF4, +0x00,0xF3,0xA6,0x74,0x76,0x8B,0xF3,0x90,0x83,0xC6,0x09,0x4A,0x75,0xE6,0x8D,0xB6, +0xF4,0x00,0xAC,0xF7,0x46,0x7A,0x01,0x00,0x74,0x02,0x24,0x7F,0x1E,0xC5,0x5E,0x10, +0x8B,0x37,0x88,0x40,0x02,0x46,0x89,0x37,0xFF,0x4E,0x78,0xFF,0x46,0x76,0xFF,0x4E, +0x74,0x1F,0x8B,0x8E,0x88,0x00,0x49,0x89,0x8E,0x88,0x00,0xE3,0x43,0x8D,0xB6,0xF4, +0x00,0x8B,0xFE,0x46,0xF3,0xA4,0xE9,0x7D,0xFF,0xC5,0x76,0x10,0x8B,0x1C,0x85,0xDB, +0x74,0x08,0x03,0xF3,0x83,0xC6,0x03,0x83,0xE6,0xFE,0x8B,0x86,0x84,0x00,0x2B,0xC2, +0xB4,0x80,0x89,0x04,0x46,0x46,0xC7,0x04,0x00,0x00,0x89,0x76,0x10,0x83,0x4E,0x7A, +0x04,0xC7,0x86,0x88,0x00,0x00,0x00,0x61,0x1F,0xF9,0xC3,0x33,0xC0,0x61,0x1F,0xC3, +0xB0,0x80,0x84,0xC0,0x61,0x1F,0xC3,0x90,0x8B,0x4E,0x78,0x2B,0x8E,0x88,0x00,0x76, +0x27,0x89,0xB6,0x8C,0x00,0x8B,0x5E,0x74,0x3B,0xCB,0x72,0x02,0x8B,0xCB,0x3B,0xC8, +0x72,0x02,0x8B,0xC8,0x8B,0xC1,0xE3,0x44,0x33,0xD2,0x8E,0xC2,0x8B,0xD1,0x83,0xBE, +0x88,0x00,0x00,0x74,0x06,0xE9,0x8E,0x00,0x33,0xC0,0xC3,0x8B,0x5E,0x10,0x03,0x1F, +0x43,0x43,0x52,0xF7,0x46,0x7A,0x01,0x00,0x75,0x2A,0xAC,0x8D,0xBE,0xE4,0x00,0x8B, +0x8E,0x86,0x00,0xF2,0xAE,0x74,0x34,0x88,0x07,0x43,0x4A,0x75,0xED,0x58,0x8B,0x5E, +0x10,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x8B,0xC6,0x2B,0x86, +0x8C,0x00,0xC3,0x90,0xAC,0x8D,0xBE,0xE4,0x00,0x8B,0x8E,0x86,0x00,0xF2,0xAE,0x74, +0x0A,0x24,0x7F,0x88,0x07,0x43,0x4A,0x75,0xEB,0xEB,0xD2,0x88,0x86,0xF4,0x00,0xC7, +0x86,0x88,0x00,0x01,0x00,0x58,0x2B,0xC2,0x74,0x0E,0x8B,0x5E,0x10,0x01,0x07,0x29, +0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0x40,0xE8,0x94,0xFE,0x72,0xBE,0x4A,0x75, +0x15,0x83,0xBE,0x8A,0x00,0x00,0x74,0xB4,0xBA,0x50,0xFF,0xED,0x89,0x86,0x82,0x00, +0x83,0x4E,0x7A,0x08,0xEB,0xA6,0x8D,0xBE,0xF4,0x00,0x03,0xBE,0x88,0x00,0xA4,0xFF, +0x86,0x88,0x00,0xE8,0x6A,0xFE,0x72,0x94,0x79,0x06,0x4A,0x74,0x8F,0xE9,0x5B,0xFF, +0x4A,0x74,0xCE,0xEB,0xE1,0x90,0x50,0xE8,0x11,0xCC,0x8B,0x46,0x74,0x39,0x46,0x72, +0x74,0x27,0x1E,0x56,0x51,0x33,0xC9,0xC5,0x76,0x0C,0xAD,0x74,0x10,0x78,0x09,0x03, +0xC8,0x05,0x01,0x00,0x24,0xFE,0x03,0xF0,0x3B,0x76,0x10,0x76,0xED,0x29,0x4E,0x76, +0x01,0x4E,0x78,0xE8,0x37,0xCC,0x59,0x5E,0x1F,0x58,0xC3,0x90,0xC4,0x7E,0x10,0x26, +0x8B,0x1D,0x83,0xC3,0x03,0x26,0x89,0x1D,0x4B,0x03,0xFB,0xAB,0x91,0xAA,0xB8,0x03, +0x00,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC3,0x90,0xC4,0x7E,0x10,0x26, +0x8B,0x1D,0x43,0x26,0x89,0x1D,0x43,0x03,0xFB,0xAA,0xFF,0x4E,0x78,0xFF,0x46,0x76, +0xFF,0x4E,0x74,0xC3,0xE8,0xE5,0xFF,0xC3,0x80,0x81,0x84,0x85,0x82,0x83,0x86,0x87, +0x50,0x53,0x8A,0xDC,0x83,0xE3,0x0E,0xD1,0xEB,0x2E,0x8A,0x87,0x98,0x3B,0x08,0x86, +0xB0,0x00,0xFE,0x86,0xB1,0x00,0xB0,0x0A,0xE8,0x87,0xD4,0x5B,0x58,0xC3,0x50,0x8A, +0xC8,0xB8,0xFF,0x00,0xE8,0x95,0xFF,0x58,0xC3,0x90,0x8A,0x86,0xBB,0x00,0xE8,0xAB, +0xFF,0xC3,0xE8,0xCB,0xFF,0xE8,0xF2,0xFF,0xC3,0x90,0xE8,0xC3,0xFF,0xE8,0xB4,0xFF, +0xC3,0x90,0x33,0xC0,0xE8,0x95,0xFF,0xC3,0xB8,0xFF,0x00,0x33,0xC9,0xE8,0x6C,0xFF, +0xC3,0x90,0xB8,0xFF,0x01,0xB1,0x10,0xE8,0x62,0xFF,0xC3,0x90,0xC3,0xFC,0x3B,0xE2, +0x3B,0xF2,0x3B,0xF2,0x3B,0xFC,0x3B,0xE2,0x3B,0xE8,0x3B,0xE8,0x3B,0xFC,0x3B,0xE2, +0x3B,0xE8,0x3B,0xE8,0x3B,0xFC,0x3B,0xE2,0x3B,0xE2,0x3B,0xE2,0x3B,0x00,0x10,0x00, +0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00, +0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x08,0x00, +0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x51,0x53,0x8B, +0x4E,0x38,0x81,0xE1,0xFF,0xEE,0xA8,0x04,0x74,0x04,0x81,0xC9,0x00,0x01,0x8A,0xE0, +0x80,0xE4,0x03,0x24,0x18,0xD0,0xE4,0x0A,0xC4,0x33,0xDB,0x8A,0xD8,0x2E,0x8B,0x87, +0xFD,0x3B,0x89,0x46,0x7C,0x2E,0x0B,0x8F,0x1D,0x3C,0x89,0x4E,0x38,0xD1,0xEB,0x2E, +0x8A,0xA7,0x3D,0x3C,0x5B,0x59,0xC3,0xAC,0x49,0x3C,0x01,0x72,0x1D,0x74,0x20,0x3C, +0x03,0x72,0x23,0x74,0x28,0x3C,0x08,0x72,0x2B,0x74,0x30,0x3C,0x20,0x72,0x37,0x74, +0x3A,0xBB,0xDA,0x3B,0x32,0xE4,0x89,0x5E,0x7E,0xC3,0xBB,0xA0,0x3B,0xEB,0xF5,0xBB, +0x94,0x3B,0xB4,0x01,0xEB,0xF0,0xBB,0xFC,0x3B,0xB4,0x02,0xEB,0xE9,0xBB,0xE2,0x3B, +0xB4,0x03,0xEB,0xE2,0xBB,0xBE,0x3B,0xB4,0x04,0xEB,0xDB,0xBB,0xCA,0x3B,0xAC,0x49, +0x88,0x86,0xBB,0x00,0xEB,0xCE,0xBB,0xD2,0x3B,0xEB,0xF3,0xBB,0xFC,0x3B,0xEB,0xC4, +0xA9,0x04,0x00,0x75,0xD1,0xA9,0x08,0x00,0x75,0xDA,0xEB,0xD1,0x8B,0x5E,0x74,0x8B, +0x4E,0x78,0x3B,0xCB,0x72,0x02,0x8B,0xCB,0x3B,0xC8,0x72,0x02,0x8B,0xC8,0x8B,0xC1, +0xE3,0x2C,0xC4,0x7E,0x10,0x8B,0xDF,0x26,0x03,0x3D,0x47,0x47,0xF7,0x46,0x7A,0x01, +0x00,0x75,0x1C,0xF7,0xC7,0x01,0x00,0x74,0x02,0x49,0xA4,0xD1,0xE9,0xF3,0xA5,0x73, +0x01,0xA4,0x26,0x01,0x07,0x29,0x46,0x78,0x01,0x46,0x76,0x29,0x46,0x74,0xC3,0x50, +0x53,0xBB,0x7F,0x7F,0xF7,0xC7,0x01,0x00,0x74,0x05,0x49,0xAC,0x22,0xC3,0xAA,0xD1, +0xE9,0xE3,0x1D,0x9C,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x14,0xAD,0x23,0xC3,0xAB,0x49, +0x74,0x0D,0xAD,0x23,0xC3,0xAB,0x49,0x74,0x06,0xAD,0x23,0xC3,0xAB,0xE2,0xE5,0x9D, +0x73,0x04,0xAC,0x22,0xC3,0xAB,0x5B,0x58,0xEB,0xB8,0xE8,0xCE,0xC9,0x8B,0x5E,0x38, +0xF7,0xC3,0x10,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x40,0x00,0x74,0x05,0xE8,0xB8,0xE3, +0xEB,0x03,0xE8,0xA8,0xE3,0x81,0x66,0x38,0xEF,0xFB,0xF6,0xC3,0x10,0x74,0x3C,0xF6, +0xC3,0x02,0x74,0x06,0xE4,0xD8,0x0C,0x01,0xE6,0xD8,0xF6,0xC3,0x04,0x74,0x11,0x83, +0xC2,0x08,0x8A,0x86,0xA7,0x00,0x0C,0x01,0xEE,0x88,0x86,0xA7,0x00,0x83,0xEA,0x08, +0xF6,0xC3,0x08,0x74,0x0F,0xE8,0x8B,0xE3,0x72,0x0A,0x8A,0x86,0xC0,0x00,0xE6,0x38, +0xB0,0x23,0xE6,0x0A,0xF7,0xC3,0x00,0x04,0x75,0x01,0xC3,0xF7,0xC3,0x00,0x08,0x75, +0xF9,0x8A,0x86,0xA5,0x00,0xF6,0xC3,0x40,0x75,0x0D,0xA8,0x10,0x75,0xEC,0x0C,0x10, +0x88,0x86,0xA5,0x00,0xE6,0x0C,0xC3,0xA8,0x01,0x75,0xDF,0x83,0xC2,0x02,0x0C,0x05, +0xEE,0x88,0x86,0xA5,0x00,0xC3,0xB0,0x00,0xE8,0x47,0xD2,0xEB,0x0F,0xB0,0x02,0xE8, +0x90,0x0E,0xEB,0x08,0x83,0x66,0x38,0xDF,0x83,0x4E,0x7A,0x02,0x33,0xC0,0x8E,0xD8, +0xFA,0xA0,0x92,0x12,0x40,0xA2,0x92,0x12,0x3C,0x05,0x72,0x1E,0xC6,0x06,0x92,0x12, +0x00,0xFB,0xB0,0x01,0xE8,0x6B,0x0E,0xFA,0xA1,0x26,0x01,0x23,0x06,0x2A,0x01,0xA8, +0x01,0x75,0x07,0xE8,0xE2,0x07,0xE8,0x61,0x09,0x90,0xB0,0x00,0xE8,0x37,0xD2,0xFB, +0x85,0xED,0x74,0xB9,0xFA,0xF7,0x46,0x7A,0x46,0x00,0x75,0xC0,0x8B,0x46,0x78,0x3D, +0x0A,0x00,0x72,0xB0,0x8B,0x4E,0x74,0x83,0xF9,0x50,0x72,0x9A,0x83,0x66,0x38,0xDF, +0xC5,0x76,0x14,0x8B,0x46,0x3A,0x85,0xC0,0x75,0x58,0xAD,0x85,0xC0,0x75,0x0F,0xE8, +0xF8,0xFE,0xF7,0x46,0x7A,0x08,0x00,0x74,0x93,0xE8,0xA0,0xFA,0xEB,0x8E,0x3B,0x76, +0x04,0x76,0x21,0xB9,0x02,0x00,0x39,0x4E,0x2E,0x77,0x05,0xC7,0x46,0x2E,0x00,0x00, +0x56,0x8B,0x76,0x2C,0x89,0x76,0x04,0xC7,0x04,0x00,0x00,0x46,0x46,0x89,0x76,0x2C, +0x29,0x4E,0x2E,0x5E,0x85,0xC0,0x79,0x17,0xF6,0xC4,0x10,0x74,0x05,0xFF,0x56,0x7C, +0xEB,0x03,0xFF,0x56,0x7E,0x89,0x76,0x14,0xB0,0x0C,0xE8,0x85,0xD1,0xEB,0x86,0x89, +0x46,0x3A,0xFF,0x96,0x80,0x00,0x29,0x46,0x3A,0x89,0x76,0x14,0xB0,0x0C,0xE8,0x71, +0xD1,0xE9,0x71,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x10,0x02, +0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, -0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0, -0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0, -0xC0,0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0, +0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80, +0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, @@ -1021,860 +1023,860 @@ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, -0x80,0x80,0x80,0x80,0x80,0x80,0x30,0x41,0x5A,0x41,0xB2,0x41,0xD6,0x41,0xE8,0x41, -0xFA,0x41,0xC3,0x90,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x80,0x66,0x27, -0xFD,0x8B,0x56,0x24,0x83,0xFA,0x04,0x72,0xE9,0x83,0xEA,0x02,0x8B,0xD9,0x3B,0xCA, -0x76,0x02,0x8B,0xCA,0xB0,0x0A,0x57,0x51,0x8B,0xFE,0xF2,0xAE,0x8B,0xC1,0x59,0x5F, -0x75,0x1E,0x50,0x40,0x2B,0xC8,0x74,0x06,0x2B,0xD1,0x2B,0xD9,0xF3,0xA4,0x59,0x4B, -0x4A,0x4A,0xB0,0x0D,0xAA,0xA4,0x3B,0xCA,0x76,0x02,0x8B,0xCA,0xE3,0x13,0xEB,0xD4, -0x2B,0xD9,0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1,0xE9,0xF3,0xA5,0x73,0x01, -0xA4,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x29,0x7E,0x24,0x01,0x7E,0x1A,0x8B,0xCB,0x80, -0x7E,0x26,0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,0x18,0x03, -0x61,0xC3,0xC3,0x90,0xE8,0x7C,0x02,0x72,0xF9,0x90,0x83,0x4E,0x26,0x20,0x8B,0x46, -0x6A,0x89,0x46,0x6E,0x8B,0x46,0x48,0x0D,0x04,0x00,0x25,0xBF,0xFF,0x89,0x46,0x48, -0xB0,0x06,0xE8,0xD9,0xCF,0xC3,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A,0x29, -0x7E,0x24,0x80,0x7E,0x26,0x02,0x74,0x05,0x83,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD, -0xE8,0xD5,0x02,0x61,0xC3,0x90,0x8A,0xBE,0xC2,0x00,0xEB,0x24,0xF7,0x46,0x48,0x40, -0x00,0x75,0xB1,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x8B,0x56,0x24,0x83, -0xEA,0x0A,0x78,0x9E,0x03,0xD7,0x80,0x66,0x27,0xFD,0x33,0xC0,0x8A,0xBE,0xC2,0x00, -0xE3,0xB4,0x3B,0xFA,0x77,0xB0,0xAC,0x49,0x93,0x2E,0x8A,0x87,0xB6,0x3E,0x93,0x22, -0xDF,0x75,0x17,0xAA,0xE3,0xA0,0x3B,0xFA,0x77,0x9C,0xAC,0x49,0x93,0x2E,0x8A,0x87, -0xB6,0x3E,0x93,0x22,0xDF,0x75,0x03,0xAA,0xEB,0xD6,0xF6,0xC3,0x7F,0x75,0x05,0xFF, -0x46,0x66,0xEB,0xDF,0xF6,0xC3,0x40,0x75,0x0C,0x8B,0xD8,0x83,0xEB,0x08,0xD1,0xE3, -0x2E,0xFF,0xA7,0xB6,0x3F,0xFF,0x46,0x66,0x2C,0x20,0xEB,0xC7,0x85,0xC0,0x74,0x2C, -0x89,0x46,0x6A,0x83,0x4E,0x48,0x40,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A, -0x29,0x7E,0x24,0x80,0x7E,0x26,0x02,0x74,0x08,0x83,0x66,0x26,0xFD,0xE8,0xA3,0x01, -0xC3,0x60,0xB0,0xFD,0xE8,0x31,0x02,0x61,0xE8,0x98,0x01,0xC3,0xE9,0x57,0xFF,0x90, -0x8B,0x5E,0x66,0x4B,0x78,0x03,0x89,0x5E,0x66,0xAA,0x8B,0x5E,0x64,0xF7,0xC3,0x00, -0x20,0x75,0x03,0xE9,0x40,0xFF,0xF7,0xC3,0x40,0x00,0x74,0x08,0x8A,0x86,0xC1,0x00, -0xAA,0xE9,0x32,0xFF,0xB8,0x32,0x00,0xEB,0xA3,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68, -0x83,0xC3,0x08,0x80,0xE3,0xF8,0x89,0x5E,0x66,0x8B,0x5E,0x64,0x81,0xE3,0x00,0x18, -0x81,0xFB,0x00,0x18,0x74,0x2D,0xAA,0x85,0xDB,0x74,0x25,0xF7,0x46,0x64,0x40,0x00, -0x75,0x18,0x81,0xFB,0x00,0x10,0x74,0x0C,0x8B,0x46,0x66,0x2B,0x46,0x68,0xC1,0xE0, -0x04,0xE9,0x68,0xFF,0xB8,0x64,0x00,0xE9,0x62,0xFF,0x8A,0x86,0xC1,0x00,0xAA,0xAA, -0xE9,0xE3,0xFE,0x51,0x8B,0x4E,0x66,0x2B,0x4E,0x68,0xB0,0x20,0xF3,0xAA,0x59,0xE9, -0xD4,0xFE,0x8B,0x5E,0x66,0x89,0x5E,0x68,0x8B,0x5E,0x64,0xF7,0xC3,0x24,0x00,0x74, -0x10,0xC7,0x46,0x66,0x00,0x00,0xF7,0xC3,0x04,0x00,0x74,0x05,0xB0,0x0D,0xAA,0xB0, -0x0A,0xAA,0xEB,0x48,0x90,0x90,0xAA,0xF7,0x46,0x64,0x00,0x40,0x74,0x06,0xB8,0xD0, -0x07,0xE9,0x18,0xFF,0xE9,0x9F,0xFE,0x90,0xAA,0xF7,0x46,0x64,0x00,0x80,0x74,0x06, -0xB8,0xD0,0x07,0xE9,0x06,0xFF,0xE9,0x8D,0xFE,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68, -0x85,0xDB,0x75,0x0C,0x8B,0x5E,0x64,0xF7,0xC3,0x10,0x00,0x74,0x06,0xE9,0x76,0xFE, -0x8B,0x5E,0x64,0xF7,0xC3,0x08,0x00,0x74,0x27,0xB0,0x0A,0xAA,0xF7,0xC3,0x20,0x00, -0x75,0x1F,0xF7,0xC3,0x00,0x01,0x75,0x03,0xE9,0x5B,0xFE,0xF7,0xC3,0x40,0x00,0x75, -0x06,0xB8,0x64,0x00,0xE9,0xC5,0xFE,0x8A,0x86,0xC1,0x00,0xAA,0xAA,0xE9,0x46,0xFE, -0xAA,0xC7,0x46,0x66,0x00,0x00,0xF7,0xC3,0x00,0x06,0x74,0xF1,0xF7,0xC3,0x40,0x00, -0x74,0x19,0x8A,0x86,0xC1,0x00,0x81,0xE3,0x00,0x06,0x81,0xFB,0x00,0x04,0x72,0x06, -0x76,0x02,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xE9,0x1B,0xFE,0x81,0xE3,0x00,0x06,0x81, -0xFB,0x00,0x04,0x72,0x0E,0x76,0x06,0xB8,0x96,0x00,0xE9,0x7F,0xFE,0xB8,0x64,0x00, -0xE9,0x79,0xFE,0x8B,0x46,0x68,0xE9,0x73,0xFE,0x90,0x36,0x8B,0x0E,0xDA,0x12,0x83, -0xF9,0x32,0x73,0x1D,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8D,0x76,0x4C,0xBF, -0xDC,0x12,0x03,0xF9,0xA5,0xA5,0xA5,0x83,0xC1,0x06,0x89,0x0E,0xDA,0x12,0x07,0x1F, -0xC3,0xB0,0x08,0xE8,0x88,0xCD,0xC3,0x90,0x83,0x66,0x48,0xFE,0xE8,0xAD,0xC4,0xE8, -0xC8,0xFF,0xC3,0xF6,0x46,0x27,0x02,0x75,0x0F,0x9C,0xFA,0x83,0x7E,0x1A,0x00,0x74, -0x09,0x80,0x4E,0x27,0x01,0x9D,0xF9,0xC3,0xF8,0xC3,0x50,0x52,0xF7,0x46,0x38,0x40, -0x00,0x74,0x1D,0xE8,0x4E,0xDE,0x83,0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x27,0x83,0xEA, -0x08,0x8A,0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x5A,0x58,0xEB,0xD1, -0xE8,0x26,0xDE,0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6, -0x0C,0x5A,0x58,0xEB,0xBC,0x80,0x4E,0x27,0x02,0x5A,0x58,0x9D,0xF8,0xC3,0x08,0x46, -0x26,0x9C,0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38,0x40,0x00,0x75,0x14,0xF6,0xC1, -0x06,0x74,0x23,0xE8,0xF3,0xDD,0x8A,0xC1,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C, -0x9D,0xC3,0xF6,0xC1,0x02,0x74,0x0F,0xE8,0xEA,0xDD,0x83,0xC2,0x02,0x8A,0xC1,0x24, -0xFD,0x88,0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x8B,0x5E,0x26,0x22,0xC3,0x88,0x46,0x26, -0x74,0x01,0xC3,0x80,0x66,0x27,0xFD,0x9C,0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38, -0x40,0x00,0x75,0x16,0xF6,0xC1,0x04,0x75,0x0F,0xE8,0xAD,0xDD,0x8A,0xC1,0x24,0xFD, -0x0C,0x04,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x9D,0xC3,0xF6,0xC1,0x02,0x75,0xF9,0xE8, -0xA2,0xDD,0x83,0xC2,0x0A,0xEC,0xA8,0x20,0x75,0x0E,0x83,0xEA,0x08,0x8A,0xC1,0x0C, -0x02,0x88,0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x83,0xEA,0x0A,0x33,0xC9,0x8A,0x4E,0x1C, -0x8B,0x46,0x1A,0x3B,0xC8,0x73,0x1B,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,0x1E, -0xC5,0x76,0x00,0xF3,0x6E,0x1F,0x89,0x76,0x00,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00, -0xEB,0xCD,0x85,0xC0,0x74,0x12,0x01,0x46,0x2A,0x8B,0xC8,0x1E,0xC5,0x76,0x00,0xF3, -0x6E,0x1F,0x89,0x76,0x00,0x89,0x4E,0x1A,0xF6,0xC7,0x01,0x75,0x23,0x80,0xCB,0x02, -0x89,0x5E,0x26,0xE8,0x22,0xC3,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE, -0x88,0x86,0xA5,0x00,0xF6,0xC7,0x10,0x75,0x05,0xB0,0x02,0xE8,0x30,0xCC,0x9D,0xC3, -0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0xEB,0x86,0x90,0x8B,0xD1,0x8B,0x46,0x24,0x3B, -0xC8,0x76,0x02,0x8B,0xC8,0x2B,0xD1,0x2B,0xC1,0x8B,0xD9,0xE3,0x22,0x80,0x66,0x27, -0xFD,0x8E,0x46,0x02,0x8B,0x7E,0x22,0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1, -0xE9,0xF3,0xA5,0x73,0x01,0xA4,0x89,0x7E,0x22,0x89,0x46,0x24,0x01,0x5E,0x1A,0x8B, -0xCA,0x80,0x7E,0x26,0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8, -0xF6,0xFE,0x61,0xC3,0x50,0xE4,0x0A,0x84,0xC0,0x75,0x0A,0x86,0x86,0xA1,0x00,0x84, -0xC0,0x74,0x0A,0xE6,0x0A,0x58,0x0C,0x20,0x89,0x46,0x48,0xF9,0xC3,0x58,0x24,0xDF, -0x89,0x46,0x48,0xF8,0xC3,0x90,0xFB,0xB0,0x02,0xE8,0xE8,0x07,0xFA,0xE8,0x2E,0x01, -0xFB,0xB0,0x01,0xE8,0xDE,0x07,0xFA,0xB0,0x02,0xE8,0xD6,0xCB,0xFB,0x85,0xED,0x74, -0xE5,0xFA,0x8E,0x5E,0x0A,0xFB,0x90,0xFA,0x8B,0x46,0x48,0x8B,0x76,0x40,0xA8,0x8C, -0x75,0xDE,0xA8,0x20,0x74,0x1A,0x50,0xE8,0x6F,0xDC,0x58,0xE8,0xA6,0xFF,0x73,0x10, -0xB0,0x02,0xE8,0x79,0xCB,0xEB,0xC9,0x90,0x25,0xFF,0x00,0x8B,0xC8,0xEB,0x36,0x90, -0xA8,0x01,0x75,0x22,0x46,0x83,0xE6,0xFE,0x3B,0x76,0x08,0x74,0x79,0xAD,0x8A,0xFC, -0xB3,0xF0,0x22,0xFB,0x3A,0xFB,0x74,0xE0,0x3A,0xBE,0xA0,0x00,0x74,0x2E,0xE8,0xD2, -0xFD,0x73,0x77,0xEB,0x9B,0x90,0x8A,0xE0,0x24,0xFC,0x88,0x46,0x48,0x8B,0x4E,0x4A, -0xF6,0xC4,0x02,0x74,0x1D,0xE8,0xBB,0xFD,0x72,0x86,0xE8,0x13,0xF3,0x89,0x76,0x40, -0xE3,0x93,0x83,0x4E,0x48,0x03,0x89,0x4E,0x4A,0xE9,0x74,0xFF,0x25,0xFF,0x0F,0x8B, -0xC8,0x90,0x8B,0x86,0x98,0x00,0x85,0xC0,0x74,0x1A,0x51,0x8A,0x8E,0xA0,0x00,0xC0, -0xE9,0x04,0xBA,0x01,0x00,0xD3,0xE2,0x59,0x23,0xC2,0x74,0x08,0x03,0xF1,0x89,0x76, -0x40,0xE9,0x61,0xFF,0xFF,0x56,0x62,0xE3,0xF5,0x83,0x4E,0x48,0x01,0x89,0x4E,0x4A, -0x89,0x76,0x40,0xE9,0x3A,0xFF,0x81,0x4E,0x26,0x00,0x10,0x8B,0x46,0x50,0x3B,0x46, -0x46,0x77,0x03,0xE8,0x52,0xFD,0xE9,0x27,0xFF,0x90,0x88,0xBE,0xA0,0x00,0xEB,0xAC, -0x0A,0x06,0x90,0x12,0x8A,0xE0,0xBA,0x06,0x01,0xB0,0x04,0xEE,0xEC,0x84,0xC0,0x75, -0x12,0xB0,0x04,0xEE,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80,0x74,0x06,0xC7,0x06,0x84, -0x12,0x00,0x00,0x88,0x26,0x90,0x12,0xC3,0x0A,0x06,0x90,0x12,0x8A,0xE0,0xBA,0x06, -0x01,0xEC,0xA8,0x01,0x75,0xED,0xBA,0x08,0x01,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80, -0x74,0xE1,0xC7,0x06,0x84,0x12,0x00,0x00,0x88,0x26,0x90,0x12,0xC3,0x90,0x36,0xF7, -0x06,0x24,0x01,0x01,0x00,0x75,0x30,0x36,0x8B,0x0E,0xDA,0x12,0x80,0xF9,0x36,0x73, -0x26,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0xDC,0x12,0x03,0xF9,0xB0,0x08,0xE8,0x91, -0xCA,0x85,0xED,0x74,0x0E,0x8D,0x76,0x4C,0xA5,0xA5,0xA5,0x80,0xC1,0x06,0x80,0xF9, -0x36,0x72,0xE9,0x89,0x0E,0xDA,0x12,0xC3,0xC3,0x90,0xF7,0x06,0x26,0x01,0x01,0x00, -0x75,0xF6,0x8B,0x0E,0x20,0x13,0x85,0xC9,0x75,0xEE,0x33,0xC0,0x8E,0xC0,0x8E,0xD8, -0xBF,0x24,0x13,0xB9,0x36,0x00,0xB0,0x0A,0xE8,0x57,0xCA,0x85,0xED,0x75,0x06,0xE9, -0x12,0x01,0xE9,0x0A,0x01,0x33,0xDB,0x8A,0x46,0x4C,0x8A,0xA6,0xB3,0x00,0xFE,0xCC, -0x78,0x0E,0x88,0xA6,0xB3,0x00,0x0A,0xDC,0xB4,0x0A,0xAB,0x83,0xE9,0x02,0x76,0xE2, -0x8A,0xA6,0xB2,0x00,0xFE,0xCC,0x78,0x0E,0x88,0xA6,0xB2,0x00,0x0A,0xDC,0xB4,0x08, -0xAB,0x83,0xE9,0x02,0x76,0xCC,0x8A,0xA6,0xB1,0x00,0xFE,0xCC,0x78,0x18,0x8A,0xBE, -0xB0,0x00,0x75,0x04,0x88,0xA6,0xB0,0x00,0x88,0xA6,0xB1,0x00,0x0A,0xDC,0x8A,0xE7, -0xAB,0x83,0xE9,0x02,0x76,0xAC,0x8A,0xA6,0xB4,0x00,0xFE,0xCC,0x78,0x1F,0x88,0xA6, -0xB4,0x00,0x0A,0xDC,0xB4,0x0B,0xAB,0x8A,0x86,0xBC,0x00,0x8A,0xA6,0xBD,0x00,0xAB, -0x8B,0x86,0xBE,0x00,0xAB,0x83,0xE9,0x06,0x76,0x88,0x8A,0x46,0x4C,0x8A,0xA6,0xB6, -0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB6,0x00,0x0A,0xDC,0xB4,0x0C,0xAB,0xE8,0xF5, -0xCB,0xAB,0x8B,0x46,0x2A,0xAB,0x83,0xE9,0x06,0x76,0x74,0x8A,0x46,0x4C,0x8A,0xA6, -0xB7,0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB7,0x00,0x0A,0xDC,0xB4,0x0D,0xAB,0xE8, -0xD4,0xCB,0xAB,0x8B,0x46,0x34,0xAB,0x83,0xE9,0x06,0x76,0x53,0x8A,0x46,0x4C,0x8A, -0xA6,0xB8,0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB8,0x00,0x0A,0xDC,0xB4,0x0E,0xAB, -0xA1,0x50,0x12,0xAB,0xA1,0x52,0x12,0xAB,0x83,0xE9,0x06,0x76,0x32,0x8A,0x46,0x4C, -0x8A,0xA6,0xB5,0x00,0xFE,0xCC,0x78,0x18,0x88,0xA6,0xB5,0x00,0x0A,0xDC,0xB4,0x0F, -0xAB,0x8B,0x86,0x9A,0x00,0xAB,0x8B,0x86,0x9C,0x00,0xAB,0x83,0xE9,0x06,0x76,0x0F, -0x84,0xDB,0x75,0x03,0xE9,0xEF,0xFE,0xB0,0x0A,0xE8,0x12,0xC9,0xE9,0xE7,0xFE,0xB0, -0x0A,0xE8,0x0A,0xC9,0xF7,0xD9,0x83,0xC1,0x36,0x8B,0xC1,0x0D,0x80,0x00,0x86,0xC4, -0xA3,0x22,0x13,0x41,0x41,0x89,0x0E,0x20,0x13,0xC3,0xA1,0x84,0x12,0x2B,0xC1,0x72, -0x11,0xA3,0x84,0x12,0xBE,0x22,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x20,0x13, -0xF8,0xC3,0xF9,0xC3,0xC3,0x81,0xEF,0x6A,0x13,0x74,0xF9,0x8B,0xC7,0x0D,0x80,0x00, -0x86,0xC4,0xA3,0x68,0x13,0x47,0x47,0x89,0x3E,0x66,0x13,0xC3,0xF7,0x06,0x2A,0x01, -0x01,0x00,0x75,0xE0,0x8B,0x0E,0x66,0x13,0xE3,0x07,0x80,0xF9,0x20,0x77,0xD5,0x49, -0x49,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0x6A,0x13,0x8B,0xF7,0x03,0xF9,0x83,0xC6, -0x34,0x3B,0xFE,0x77,0xC0,0xB0,0x0E,0xE8,0xC8,0xC8,0x85,0xED,0x74,0xB7,0x8A,0x46, -0x4C,0x8A,0xB6,0xB9,0x00,0xFE,0xCE,0x78,0x15,0x88,0xB6,0xB9,0x00,0x8A,0xA6,0xA9, -0x00,0x80,0xCC,0xC0,0xAB,0x84,0xF6,0x74,0x05,0xB0,0x0E,0xE8,0x70,0xC8,0x8A,0xB6, -0xBA,0x00,0xFE,0xCE,0x78,0xCB,0x8A,0x9E,0xA9,0x00,0x8A,0xBE,0xAB,0x00,0x8A,0x56, -0x3F,0x8A,0xF3,0x32,0xF7,0x0A,0xB6,0xAC,0x00,0xC6,0x86,0xAC,0x00,0x00,0x22,0xF2, -0x74,0x4B,0xF6,0xC6,0x08,0x74,0x0F,0xB4,0x02,0xF6,0xC3,0x08,0x75,0x02,0xB4,0x03, -0xAB,0x80,0xE6,0xF7,0x74,0x37,0xF6,0xC6,0x01,0x74,0x0F,0xB4,0x00,0xF6,0xC3,0x01, -0x75,0x02,0xB4,0x01,0xAB,0x80,0xE6,0xFE,0x74,0x23,0xF6,0xC6,0x02,0x74,0x0F,0xB4, -0x04,0xF6,0xC3,0x02,0x75,0x02,0xB4,0x05,0xAB,0x80,0xE6,0xFD,0x74,0x0F,0xF6,0xC6, -0x04,0x74,0x0A,0xB4,0x06,0xF6,0xC3,0x04,0x75,0x02,0xB4,0x07,0xAB,0xC6,0x86,0xBA, -0x00,0x00,0x88,0x9E,0xAB,0x00,0xE9,0x58,0xFF,0x90,0xA1,0x84,0x12,0x2B,0xC1,0x72, -0x11,0xA3,0x84,0x12,0xBE,0x68,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x66,0x13, -0xF8,0xC3,0xF9,0xC3,0xA1,0x84,0x12,0x41,0x41,0x2B,0xC1,0x72,0x23,0xA3,0x84,0x12, -0x8B,0xC1,0x48,0x48,0x32,0xE4,0x0C,0x80,0x86,0xC4,0xEF,0x90,0x90,0x90,0x90,0x90, -0xBE,0xDC,0x12,0x49,0x49,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0xDA,0x12,0xF8,0xC3, -0xF9,0xC3,0x8A,0xC8,0x8A,0x46,0x4C,0xB4,0x01,0x83,0xEB,0x06,0xEF,0x90,0x90,0x90, -0x90,0x90,0xB8,0x01,0x00,0xEF,0x90,0x90,0x90,0x90,0x90,0x8A,0xC1,0xEF,0x90,0x90, -0x90,0x90,0x90,0xE9,0x97,0x00,0xE9,0xAC,0x00,0x33,0xC0,0x8E,0xD8,0x89,0x1E,0x84, -0x12,0xC3,0x36,0x8B,0x1E,0x84,0x12,0xFB,0x90,0xFA,0xB0,0x0C,0xE8,0xA3,0xC7,0x85, -0xED,0x74,0xE6,0xC5,0x76,0x0C,0x83,0xFB,0x14,0x72,0xDB,0xFB,0x90,0xFA,0xAD,0x85, -0xC0,0x78,0xAF,0x74,0xE2,0x8B,0xFE,0x03,0xF8,0x36,0x8B,0x0E,0x86,0x12,0x3B,0xC1, -0x77,0x02,0x8B,0xC8,0x83,0xEB,0x04,0x3B,0xD9,0x77,0x02,0x8B,0xCB,0x33,0xC0,0x8A, -0x46,0x4C,0xEF,0x90,0x90,0x90,0x90,0x90,0x8B,0xC1,0xEF,0x90,0x90,0x90,0x90,0x90, -0x41,0x80,0xE1,0xFE,0x2B,0xD9,0x51,0xD1,0xE9,0xF3,0x6F,0x90,0x59,0x8B,0xC7,0x40, -0x24,0xFE,0x3B,0xC6,0x74,0x27,0x2B,0xFE,0x4E,0x4E,0x53,0x8B,0x5E,0x10,0x3B,0xF3, -0x72,0x13,0x03,0x1F,0x83,0xC3,0x03,0x80,0xE3,0xFE,0xC7,0x07,0x00,0x00,0x83,0x6E, -0x74,0x02,0x89,0x5E,0x10,0x5B,0x89,0x3C,0x89,0x76,0x0C,0xEB,0x89,0x89,0x76,0x0C, -0x39,0x76,0x10,0x77,0x81,0x72,0x08,0x83,0x3C,0x00,0x74,0x03,0xE9,0x77,0xFF,0xE8, -0x27,0xBE,0xE9,0x62,0xFF,0x36,0x89,0x1E,0x84,0x12,0xB0,0x0C,0xE8,0xCF,0xC6,0x33, -0xC0,0x8E,0xD8,0xC3,0xA1,0x84,0x12,0x3D,0x10,0x00,0x72,0x77,0xBA,0x04,0x01,0x3B, -0x06,0x88,0x12,0x75,0x06,0xC7,0x06,0x7E,0x12,0x00,0x00,0x8B,0x0E,0xDA,0x12,0xE3, -0x0B,0xE8,0xD0,0xFE,0x72,0x57,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x20,0x13, -0xE3,0x0B,0xE8,0xA5,0xFD,0x72,0x46,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x66, -0x13,0xE3,0x0B,0xE8,0x94,0xFE,0x72,0x35,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0xA1,0x28, -0x01,0xA9,0x01,0x00,0x75,0x03,0xE8,0xF9,0xFE,0x80,0x3E,0x8D,0x12,0x00,0x75,0x1D, -0xA1,0x84,0x12,0x3D,0x20,0x00,0x76,0x15,0x3B,0x06,0x82,0x12,0x76,0x09,0xA1,0x7E, -0x12,0x3B,0x06,0x80,0x12,0x72,0x0C,0x80,0x0E,0x90,0x12,0x80,0xC3,0xB0,0x80,0xFF, -0x16,0x7C,0x12,0xC3,0x80,0x0E,0x90,0x12,0x40,0xC3,0x6A,0x00,0x1F,0xC6,0x06,0x93, -0x12,0x17,0x9C,0x0E,0xE8,0xD1,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x20,0x9C, -0x0E,0xE8,0xC4,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x16,0x9C,0x0E,0xE8,0xB7, -0xC8,0x90,0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xCA,0xFB,0x90,0xFA,0xBA,0x04,0x01, -0xED,0x90,0x90,0x90,0x90,0x90,0x3A,0x06,0x94,0x12,0x77,0xBE,0x33,0xDB,0x8A,0xD8, -0xD1,0xE3,0x2E,0x8B,0xAF,0x44,0x00,0xC4,0x7E,0x08,0x85,0xFF,0x74,0xB9,0xF6,0xC4, -0xC0,0x75,0x55,0x32,0xC0,0xC1,0xE0,0x02,0x80,0xE4,0xF0,0x8B,0xF0,0xED,0x90,0x90, -0x90,0x90,0x90,0x85,0xC0,0x74,0xBB,0x8B,0xC8,0x41,0x80,0xE1,0xFE,0x0B,0xC6,0x8B, -0x5E,0x50,0x4B,0x4B,0x2B,0xD9,0x78,0x9C,0xAB,0x8B,0xC1,0x40,0x40,0x01,0x46,0x4E, -0xD1,0xE9,0xF3,0x6D,0x90,0x89,0x5E,0x50,0x89,0x7E,0x08,0x8B,0x46,0x26,0x80,0xE4, -0xEF,0x89,0x46,0x26,0xF6,0xC4,0x01,0x75,0x0C,0xF7,0x46,0x48,0x0C,0x00,0x75,0x05, -0xB0,0x02,0xE8,0x99,0xC5,0xE9,0x7A,0xFF,0x86,0xC4,0x8B,0xC8,0x83,0xE1,0x3F,0x41, -0x80,0xE1,0xFE,0xE3,0x0A,0x3C,0x80,0x72,0x09,0x24,0x3F,0xB4,0xF0,0xEB,0xB0,0xE9, -0x60,0xFF,0x25,0x3F,0x00,0x33,0xFF,0x8E,0xC7,0xBF,0x96,0x12,0x8B,0xF7,0xD1,0xE9, -0xF3,0x6D,0x90,0x8B,0xC8,0xE8,0x48,0xED,0xE9,0x47,0xFF,0x90,0x6A,0x00,0x1F,0xC6, -0x06,0x93,0x12,0x1B,0x9C,0x0E,0xE8,0xEF,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E, -0xD8,0x8E,0xC0,0xBA,0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xB0,0x06,0xEE,0xEC,0xA2, -0x8C,0x12,0xA8,0x40,0x74,0x11,0xA1,0x88,0x12,0xA3,0x84,0x12,0xC6,0x06,0x8D,0x12, -0x00,0xE8,0x60,0xFE,0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0x04,0xFF,0xB8,0x00, -0x80,0xBA,0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x6A,0x00,0x1F,0xC6,0x06,0x93, -0x12,0x1B,0x9C,0x0E,0xE8,0xA1,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E, -0xC0,0xBA,0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xBA,0x08,0x01,0xEC,0xA2,0x8C,0x12, +0x80,0x80,0x80,0x80,0x4E,0x41,0x78,0x41,0xD0,0x41,0xF4,0x41,0x06,0x42,0x18,0x42, +0xC3,0x90,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x80,0x66,0x27,0xFD,0x8B, +0x56,0x24,0x83,0xFA,0x04,0x72,0xE9,0x83,0xEA,0x02,0x8B,0xD9,0x3B,0xCA,0x76,0x02, +0x8B,0xCA,0xB0,0x0A,0x57,0x51,0x8B,0xFE,0xF2,0xAE,0x8B,0xC1,0x59,0x5F,0x75,0x1E, +0x50,0x40,0x2B,0xC8,0x74,0x06,0x2B,0xD1,0x2B,0xD9,0xF3,0xA4,0x59,0x4B,0x4A,0x4A, +0xB0,0x0D,0xAA,0xA4,0x3B,0xCA,0x76,0x02,0x8B,0xCA,0xE3,0x13,0xEB,0xD4,0x2B,0xD9, +0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1,0xE9,0xF3,0xA5,0x73,0x01,0xA4,0x89, +0x7E,0x22,0x2B,0x7E,0x6C,0x29,0x7E,0x24,0x01,0x7E,0x1A,0x8B,0xCB,0x80,0x7E,0x26, +0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,0x18,0x03,0x61,0xC3, +0xC3,0x90,0xE8,0x7C,0x02,0x72,0xF9,0x90,0x83,0x4E,0x26,0x20,0x8B,0x46,0x6A,0x89, +0x46,0x6E,0x8B,0x46,0x48,0x0D,0x04,0x00,0x25,0xBF,0xFF,0x89,0x46,0x48,0xB0,0x06, +0xE8,0xBF,0xCF,0xC3,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A,0x29,0x7E,0x24, +0x80,0x7E,0x26,0x02,0x74,0x05,0x83,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,0xD5, +0x02,0x61,0xC3,0x90,0x8A,0xBE,0xC2,0x00,0xEB,0x24,0xF7,0x46,0x48,0x40,0x00,0x75, +0xB1,0x8E,0x46,0x02,0x8B,0x7E,0x22,0x89,0x7E,0x6C,0x8B,0x56,0x24,0x83,0xEA,0x0A, +0x78,0x9E,0x03,0xD7,0x80,0x66,0x27,0xFD,0x33,0xC0,0x8A,0xBE,0xC2,0x00,0xE3,0xB4, +0x3B,0xFA,0x77,0xB0,0xAC,0x49,0x93,0x2E,0x8A,0x87,0xD4,0x3E,0x93,0x22,0xDF,0x75, +0x17,0xAA,0xE3,0xA0,0x3B,0xFA,0x77,0x9C,0xAC,0x49,0x93,0x2E,0x8A,0x87,0xD4,0x3E, +0x93,0x22,0xDF,0x75,0x03,0xAA,0xEB,0xD6,0xF6,0xC3,0x7F,0x75,0x05,0xFF,0x46,0x66, +0xEB,0xDF,0xF6,0xC3,0x40,0x75,0x0C,0x8B,0xD8,0x83,0xEB,0x08,0xD1,0xE3,0x2E,0xFF, +0xA7,0xD4,0x3F,0xFF,0x46,0x66,0x2C,0x20,0xEB,0xC7,0x85,0xC0,0x74,0x2C,0x89,0x46, +0x6A,0x83,0x4E,0x48,0x40,0x89,0x7E,0x22,0x2B,0x7E,0x6C,0x01,0x7E,0x1A,0x29,0x7E, +0x24,0x80,0x7E,0x26,0x02,0x74,0x08,0x83,0x66,0x26,0xFD,0xE8,0xA3,0x01,0xC3,0x60, +0xB0,0xFD,0xE8,0x31,0x02,0x61,0xE8,0x98,0x01,0xC3,0xE9,0x57,0xFF,0x90,0x8B,0x5E, +0x66,0x4B,0x78,0x03,0x89,0x5E,0x66,0xAA,0x8B,0x5E,0x64,0xF7,0xC3,0x00,0x20,0x75, +0x03,0xE9,0x40,0xFF,0xF7,0xC3,0x40,0x00,0x74,0x08,0x8A,0x86,0xC1,0x00,0xAA,0xE9, +0x32,0xFF,0xB8,0x32,0x00,0xEB,0xA3,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68,0x83,0xC3, +0x08,0x80,0xE3,0xF8,0x89,0x5E,0x66,0x8B,0x5E,0x64,0x81,0xE3,0x00,0x18,0x81,0xFB, +0x00,0x18,0x74,0x2D,0xAA,0x85,0xDB,0x74,0x25,0xF7,0x46,0x64,0x40,0x00,0x75,0x18, +0x81,0xFB,0x00,0x10,0x74,0x0C,0x8B,0x46,0x66,0x2B,0x46,0x68,0xC1,0xE0,0x04,0xE9, +0x68,0xFF,0xB8,0x64,0x00,0xE9,0x62,0xFF,0x8A,0x86,0xC1,0x00,0xAA,0xAA,0xE9,0xE3, +0xFE,0x51,0x8B,0x4E,0x66,0x2B,0x4E,0x68,0xB0,0x20,0xF3,0xAA,0x59,0xE9,0xD4,0xFE, +0x8B,0x5E,0x66,0x89,0x5E,0x68,0x8B,0x5E,0x64,0xF7,0xC3,0x24,0x00,0x74,0x10,0xC7, +0x46,0x66,0x00,0x00,0xF7,0xC3,0x04,0x00,0x74,0x05,0xB0,0x0D,0xAA,0xB0,0x0A,0xAA, +0xEB,0x48,0x90,0x90,0xAA,0xF7,0x46,0x64,0x00,0x40,0x74,0x06,0xB8,0xD0,0x07,0xE9, +0x18,0xFF,0xE9,0x9F,0xFE,0x90,0xAA,0xF7,0x46,0x64,0x00,0x80,0x74,0x06,0xB8,0xD0, +0x07,0xE9,0x06,0xFF,0xE9,0x8D,0xFE,0x90,0x8B,0x5E,0x66,0x89,0x5E,0x68,0x85,0xDB, +0x75,0x0C,0x8B,0x5E,0x64,0xF7,0xC3,0x10,0x00,0x74,0x06,0xE9,0x76,0xFE,0x8B,0x5E, +0x64,0xF7,0xC3,0x08,0x00,0x74,0x27,0xB0,0x0A,0xAA,0xF7,0xC3,0x20,0x00,0x75,0x1F, +0xF7,0xC3,0x00,0x01,0x75,0x03,0xE9,0x5B,0xFE,0xF7,0xC3,0x40,0x00,0x75,0x06,0xB8, +0x64,0x00,0xE9,0xC5,0xFE,0x8A,0x86,0xC1,0x00,0xAA,0xAA,0xE9,0x46,0xFE,0xAA,0xC7, +0x46,0x66,0x00,0x00,0xF7,0xC3,0x00,0x06,0x74,0xF1,0xF7,0xC3,0x40,0x00,0x74,0x19, +0x8A,0x86,0xC1,0x00,0x81,0xE3,0x00,0x06,0x81,0xFB,0x00,0x04,0x72,0x06,0x76,0x02, +0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xE9,0x1B,0xFE,0x81,0xE3,0x00,0x06,0x81,0xFB,0x00, +0x04,0x72,0x0E,0x76,0x06,0xB8,0x96,0x00,0xE9,0x7F,0xFE,0xB8,0x64,0x00,0xE9,0x79, +0xFE,0x8B,0x46,0x68,0xE9,0x73,0xFE,0x90,0x36,0x8B,0x0E,0xDA,0x12,0x83,0xF9,0x32, +0x73,0x1D,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0x8D,0x76,0x4C,0xBF,0xDC,0x12, +0x03,0xF9,0xA5,0xA5,0xA5,0x83,0xC1,0x06,0x89,0x0E,0xDA,0x12,0x07,0x1F,0xC3,0xB0, +0x08,0xE8,0x6E,0xCD,0xC3,0x90,0x83,0x66,0x48,0xFE,0xE8,0x93,0xC4,0xE8,0xC8,0xFF, +0xC3,0xF6,0x46,0x27,0x02,0x75,0x0F,0x9C,0xFA,0x83,0x7E,0x1A,0x00,0x74,0x09,0x80, +0x4E,0x27,0x01,0x9D,0xF9,0xC3,0xF8,0xC3,0x50,0x52,0xF7,0x46,0x38,0x40,0x00,0x74, +0x1D,0xE8,0x34,0xDE,0x83,0xC2,0x0A,0xEC,0xA8,0x40,0x75,0x27,0x83,0xEA,0x08,0x8A, +0x86,0xA5,0x00,0x0C,0x02,0x88,0x86,0xA5,0x00,0xEE,0x5A,0x58,0xEB,0xD1,0xE8,0x0C, +0xDE,0x8A,0x86,0xA5,0x00,0x24,0xFB,0x0C,0x02,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x5A, +0x58,0xEB,0xBC,0x80,0x4E,0x27,0x02,0x5A,0x58,0x9D,0xF8,0xC3,0x08,0x46,0x26,0x9C, +0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38,0x40,0x00,0x75,0x14,0xF6,0xC1,0x06,0x74, +0x23,0xE8,0xD9,0xDD,0x8A,0xC1,0x24,0xF9,0x88,0x86,0xA5,0x00,0xE6,0x0C,0x9D,0xC3, +0xF6,0xC1,0x02,0x74,0x0F,0xE8,0xD0,0xDD,0x83,0xC2,0x02,0x8A,0xC1,0x24,0xFD,0x88, +0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x8B,0x5E,0x26,0x22,0xC3,0x88,0x46,0x26,0x74,0x01, +0xC3,0x80,0x66,0x27,0xFD,0x9C,0xFA,0x8A,0x8E,0xA5,0x00,0xF7,0x46,0x38,0x40,0x00, +0x75,0x16,0xF6,0xC1,0x04,0x75,0x0F,0xE8,0x93,0xDD,0x8A,0xC1,0x24,0xFD,0x0C,0x04, +0x88,0x86,0xA5,0x00,0xE6,0x0C,0x9D,0xC3,0xF6,0xC1,0x02,0x75,0xF9,0xE8,0x88,0xDD, +0x83,0xC2,0x0A,0xEC,0xA8,0x20,0x75,0x0E,0x83,0xEA,0x08,0x8A,0xC1,0x0C,0x02,0x88, +0x86,0xA5,0x00,0xEE,0x9D,0xC3,0x83,0xEA,0x0A,0x33,0xC9,0x8A,0x4E,0x1C,0x8B,0x46, +0x1A,0x3B,0xC8,0x73,0x1B,0x01,0x4E,0x2A,0x2B,0xC1,0x89,0x46,0x1A,0x1E,0xC5,0x76, +0x00,0xF3,0x6E,0x1F,0x89,0x76,0x00,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0xEB,0xCD, +0x85,0xC0,0x74,0x12,0x01,0x46,0x2A,0x8B,0xC8,0x1E,0xC5,0x76,0x00,0xF3,0x6E,0x1F, +0x89,0x76,0x00,0x89,0x4E,0x1A,0xF6,0xC7,0x01,0x75,0x23,0x80,0xCB,0x02,0x89,0x5E, +0x26,0xE8,0x08,0xC3,0x83,0xC2,0x02,0x8A,0x86,0xA5,0x00,0x24,0xFD,0xEE,0x88,0x86, +0xA5,0x00,0xF6,0xC7,0x10,0x75,0x05,0xB0,0x02,0xE8,0x16,0xCC,0x9D,0xC3,0x83,0xC2, +0x02,0x8A,0x86,0xA5,0x00,0xEB,0x86,0x90,0x8B,0xD1,0x8B,0x46,0x24,0x3B,0xC8,0x76, +0x02,0x8B,0xC8,0x2B,0xD1,0x2B,0xC1,0x8B,0xD9,0xE3,0x22,0x80,0x66,0x27,0xFD,0x8E, +0x46,0x02,0x8B,0x7E,0x22,0xF7,0xC6,0x01,0x00,0x74,0x02,0xA4,0x49,0xD1,0xE9,0xF3, +0xA5,0x73,0x01,0xA4,0x89,0x7E,0x22,0x89,0x46,0x24,0x01,0x5E,0x1A,0x8B,0xCA,0x80, +0x7E,0x26,0x02,0x74,0x05,0x80,0x66,0x26,0xFD,0xC3,0x60,0xB0,0xFD,0xE8,0xF6,0xFE, +0x61,0xC3,0x50,0xE4,0x0A,0x84,0xC0,0x75,0x0A,0x86,0x86,0xA1,0x00,0x84,0xC0,0x74, +0x0A,0xE6,0x0A,0x58,0x0C,0x20,0x89,0x46,0x48,0xF9,0xC3,0x58,0x24,0xDF,0x89,0x46, +0x48,0xF8,0xC3,0x90,0xFB,0xB0,0x02,0xE8,0xE8,0x07,0xFA,0xE8,0x2E,0x01,0xFB,0xB0, +0x01,0xE8,0xDE,0x07,0xFA,0xB0,0x02,0xE8,0xBC,0xCB,0xFB,0x85,0xED,0x74,0xE5,0xFA, +0x8E,0x5E,0x0A,0xFB,0x90,0xFA,0x8B,0x46,0x48,0x8B,0x76,0x40,0xA8,0x8C,0x75,0xDE, +0xA8,0x20,0x74,0x1A,0x50,0xE8,0x55,0xDC,0x58,0xE8,0xA6,0xFF,0x73,0x10,0xB0,0x02, +0xE8,0x5F,0xCB,0xEB,0xC9,0x90,0x25,0xFF,0x00,0x8B,0xC8,0xEB,0x36,0x90,0xA8,0x01, +0x75,0x22,0x46,0x83,0xE6,0xFE,0x3B,0x76,0x08,0x74,0x79,0xAD,0x8A,0xFC,0xB3,0xF0, +0x22,0xFB,0x3A,0xFB,0x74,0xE0,0x3A,0xBE,0xA0,0x00,0x74,0x2E,0xE8,0xD2,0xFD,0x73, +0x77,0xEB,0x9B,0x90,0x8A,0xE0,0x24,0xFC,0x88,0x46,0x48,0x8B,0x4E,0x4A,0xF6,0xC4, +0x02,0x74,0x1D,0xE8,0xBB,0xFD,0x72,0x86,0xE8,0x13,0xF3,0x89,0x76,0x40,0xE3,0x93, +0x83,0x4E,0x48,0x03,0x89,0x4E,0x4A,0xE9,0x74,0xFF,0x25,0xFF,0x0F,0x8B,0xC8,0x90, +0x8B,0x86,0x98,0x00,0x85,0xC0,0x74,0x1A,0x51,0x8A,0x8E,0xA0,0x00,0xC0,0xE9,0x04, +0xBA,0x01,0x00,0xD3,0xE2,0x59,0x23,0xC2,0x74,0x08,0x03,0xF1,0x89,0x76,0x40,0xE9, +0x61,0xFF,0xFF,0x56,0x62,0xE3,0xF5,0x83,0x4E,0x48,0x01,0x89,0x4E,0x4A,0x89,0x76, +0x40,0xE9,0x3A,0xFF,0x81,0x4E,0x26,0x00,0x10,0x8B,0x46,0x50,0x3B,0x46,0x46,0x77, +0x03,0xE8,0x52,0xFD,0xE9,0x27,0xFF,0x90,0x88,0xBE,0xA0,0x00,0xEB,0xAC,0x0A,0x06, +0x90,0x12,0x8A,0xE0,0xBA,0x06,0x01,0xB0,0x04,0xEE,0xEC,0x84,0xC0,0x75,0x12,0xB0, +0x04,0xEE,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80,0x74,0x06,0xC7,0x06,0x84,0x12,0x00, +0x00,0x88,0x26,0x90,0x12,0xC3,0x0A,0x06,0x90,0x12,0x8A,0xE0,0xBA,0x06,0x01,0xEC, +0xA8,0x01,0x75,0xED,0xBA,0x08,0x01,0x8A,0xC4,0xEE,0x32,0xE4,0xA8,0x80,0x74,0xE1, +0xC7,0x06,0x84,0x12,0x00,0x00,0x88,0x26,0x90,0x12,0xC3,0x90,0x36,0xF7,0x06,0x24, +0x01,0x01,0x00,0x75,0x30,0x36,0x8B,0x0E,0xDA,0x12,0x80,0xF9,0x36,0x73,0x26,0x33, +0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0xDC,0x12,0x03,0xF9,0xB0,0x08,0xE8,0x77,0xCA,0x85, +0xED,0x74,0x0E,0x8D,0x76,0x4C,0xA5,0xA5,0xA5,0x80,0xC1,0x06,0x80,0xF9,0x36,0x72, +0xE9,0x89,0x0E,0xDA,0x12,0xC3,0xC3,0x90,0xF7,0x06,0x26,0x01,0x01,0x00,0x75,0xF6, +0x8B,0x0E,0x20,0x13,0x85,0xC9,0x75,0xEE,0x33,0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0x24, +0x13,0xB9,0x36,0x00,0xB0,0x0A,0xE8,0x3D,0xCA,0x85,0xED,0x75,0x06,0xE9,0x12,0x01, +0xE9,0x0A,0x01,0x33,0xDB,0x8A,0x46,0x4C,0x8A,0xA6,0xB3,0x00,0xFE,0xCC,0x78,0x0E, +0x88,0xA6,0xB3,0x00,0x0A,0xDC,0xB4,0x0A,0xAB,0x83,0xE9,0x02,0x76,0xE2,0x8A,0xA6, +0xB2,0x00,0xFE,0xCC,0x78,0x0E,0x88,0xA6,0xB2,0x00,0x0A,0xDC,0xB4,0x08,0xAB,0x83, +0xE9,0x02,0x76,0xCC,0x8A,0xA6,0xB1,0x00,0xFE,0xCC,0x78,0x18,0x8A,0xBE,0xB0,0x00, +0x75,0x04,0x88,0xA6,0xB0,0x00,0x88,0xA6,0xB1,0x00,0x0A,0xDC,0x8A,0xE7,0xAB,0x83, +0xE9,0x02,0x76,0xAC,0x8A,0xA6,0xB4,0x00,0xFE,0xCC,0x78,0x1F,0x88,0xA6,0xB4,0x00, +0x0A,0xDC,0xB4,0x0B,0xAB,0x8A,0x86,0xBC,0x00,0x8A,0xA6,0xBD,0x00,0xAB,0x8B,0x86, +0xBE,0x00,0xAB,0x83,0xE9,0x06,0x76,0x88,0x8A,0x46,0x4C,0x8A,0xA6,0xB6,0x00,0xFE, +0xCC,0x78,0x19,0x88,0xA6,0xB6,0x00,0x0A,0xDC,0xB4,0x0C,0xAB,0xE8,0xDB,0xCB,0xAB, +0x8B,0x46,0x2A,0xAB,0x83,0xE9,0x06,0x76,0x74,0x8A,0x46,0x4C,0x8A,0xA6,0xB7,0x00, +0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB7,0x00,0x0A,0xDC,0xB4,0x0D,0xAB,0xE8,0xBA,0xCB, +0xAB,0x8B,0x46,0x34,0xAB,0x83,0xE9,0x06,0x76,0x53,0x8A,0x46,0x4C,0x8A,0xA6,0xB8, +0x00,0xFE,0xCC,0x78,0x19,0x88,0xA6,0xB8,0x00,0x0A,0xDC,0xB4,0x0E,0xAB,0xA1,0x50, +0x12,0xAB,0xA1,0x52,0x12,0xAB,0x83,0xE9,0x06,0x76,0x32,0x8A,0x46,0x4C,0x8A,0xA6, +0xB5,0x00,0xFE,0xCC,0x78,0x18,0x88,0xA6,0xB5,0x00,0x0A,0xDC,0xB4,0x0F,0xAB,0x8B, +0x86,0x9A,0x00,0xAB,0x8B,0x86,0x9C,0x00,0xAB,0x83,0xE9,0x06,0x76,0x0F,0x84,0xDB, +0x75,0x03,0xE9,0xEF,0xFE,0xB0,0x0A,0xE8,0xF8,0xC8,0xE9,0xE7,0xFE,0xB0,0x0A,0xE8, +0xF0,0xC8,0xF7,0xD9,0x83,0xC1,0x36,0x8B,0xC1,0x0D,0x80,0x00,0x86,0xC4,0xA3,0x22, +0x13,0x41,0x41,0x89,0x0E,0x20,0x13,0xC3,0xA1,0x84,0x12,0x2B,0xC1,0x72,0x11,0xA3, +0x84,0x12,0xBE,0x22,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x20,0x13,0xF8,0xC3, +0xF9,0xC3,0xC3,0x81,0xEF,0x6A,0x13,0x74,0xF9,0x8B,0xC7,0x0D,0x80,0x00,0x86,0xC4, +0xA3,0x68,0x13,0x47,0x47,0x89,0x3E,0x66,0x13,0xC3,0xF7,0x06,0x2A,0x01,0x01,0x00, +0x75,0xE0,0x8B,0x0E,0x66,0x13,0xE3,0x07,0x80,0xF9,0x20,0x77,0xD5,0x49,0x49,0x33, +0xC0,0x8E,0xC0,0x8E,0xD8,0xBF,0x6A,0x13,0x8B,0xF7,0x03,0xF9,0x83,0xC6,0x34,0x3B, +0xFE,0x77,0xC0,0xB0,0x0E,0xE8,0xAE,0xC8,0x85,0xED,0x74,0xB7,0x8A,0x46,0x4C,0x8A, +0xB6,0xB9,0x00,0xFE,0xCE,0x78,0x15,0x88,0xB6,0xB9,0x00,0x8A,0xA6,0xA9,0x00,0x80, +0xCC,0xC0,0xAB,0x84,0xF6,0x74,0x05,0xB0,0x0E,0xE8,0x56,0xC8,0x8A,0xB6,0xBA,0x00, +0xFE,0xCE,0x78,0xCB,0x8A,0x9E,0xA9,0x00,0x8A,0xBE,0xAB,0x00,0x8A,0x56,0x3F,0x8A, +0xF3,0x32,0xF7,0x0A,0xB6,0xAC,0x00,0xC6,0x86,0xAC,0x00,0x00,0x22,0xF2,0x74,0x4B, +0xF6,0xC6,0x08,0x74,0x0F,0xB4,0x02,0xF6,0xC3,0x08,0x75,0x02,0xB4,0x03,0xAB,0x80, +0xE6,0xF7,0x74,0x37,0xF6,0xC6,0x01,0x74,0x0F,0xB4,0x00,0xF6,0xC3,0x01,0x75,0x02, +0xB4,0x01,0xAB,0x80,0xE6,0xFE,0x74,0x23,0xF6,0xC6,0x02,0x74,0x0F,0xB4,0x04,0xF6, +0xC3,0x02,0x75,0x02,0xB4,0x05,0xAB,0x80,0xE6,0xFD,0x74,0x0F,0xF6,0xC6,0x04,0x74, +0x0A,0xB4,0x06,0xF6,0xC3,0x04,0x75,0x02,0xB4,0x07,0xAB,0xC6,0x86,0xBA,0x00,0x00, +0x88,0x9E,0xAB,0x00,0xE9,0x58,0xFF,0x90,0xA1,0x84,0x12,0x2B,0xC1,0x72,0x11,0xA3, +0x84,0x12,0xBE,0x68,0x13,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0x66,0x13,0xF8,0xC3, +0xF9,0xC3,0xA1,0x84,0x12,0x41,0x41,0x2B,0xC1,0x72,0x23,0xA3,0x84,0x12,0x8B,0xC1, +0x48,0x48,0x32,0xE4,0x0C,0x80,0x86,0xC4,0xEF,0x90,0x90,0x90,0x90,0x90,0xBE,0xDC, +0x12,0x49,0x49,0xD1,0xE9,0xF3,0x6F,0x90,0x89,0x0E,0xDA,0x12,0xF8,0xC3,0xF9,0xC3, +0x8A,0xC8,0x8A,0x46,0x4C,0xB4,0x01,0x83,0xEB,0x06,0xEF,0x90,0x90,0x90,0x90,0x90, +0xB8,0x01,0x00,0xEF,0x90,0x90,0x90,0x90,0x90,0x8A,0xC1,0xEF,0x90,0x90,0x90,0x90, +0x90,0xE9,0x97,0x00,0xE9,0xAC,0x00,0x33,0xC0,0x8E,0xD8,0x89,0x1E,0x84,0x12,0xC3, +0x36,0x8B,0x1E,0x84,0x12,0xFB,0x90,0xFA,0xB0,0x0C,0xE8,0x89,0xC7,0x85,0xED,0x74, +0xE6,0xC5,0x76,0x0C,0x83,0xFB,0x14,0x72,0xDB,0xFB,0x90,0xFA,0xAD,0x85,0xC0,0x78, +0xAF,0x74,0xE2,0x8B,0xFE,0x03,0xF8,0x36,0x8B,0x0E,0x86,0x12,0x3B,0xC1,0x77,0x02, +0x8B,0xC8,0x83,0xEB,0x04,0x3B,0xD9,0x77,0x02,0x8B,0xCB,0x33,0xC0,0x8A,0x46,0x4C, +0xEF,0x90,0x90,0x90,0x90,0x90,0x8B,0xC1,0xEF,0x90,0x90,0x90,0x90,0x90,0x41,0x80, +0xE1,0xFE,0x2B,0xD9,0x51,0xD1,0xE9,0xF3,0x6F,0x90,0x59,0x8B,0xC7,0x40,0x24,0xFE, +0x3B,0xC6,0x74,0x27,0x2B,0xFE,0x4E,0x4E,0x53,0x8B,0x5E,0x10,0x3B,0xF3,0x72,0x13, +0x03,0x1F,0x83,0xC3,0x03,0x80,0xE3,0xFE,0xC7,0x07,0x00,0x00,0x83,0x6E,0x74,0x02, +0x89,0x5E,0x10,0x5B,0x89,0x3C,0x89,0x76,0x0C,0xEB,0x89,0x89,0x76,0x0C,0x39,0x76, +0x10,0x77,0x81,0x72,0x08,0x83,0x3C,0x00,0x74,0x03,0xE9,0x77,0xFF,0xE8,0x0D,0xBE, +0xE9,0x62,0xFF,0x36,0x89,0x1E,0x84,0x12,0xB0,0x0C,0xE8,0xB5,0xC6,0x33,0xC0,0x8E, +0xD8,0xC3,0xA1,0x84,0x12,0x3D,0x10,0x00,0x72,0x77,0xBA,0x04,0x01,0x3B,0x06,0x88, +0x12,0x75,0x06,0xC7,0x06,0x7E,0x12,0x00,0x00,0x8B,0x0E,0xDA,0x12,0xE3,0x0B,0xE8, +0xD0,0xFE,0x72,0x57,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x20,0x13,0xE3,0x0B, +0xE8,0xA5,0xFD,0x72,0x46,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0x8B,0x0E,0x66,0x13,0xE3, +0x0B,0xE8,0x94,0xFE,0x72,0x35,0xC7,0x06,0x7E,0x12,0xFF,0x7F,0xA1,0x28,0x01,0xA9, +0x01,0x00,0x75,0x03,0xE8,0xF9,0xFE,0x80,0x3E,0x8D,0x12,0x00,0x75,0x1D,0xA1,0x84, +0x12,0x3D,0x20,0x00,0x76,0x15,0x3B,0x06,0x82,0x12,0x76,0x09,0xA1,0x7E,0x12,0x3B, +0x06,0x80,0x12,0x72,0x0C,0x80,0x0E,0x90,0x12,0x80,0xC3,0xB0,0x80,0xFF,0x16,0x7C, +0x12,0xC3,0x80,0x0E,0x90,0x12,0x40,0xC3,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x17, +0x9C,0x0E,0xE8,0xB7,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x20,0x9C,0x0E,0xE8, +0xAA,0xC8,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x16,0x9C,0x0E,0xE8,0x9D,0xC8,0x90, +0xBA,0x06,0x01,0xEC,0xA8,0x20,0x75,0xCA,0xFB,0x90,0xFA,0xBA,0x04,0x01,0xED,0x90, +0x90,0x90,0x90,0x90,0x3A,0x06,0x94,0x12,0x77,0xBE,0x33,0xDB,0x8A,0xD8,0xD1,0xE3, +0x2E,0x8B,0xAF,0x44,0x00,0xC4,0x7E,0x08,0x85,0xFF,0x74,0xB9,0xF6,0xC4,0xC0,0x75, +0x55,0x32,0xC0,0xC1,0xE0,0x02,0x80,0xE4,0xF0,0x8B,0xF0,0xED,0x90,0x90,0x90,0x90, +0x90,0x85,0xC0,0x74,0xBB,0x8B,0xC8,0x41,0x80,0xE1,0xFE,0x0B,0xC6,0x8B,0x5E,0x50, +0x4B,0x4B,0x2B,0xD9,0x78,0x9C,0xAB,0x8B,0xC1,0x40,0x40,0x01,0x46,0x4E,0xD1,0xE9, +0xF3,0x6D,0x90,0x89,0x5E,0x50,0x89,0x7E,0x08,0x8B,0x46,0x26,0x80,0xE4,0xEF,0x89, +0x46,0x26,0xF6,0xC4,0x01,0x75,0x0C,0xF7,0x46,0x48,0x0C,0x00,0x75,0x05,0xB0,0x02, +0xE8,0x7F,0xC5,0xE9,0x7A,0xFF,0x86,0xC4,0x8B,0xC8,0x83,0xE1,0x3F,0x41,0x80,0xE1, +0xFE,0xE3,0x0A,0x3C,0x80,0x72,0x09,0x24,0x3F,0xB4,0xF0,0xEB,0xB0,0xE9,0x60,0xFF, +0x25,0x3F,0x00,0x33,0xFF,0x8E,0xC7,0xBF,0x96,0x12,0x8B,0xF7,0xD1,0xE9,0xF3,0x6D, +0x90,0x8B,0xC8,0xE8,0x48,0xED,0xE9,0x47,0xFF,0x90,0x6A,0x00,0x1F,0xC6,0x06,0x93, +0x12,0x1B,0x9C,0x0E,0xE8,0xD5,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E, +0xC0,0xBA,0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xB0,0x06,0xEE,0xEC,0xA2,0x8C,0x12, 0xA8,0x40,0x74,0x11,0xA1,0x88,0x12,0xA3,0x84,0x12,0xC6,0x06,0x8D,0x12,0x00,0xE8, -0x12,0xFE,0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0xB6,0xFE,0xB8,0x00,0x80,0xBA, -0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0xEE,0x86,0xE0,0xEE,0x86,0xE0,0xEC,0x86, -0xE0,0xEC,0x86,0xE0,0x80,0xE1,0xFE,0xF3,0x6C,0x90,0x80,0xE1,0xFE,0xF3,0x6E,0x90, -0x05,0x00,0x57,0x47,0x8A,0x4B,0x05,0x00,0x57,0x48,0x8A,0x4B,0x05,0x00,0x85,0x48, -0x8A,0x4B,0x05,0x00,0x17,0x49,0x8A,0x4B,0x06,0x00,0x7A,0x48,0x78,0x4B,0x06,0x00, -0x9C,0x48,0x78,0x4B,0x06,0x00,0xA5,0x48,0x78,0x4B,0x06,0x00,0xAD,0x48,0x78,0x4B, -0x06,0x00,0x02,0x49,0x78,0x4B,0x06,0x00,0x0A,0x49,0x78,0x4B,0x06,0x00,0x30,0x4A, -0x7E,0x4B,0x06,0x00,0x5D,0x4A,0x7E,0x4B,0x05,0x00,0x80,0x4A,0x84,0x4B,0x05,0x00, -0xCE,0x4A,0x84,0x4B,0x00,0x00,0x1E,0x06,0x83,0x3E,0x44,0x12,0x00,0x74,0x09,0xA0, -0x06,0x01,0x24,0x30,0x3C,0x30,0x74,0x1A,0x8C,0xC8,0x8E,0xD8,0x8E,0xC0,0xBB,0x90, -0x4B,0x8B,0x0F,0xE3,0x0D,0x8B,0x7F,0x02,0x8B,0x77,0x04,0xF3,0xA4,0x83,0xC3,0x06, -0xEB,0xEF,0x07,0x1F,0xC3,0x90,0x33,0xC0,0xA3,0x3E,0x01,0xB9,0x0C,0x01,0xBE,0x40, -0x01,0x8B,0xFE,0x81,0xC6,0xB4,0x0F,0x89,0x04,0x8B,0xC6,0x2B,0xF1,0x3B,0xC7,0x77, -0xF6,0xA3,0x3C,0x01,0xC3,0x90,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x8B,0x5E, -0x00,0x3B,0xEB,0x74,0x2B,0x8B,0x76,0x02,0x89,0x1C,0x89,0x77,0x02,0x36,0xA1,0x3C, -0x01,0x89,0x46,0x00,0x36,0x89,0x2E,0x3C,0x01,0x8B,0xEB,0xFF,0x4E,0x06,0x74,0x08, -0x8B,0x6E,0x00,0xFF,0x4E,0x06,0x75,0xF8,0x36,0x89,0x2E,0x3E,0x01,0x8B,0x66,0x04, -0x61,0x07,0x1F,0xC3,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x98,0x89,0x46,0x06, -0x89,0x66,0x04,0x3B,0x6E,0x00,0x74,0x10,0x8B,0x6E,0x00,0xFF,0x4E,0x06,0x75,0xF8, -0x36,0x89,0x2E,0x3E,0x01,0x8B,0x66,0x04,0x61,0x07,0x1F,0xC3,0xC3,0x90,0x1E,0x06, -0x60,0x9C,0xFA,0x33,0xED,0x8E,0xDD,0x8B,0x2E,0x3C,0x01,0x85,0xED,0x74,0x3D,0x8B, -0x4E,0x00,0x89,0x0E,0x3C,0x01,0x8B,0xCC,0x8D,0xA6,0x0A,0x01,0x56,0x1E,0x06,0x60, -0x89,0x66,0x04,0xC7,0x46,0x08,0x0F,0x1A,0xC7,0x46,0x06,0x01,0x00,0x8B,0x1E,0x3E, -0x01,0x85,0xDB,0x74,0x1D,0x8B,0xC5,0x87,0x07,0x89,0x46,0x00,0x89,0x5E,0x02,0x8B, -0xD8,0x89,0x6F,0x02,0x8B,0xE1,0x9D,0x61,0x07,0x1F,0xF8,0xC3,0x9D,0x61,0x07,0x1F, -0xF9,0xC3,0x89,0x2E,0x3E,0x01,0x89,0x6E,0x00,0x89,0x6E,0x02,0x87,0xE1,0x9D,0x8B, -0xE1,0xEB,0xE4,0x00,0x0D,0x0A,0x54,0x65,0x72,0x6D,0x69,0x6E,0x61,0x6C,0x73,0x20, -0x73,0x75,0x70,0x70,0x6F,0x72,0x74,0x65,0x64,0x3A,0x0D,0x0A,0x31,0x29,0x20,0x41, -0x4E,0x53,0x49,0x20,0x63,0x6F,0x6D,0x70,0x61,0x74,0x69,0x62,0x6C,0x65,0x0D,0x0A, -0x32,0x29,0x20,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x0D,0x0A,0x50,0x6C,0x65,0x61, -0x73,0x65,0x20,0x73,0x65,0x6C,0x65,0x63,0x74,0x3A,0x20,0x00,0x0D,0x0A,0x63,0x6F, -0x64,0x65,0x20,0x73,0x65,0x67,0x6D,0x65,0x6E,0x74,0x3D,0x00,0x0D,0x0A,0x4D,0x6F, -0x6E,0x69,0x74,0x6F,0x72,0x20,0x76,0x32,0x2E,0x35,0x0A,0x0D,0x0A,0x3E,0x00,0x0D, -0x0A,0x50,0x61,0x72,0x64,0x6F,0x6E,0x3F,0x00,0x0D,0x0A,0x4E,0x6F,0x20,0x61,0x64, -0x64,0x72,0x65,0x73,0x73,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x00, -0x0D,0x0A,0x3A,0x00,0x0D,0x0A,0x00,0x4C,0x6F,0x63,0x3D,0x00,0x0D,0x0A,0x46,0x41, -0x54,0x41,0x4C,0x20,0x45,0x52,0x52,0x4F,0x52,0x3D,0x00,0x0D,0x0A,0x4D,0x6F,0x6E, -0x69,0x74,0x6F,0x72,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x73,0x3A,0x2D,0x0D, -0x0A,0x20,0x20,0x20,0x44,0x2C,0x64,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78, -0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x6D,0x65,0x6D,0x6F, -0x72,0x79,0x0D,0x0A,0x20,0x20,0x20,0x4C,0x2C,0x6C,0x5B,0x5B,0x78,0x78,0x78,0x78, -0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x73, -0x69,0x6E,0x67,0x6C,0x65,0x20,0x6C,0x69,0x6E,0x65,0x0D,0x0A,0x20,0x20,0x20,0x45, -0x2C,0x65,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20, -0x2D,0x20,0x65,0x64,0x69,0x74,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,0x0D,0x0A,0x20, -0x20,0x20,0x46,0x2C,0x66,0x5B,0x5B,0x78,0x78,0x78,0x78,0x20,0x5D,0x78,0x78,0x78, -0x78,0x5D,0x20,0x2D,0x20,0x66,0x69,0x6C,0x6C,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79, -0x20,0x70,0x61,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x0D,0x0A,0x20,0x20,0x20, -0x49,0x5B,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, -0x20,0x2D,0x20,0x77,0x6F,0x72,0x64,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72, -0x6F,0x6D,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x69,0x5B,0x78,0x78, -0x78,0x78,0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62, -0x79,0x74,0x65,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72,0x6F,0x6D,0x20,0x70, -0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x4F,0x78,0x78,0x78,0x78,0x20,0x78,0x78, -0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75, -0x74,0x20,0x77,0x6F,0x72,0x64,0x20,0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A, -0x20,0x20,0x20,0x6F,0x78,0x78,0x78,0x78,0x20,0x78,0x78,0x20,0x20,0x20,0x20,0x20, -0x20,0x20,0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75,0x74,0x20,0x62,0x79,0x74, -0x65,0x20,0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x47,0x5B, -0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x2D, -0x20,0x67,0x6F,0x74,0x6F,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x0D,0x0A,0x20, -0x20,0x20,0x57,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D, -0x20,0x20,0x20,0x2D,0x20,0x77,0x61,0x74,0x63,0x68,0x20,0x61,0x20,0x77,0x6F,0x72, -0x64,0x0D,0x0A,0x20,0x20,0x20,0x43,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, -0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69,0x6E,0x74,0x65,0x72,0x72,0x75, -0x70,0x74,0x73,0x20,0x6F,0x66,0x66,0x0D,0x0A,0x20,0x20,0x20,0x53,0x20,0x20,0x20, -0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69, -0x6E,0x74,0x65,0x72,0x72,0x75,0x70,0x74,0x73,0x20,0x6F,0x6E,0x0D,0x0A,0x20,0x20, -0x20,0x73,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, -0x20,0x20,0x2D,0x20,0x73,0x69,0x6E,0x67,0x6C,0x65,0x20,0x73,0x74,0x65,0x70,0x0D, -0x0A,0x20,0x20,0x20,0x42,0x78,0x78,0x78,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20, -0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65,0x61,0x6B,0x70,0x6F,0x69,0x6E, -0x74,0x20,0x73,0x65,0x74,0x0D,0x0A,0x20,0x20,0x20,0x62,0x20,0x20,0x20,0x20,0x20, -0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65, -0x61,0x6B,0x70,0x6F,0x69,0x6E,0x74,0x20,0x63,0x6C,0x65,0x61,0x72,0x0D,0x0A,0x20, -0x20,0x20,0x52,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, -0x20,0x20,0x20,0x2D,0x20,0x72,0x65,0x73,0x74,0x61,0x72,0x74,0x20,0x62,0x72,0x65, -0x61,0x6B,0x70,0x6F,0x69,0x6E,0x74,0x0D,0x0A,0x20,0x20,0x20,0x72,0x20,0x20,0x20, -0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x72, -0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x20,0x61,0x74,0x20,0x62,0x72,0x6B,0x70, -0x74,0x0D,0x0A,0x20,0x20,0x20,0x58,0x2C,0x78,0x20,0x6E,0x20,0x20,0x20,0x20,0x20, -0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x65,0x78,0x61,0x6D,0x69,0x6E,0x65, -0x20,0x63,0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x6E,0x0D,0x0A,0x20,0x20,0x20,0x48, -0x2C,0x3F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, -0x2D,0x20,0x74,0x68,0x69,0x73,0x20,0x6D,0x65,0x73,0x73,0x61,0x67,0x65,0x00,0x1B, -0x5B,0x32,0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x41,0x4E,0x53,0x49,0x20,0x54,0x65, -0x72,0x6D,0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x0A,0x00,0x1B,0x5B,0x4B,0x00,0x1B,0x5B, -0x4A,0x00,0x1B,0x5B,0x32,0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x00,0x1B,0x5B,0x44, -0x20,0x1B,0x5B,0x44,0x00,0x1B,0x5B,0x31,0x3B,0x37,0x32,0x48,0x00,0x1B,0x5B,0x00, -0x3B,0x00,0x48,0x00,0x1B,0x5B,0x73,0x00,0x1B,0x5B,0x75,0x00,0x1B,0x7A,0x2B,0x0B, -0x7F,0x1B,0x7A,0x2E,0x0C,0x7F,0x1B,0x7A,0x2D,0x08,0x7F,0x1B,0x7A,0x2C,0x0A,0x7F, -0x1B,0x7A,0x22,0x08,0x7F,0x1A,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x20,0x54,0x65, -0x72,0x6D,0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x00,0x1B,0x54,0x00,0x1B,0x59,0x00,0x1A, -0x00,0x1E,0x00,0x08,0x20,0x08,0x00,0x00,0x1B,0x3D,0x00,0x00,0x00,0x1B,0x46,0x00, -0x0D,0x00,0x3F,0x44,0x64,0x45,0x65,0x46,0x66,0x47,0x67,0x48,0x68,0x49,0x69,0x4F, -0x6F,0x43,0x63,0x53,0x73,0x42,0x62,0x52,0x72,0x57,0x77,0x58,0x78,0x4C,0x6C,0x1E, -0x60,0xB6,0x57,0xB6,0x57,0x32,0x58,0x32,0x58,0xB8,0x59,0xB8,0x59,0x96,0x59,0x96, -0x59,0x1E,0x60,0x1E,0x60,0x4E,0x57,0x2A,0x57,0x08,0x57,0xE8,0x56,0x72,0x57,0x72, -0x57,0x7A,0x57,0x2A,0x5F,0xEE,0x5E,0x3A,0x5F,0x15,0x5F,0x22,0x5F,0x82,0x57,0x82, -0x57,0xE0,0x59,0xE0,0x59,0xBE,0x57,0xBE,0x57,0x6A,0x61,0x7A,0x61,0xA2,0x61,0xAE, -0x61,0xBA,0x61,0xD8,0x61,0xE4,0x61,0x04,0x62,0xDA,0x56,0x2C,0x62,0x3A,0x62,0x42, -0x59,0x20,0x20,0x66,0x6C,0x61,0x67,0x73,0x3D,0x00,0x20,0x20,0x61,0x78,0x3D,0x00, -0x20,0x20,0x62,0x78,0x3D,0x00,0x20,0x20,0x63,0x78,0x3D,0x00,0x20,0x20,0x64,0x78, -0x3D,0x00,0x20,0x20,0x63,0x73,0x3D,0x00,0x20,0x20,0x64,0x73,0x3D,0x00,0x20,0x20, -0x65,0x73,0x3D,0x00,0x20,0x20,0x73,0x73,0x3D,0x00,0x20,0x20,0x64,0x69,0x3D,0x00, -0x20,0x20,0x73,0x69,0x3D,0x00,0x20,0x20,0x62,0x70,0x3D,0x00,0x20,0x20,0x73,0x70, -0x3D,0x00,0x20,0x20,0x69,0x70,0x3D,0x00,0x20,0x63,0x68,0x61,0x6E,0x65,0x6C,0x3D, -0x00,0x20,0x20,0x20,0x20,0x73,0x65,0x67,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74, -0x72,0x3D,0x00,0x20,0x74,0x69,0x5F,0x74,0x6F,0x73,0x3D,0x00,0x20,0x74,0x69,0x5F, -0x6D,0x61,0x78,0x3D,0x00,0x20,0x74,0x69,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74, -0x69,0x5F,0x73,0x69,0x7A,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74,0x66,0x3D,0x00, -0x20,0x74,0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x74,0x69,0x5F,0x66,0x6C,0x67, -0x3D,0x00,0x20,0x74,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x70, -0x63,0x6E,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x72,0x69, -0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x72,0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20, -0x72,0x69,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x69,0x7A,0x3D, -0x00,0x20,0x72,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x6D,0x69, -0x6E,0x3D,0x00,0x20,0x72,0x69,0x5F,0x66,0x6C,0x67,0x3D,0x00,0x20,0x72,0x69,0x5F, -0x74,0x6F,0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x74,0x68,0x72,0x3D,0x00,0x20,0x74, -0x68,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x74,0x72,0x3D,0x00, -0x20,0x74,0x68,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x69,0x7A, -0x3D,0x00,0x20,0x74,0x68,0x5F,0x74,0x72,0x67,0x3D,0x00,0x20,0x74,0x68,0x5F,0x66, -0x6C,0x67,0x3D,0x00,0x20,0x74,0x68,0x5F,0x63,0x6E,0x74,0x3D,0x00,0x20,0x72,0x68, -0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20, -0x72,0x68,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x69,0x7A,0x3D, -0x00,0x20,0x72,0x68,0x5F,0x73,0x70,0x61,0x3D,0x00,0x20,0x72,0x68,0x5F,0x61,0x73, -0x6F,0x3D,0x00,0x20,0x72,0x68,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x72,0x68,0x5F, -0x66,0x6C,0x67,0x3D,0x00,0x20,0x6D,0x5F,0x63,0x61,0x72,0x65,0x3D,0x00,0x20,0x70, -0x74,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x61,0x73,0x5F,0x66,0x6C,0x6F,0x3D,0x00, -0x20,0x72,0x6D,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x20,0x20,0x71,0x5F,0x69,0x6E, -0x3D,0x00,0x20,0x20,0x71,0x5F,0x6F,0x75,0x74,0x3D,0x00,0x20,0x71,0x5F,0x64,0x72, -0x61,0x6E,0x3D,0x00,0x20,0x20,0x71,0x5F,0x74,0x69,0x6D,0x3D,0x00,0x20,0x20,0x20, -0x71,0x5F,0x66,0x63,0x3D,0x00,0x20,0x71,0x5F,0x73,0x74,0x61,0x74,0x3D,0x00,0x20, -0x71,0x5F,0x64,0x61,0x74,0x61,0x3D,0x00,0x20,0x71,0x5F,0x6D,0x6F,0x64,0x6D,0x3D, -0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x6F,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F, -0x62,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x65,0x3D,0x00,0x20,0x68,0x61,0x6E, -0x64,0x5F,0x69,0x3D,0x00,0x20,0x20,0x6F,0x70,0x6F,0x73,0x74,0x3D,0x00,0x20,0x20, -0x74,0x69,0x6D,0x65,0x6F,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x31,0x3D,0x00, -0x20,0x63,0x75,0x73,0x74,0x6D,0x32,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x64, -0x3D,0x00,0x20,0x74,0x78,0x72,0x61,0x74,0x65,0x3D,0x00,0x20,0x72,0x78,0x72,0x61, -0x74,0x65,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x61,0x70,0x3D,0x00,0x20,0x63,0x5F, -0x61,0x64,0x64,0x72,0x3D,0x00,0x20,0x63,0x5F,0x61,0x69,0x73,0x72,0x3D,0x00,0x20, -0x63,0x5F,0x78,0x74,0x61,0x67,0x3D,0x00,0x20,0x63,0x5F,0x64,0x65,0x66,0x72,0x3D, -0x00,0x20,0x63,0x5F,0x66,0x6C,0x73,0x68,0x3D,0x00,0x20,0x74,0x78,0x6D,0x61,0x78, -0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x65,0x6D,0x73,0x3D,0x00,0x20,0x20,0x63,0x5F, -0x6C,0x73,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x65,0x72,0x3D,0x00,0x20,0x20, -0x63,0x5F,0x66,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x63,0x72,0x3D,0x00, -0x20,0x20,0x63,0x5F,0x6C,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x64,0x73,0x73, -0x3D,0x00,0x20,0x63,0x5F,0x64,0x73,0x73,0x69,0x3D,0x00,0x20,0x63,0x5F,0x64,0x73, -0x73,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x73,0x72,0x3D,0x00,0x20,0x20,0x63, -0x5F,0x63,0x61,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x65,0x66,0x72,0x3D,0x00,0x20, -0x63,0x5F,0x65,0x72,0x73,0x74,0x3D,0x00,0x20,0x63,0x5F,0x65,0x63,0x6E,0x74,0x3D, -0x00,0x20,0x63,0x5F,0x62,0x72,0x6B,0x63,0x3D,0x00,0x20,0x63,0x5F,0x62,0x6F,0x6B, -0x63,0x3D,0x00,0x20,0x63,0x5F,0x72,0x65,0x70,0x6C,0x3D,0x00,0x20,0x63,0x5F,0x63, -0x63,0x73,0x72,0x3D,0x00,0x20,0x63,0x5F,0x73,0x74,0x74,0x31,0x3D,0x00,0x20,0x63, -0x5F,0x73,0x74,0x74,0x32,0x3D,0x00,0x2B,0xC0,0x8E,0xD8,0x8E,0xC0,0xE8,0xC2,0x00, -0xE8,0xE5,0x00,0xFA,0xBF,0x84,0x00,0xC7,0x05,0xBE,0x56,0x8C,0x4D,0x02,0xBF,0x0C, -0x00,0xC7,0x05,0x50,0x5E,0x8C,0x4D,0x02,0xBF,0x04,0x00,0xC7,0x05,0x9C,0x5E,0x8C, -0x4D,0x02,0xE8,0xF1,0x00,0x90,0xE8,0x49,0x01,0xE8,0x16,0x00,0xF4,0x90,0xE8,0xE5, -0x00,0xBE,0x9C,0x4D,0xE8,0x09,0x0C,0xA0,0x93,0x12,0xE8,0x5D,0x0C,0xE8,0xC2,0x09, -0xEB,0xE4,0xE8,0xD5,0x0C,0xE8,0xC4,0x0C,0x0A,0xC0,0x74,0xF6,0x8B,0x1E,0xF8,0x79, -0x3C,0x0D,0x74,0x2E,0x3C,0x08,0x74,0x17,0x3C,0x7F,0x74,0x13,0x83,0xFB,0x20,0x7F, -0xE1,0x88,0x87,0xD6,0x79,0x43,0x89,0x1E,0xF8,0x79,0xE8,0x77,0x0C,0xEB,0xD3,0x0B, -0xDB,0x74,0xCF,0x4B,0x89,0x1E,0xF8,0x79,0x8B,0x36,0x16,0x7A,0xE8,0xC1,0x0B,0xEB, -0xC1,0x90,0xE8,0x02,0x00,0xEB,0xBB,0xC6,0x87,0xD6,0x79,0x00,0x0B,0xDB,0x74,0x1E, -0xA0,0xD6,0x79,0xBF,0x42,0x51,0xB9,0x1D,0x00,0x8B,0xD9,0x06,0x0E,0x07,0xF2,0xAE, -0x07,0x75,0x17,0x41,0x2B,0xD9,0xD1,0xE3,0x2E,0xFF,0x97,0x5F,0x51,0x90,0x33,0xC0, -0xA3,0xF8,0x79,0xBE,0x6B,0x4D,0xE8,0x87,0x0B,0xC3,0xBE,0x6F,0x4D,0xE8,0x80,0x0B, -0xEB,0xEC,0xBA,0x00,0x02,0xB0,0x93,0xEE,0xB0,0x55,0xEE,0xBA,0x10,0x02,0xB0,0x93, -0xEE,0xB0,0xAA,0xEE,0xBA,0x00,0x02,0xEC,0x3C,0x55,0x75,0x08,0xBA,0x10,0x02,0xEC, -0x3C,0xAA,0x74,0x03,0xE8,0x2F,0xF6,0xC3,0xBA,0x04,0x02,0xB0,0x1A,0xEE,0xB0,0x20, -0xEE,0xB0,0x30,0xEE,0xB0,0x40,0xEE,0xB0,0x80,0xEE,0xBA,0x00,0x02,0xB0,0x13,0xEE, -0xB0,0x07,0xEE,0xBA,0x08,0x02,0xB0,0x80,0xEE,0xBA,0x02,0x02,0xB0,0xBB,0xEE,0xBA, -0x04,0x02,0xB0,0x05,0xEE,0xC3,0xC6,0x06,0xCA,0x13,0x01,0xC7,0x06,0xF8,0x79,0x00, -0x00,0xC6,0x06,0xF6,0x79,0x01,0xC7,0x06,0xD0,0x79,0x00,0x00,0xC7,0x06,0xD2,0x79, -0x00,0x00,0xC7,0x06,0xD4,0x79,0x00,0x00,0xC7,0x06,0xFA,0x79,0x00,0x00,0xC7,0x06, -0xFC,0x79,0x00,0x00,0xC7,0x06,0xFE,0x79,0x00,0x00,0xC7,0x06,0x00,0x7A,0x00,0x00, -0xC7,0x06,0x02,0x7A,0xB0,0x59,0x8C,0x0E,0x04,0x7A,0xC7,0x06,0x06,0x7A,0x00,0x00, -0xC7,0x06,0x27,0x7A,0x00,0x00,0xC6,0x06,0x29,0x7A,0x00,0xC6,0x06,0x2A,0x7A,0x00, -0xC3,0x90,0xBE,0x04,0x4D,0xE8,0xC8,0x0A,0xE8,0x3F,0x00,0x2C,0x31,0x3C,0x01,0x77, -0xF7,0xE8,0x81,0x09,0x8B,0x36,0x0C,0x7A,0xE8,0xB5,0x0A,0xBE,0x4C,0x4D,0xE8,0xAF, -0x0A,0x0E,0x58,0xE8,0xF8,0x0A,0xBE,0x5C,0x4D,0xE8,0xA4,0x0A,0xC3,0x90,0x60,0xD1, -0xE3,0x83,0xFB,0x18,0x73,0x11,0x1E,0xBA,0x00,0x00,0x8E,0xDA,0x2E,0xFF,0x97,0x99, -0x51,0x8B,0xEC,0x89,0x46,0x10,0x1F,0x61,0xCF,0x90,0xE8,0x4F,0x0B,0x0A,0xC0,0x75, -0x05,0xE8,0x56,0x0B,0xEB,0xF4,0xC3,0x90,0x83,0x3E,0xF8,0x79,0x01,0x74,0x16,0xBE, -0xD7,0x79,0xE8,0x31,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x04,0x3C,0x20,0x75,0x05, -0xE8,0x23,0x0A,0xEE,0xC3,0xE9,0xD2,0xFE,0x83,0x3E,0xF8,0x79,0x01,0x74,0xF6,0xBE, -0xD7,0x79,0xE8,0x11,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x08,0x3C,0x20,0x74,0x04, -0xE9,0xB7,0xFE,0x90,0xE8,0xFF,0x09,0xEF,0xC3,0x90,0x8B,0x16,0x06,0x7A,0x83,0x3E, -0xF8,0x79,0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xEB,0x09,0x8B,0xD0,0xA3,0x06,0x7A, -0xB0,0x20,0xE8,0x57,0x0B,0x8B,0x16,0x06,0x7A,0xEC,0xE8,0x6F,0x0B,0xC3,0x8B,0x16, -0x06,0x7A,0x83,0x3E,0xF8,0x79,0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xC7,0x09,0x8B, -0xD0,0xA3,0x06,0x7A,0xB0,0x20,0xE8,0x33,0x0B,0x8B,0x16,0x06,0x7A,0xED,0xE8,0x67, -0x0B,0xC3,0xFA,0xC6,0x06,0xF6,0x79,0x00,0xC3,0x90,0xC6,0x06,0xF6,0x79,0x01,0xFB, -0xC3,0x90,0x06,0xE8,0x58,0x09,0xB0,0x20,0xE8,0x11,0x0B,0x26,0x8B,0x05,0xE8,0x47, -0x0B,0xB0,0x08,0xE8,0x06,0x0B,0xE8,0x03,0x0B,0xE8,0x00,0x0B,0xE8,0xFD,0x0A,0xB8, -0x01,0x00,0xE8,0xCF,0xF4,0xBA,0x02,0x02,0xEC,0x24,0x01,0x75,0x02,0xEB,0xDC,0xBA, -0x06,0x02,0xEC,0x07,0xC3,0x90,0xC7,0x06,0x08,0x7A,0x10,0x00,0xEB,0x06,0xC7,0x06, -0x08,0x7A,0x01,0x00,0x06,0x8E,0x06,0xFC,0x79,0x8B,0x3E,0xFA,0x79,0xE8,0x0E,0x09, -0xE8,0x0B,0x00,0x89,0x3E,0xFA,0x79,0x8C,0x06,0xFC,0x79,0x07,0xC3,0x90,0xBE,0x94, -0x4D,0xE8,0x7C,0x09,0x8B,0x16,0x08,0x7A,0x52,0xE8,0x2A,0x09,0xE8,0x0F,0x0A,0xE8, -0x0C,0x0A,0x33,0xDB,0xB9,0x10,0x00,0x90,0x26,0x8A,0x01,0xE8,0xBC,0x09,0xE8,0xFD, -0x09,0x43,0xE2,0xF4,0xE8,0xF7,0x09,0xE8,0xF4,0x09,0x33,0xDB,0xB9,0x10,0x00,0x90, -0x26,0x8A,0x01,0x3C,0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xE3, -0x09,0x43,0xE2,0xEC,0xBE,0x94,0x4D,0xE8,0x36,0x09,0x83,0xC7,0x10,0x5A,0x4A,0x75, -0xB7,0xC3,0x06,0x8E,0x06,0x00,0x7A,0x8B,0x3E,0xFE,0x79,0xE8,0xA0,0x08,0x89,0x3E, -0xFE,0x79,0x8C,0x06,0x00,0x7A,0x57,0x8B,0x36,0x0E,0x7A,0xE8,0x12,0x09,0xC7,0x06, -0x08,0x7A,0x10,0x00,0xBA,0x00,0x02,0xE8,0xE8,0x00,0xE8,0x81,0xFF,0x5F,0xBA,0x00, -0x00,0xE8,0xDE,0x00,0xBE,0x97,0x4D,0xE8,0xF6,0x08,0x8C,0xC0,0xE8,0x3F,0x09,0xB0, -0x3A,0xE8,0x90,0x09,0x8B,0xC7,0xE8,0x35,0x09,0xE8,0x7E,0x08,0xE8,0xC3,0x00,0x90, -0xE8,0xB7,0x09,0xE8,0xA6,0x09,0x0A,0xC0,0x74,0xF6,0x3C,0x0B,0x75,0x06,0x83,0xEF, -0x10,0xEB,0x19,0x90,0x3C,0x0A,0x75,0x06,0x83,0xC7,0x10,0xEB,0x0F,0x90,0x3C,0x0C, -0x75,0x04,0x47,0xEB,0x07,0x90,0x3C,0x08,0x75,0x24,0x4F,0x90,0x8B,0x36,0xFE,0x79, -0x8B,0xC7,0x2B,0xC6,0x3D,0x00,0x01,0x72,0xA5,0x3D,0x10,0x01,0x72,0x04,0x83,0xEE, -0x20,0x90,0x83,0xC6,0x10,0x89,0x36,0xFE,0x79,0x57,0x8B,0xFE,0xEB,0x80,0x3C,0x2E, -0x75,0x08,0xBA,0x01,0x13,0xE8,0x6A,0x00,0x07,0xC3,0xC6,0x06,0x0A,0x7A,0x02,0x32, -0xC9,0x90,0x3C,0x30,0x72,0x4C,0x3C,0x39,0x76,0x0C,0x24,0x5F,0x3C,0x41,0x72,0x42, -0x3C,0x46,0x77,0x3E,0x2C,0x07,0x2C,0x30,0x50,0xE8,0xCC,0x08,0x58,0x02,0xC8,0xFE, -0x0E,0x0A,0x7A,0x74,0x0F,0xC0,0xE1,0x04,0xE8,0x2F,0x09,0xE8,0x1E,0x09,0x0A,0xC0, -0x74,0xF6,0xEB,0xCE,0x26,0x88,0x0D,0xE8,0xE0,0x07,0x8A,0xD0,0xE8,0x23,0x00,0x8A, -0xC1,0x3C,0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xD5,0x08,0xE9, -0x70,0xFF,0xE8,0xC5,0x07,0xE8,0x0A,0x00,0x26,0x8A,0x05,0xE8,0x7C,0x08,0xE9,0x1D, -0xFF,0x90,0xF6,0x06,0x26,0x7A,0x02,0x75,0x02,0x86,0xF2,0x52,0x8B,0x36,0x1A,0x7A, -0xE8,0x0D,0x08,0x5A,0x52,0x8A,0xC6,0x02,0x06,0x24,0x7A,0xF6,0x06,0x26,0x7A,0x01, -0x75,0x06,0xE8,0x9F,0x08,0xEB,0x0D,0x90,0x32,0xE4,0xE8,0x0D,0x08,0x8B,0x36,0x1C, -0x7A,0xE8,0xEC,0x07,0x5A,0x8A,0xC2,0x02,0x06,0x25,0x7A,0xF6,0x06,0x26,0x7A,0x01, -0x75,0x06,0xE8,0x7F,0x08,0xEB,0x06,0x90,0x32,0xE4,0xE8,0xED,0x07,0x8B,0x36,0x1E, -0x7A,0xE8,0xCC,0x07,0xC3,0x90,0x06,0x8E,0x06,0x04,0x7A,0x8B,0x3E,0x02,0x7A,0xE8, -0x3C,0x07,0x89,0x3E,0x02,0x7A,0x8C,0x06,0x04,0x7A,0x07,0xFF,0x1E,0x02,0x7A,0xC3, -0xBE,0x79,0x4D,0xE8,0xAA,0x07,0xCB,0x90,0x06,0x57,0xBE,0xD7,0x79,0xE8,0x66,0x07, -0x8B,0xD8,0xE8,0x61,0x07,0x8B,0xC8,0x2B,0xCB,0x78,0x11,0x8E,0xC3,0xBF,0x00,0x00, -0xB8,0xFF,0xFF,0x51,0xB9,0x08,0x00,0xF3,0xAB,0x59,0xE2,0xF7,0x5F,0x07,0xC3,0x90, -0x06,0xBE,0xD7,0x79,0xE8,0x3F,0x07,0x8B,0xD8,0xD1,0xE3,0x2E,0x8B,0x9F,0x44,0x00, -0xBE,0x08,0x52,0xE8,0xF1,0x08,0x8B,0xC3,0xE8,0xDD,0x08,0xB8,0x01,0x00,0xE8,0x73, -0xF2,0xE8,0xE0,0x08,0xBE,0x11,0x52,0xE8,0xDD,0x08,0x8B,0x47,0x18,0xE8,0xC8,0x08, -0xBE,0x59,0x52,0xE8,0xD1,0x08,0x8B,0x47,0x26,0xE8,0xBC,0x08,0xBE,0x35,0x52,0xE8, -0xC5,0x08,0x8B,0x47,0x1E,0xE8,0xB0,0x08,0xBE,0x3E,0x52,0xE8,0xB9,0x08,0x8B,0x47, -0x20,0xE8,0xA4,0x08,0xBE,0x50,0x52,0xE8,0xAD,0x08,0x8B,0x47,0x24,0xE8,0x98,0x08, -0xBE,0x62,0x52,0xE8,0xA1,0x08,0x8B,0x47,0x2A,0xE8,0x8C,0x08,0xE8,0x95,0x08,0xBE, -0x1A,0x52,0xE8,0x92,0x08,0x8B,0x07,0xE8,0x7E,0x08,0xBE,0x23,0x52,0xE8,0x87,0x08, -0x8B,0x47,0x1A,0xE8,0x72,0x08,0xBE,0x2C,0x52,0xE8,0x7B,0x08,0x8B,0x47,0x1C,0xE8, -0x66,0x08,0xBE,0x47,0x52,0xE8,0x6F,0x08,0x8B,0x47,0x22,0xE8,0x5A,0x08,0xE8,0x63, -0x08,0xBE,0xB3,0x52,0xE8,0x60,0x08,0x8B,0x47,0x38,0xE8,0x4B,0x08,0xBE,0x8F,0x52, -0xE8,0x54,0x08,0x8B,0x47,0x30,0xE8,0x3F,0x08,0xBE,0x98,0x52,0xE8,0x48,0x08,0x8B, -0x47,0x32,0xE8,0x33,0x08,0xBE,0x86,0x52,0xE8,0x3C,0x08,0x8B,0x47,0x2E,0xE8,0x27, -0x08,0xBE,0xA1,0x52,0xE8,0x30,0x08,0x8B,0x47,0x34,0xE8,0x1B,0x08,0xE8,0x24,0x08, -0xBE,0x6B,0x52,0xE8,0x21,0x08,0x8B,0x47,0x04,0xE8,0x0C,0x08,0xBE,0x74,0x52,0xE8, -0x15,0x08,0x8B,0x47,0x14,0xE8,0x00,0x08,0xBE,0x7D,0x52,0xE8,0x09,0x08,0x8B,0x47, -0x2C,0xE8,0xF4,0x07,0xBE,0xAA,0x52,0xE8,0xFD,0x07,0x8B,0x47,0x36,0xE8,0xE8,0x07, -0xBE,0xBC,0x52,0xE8,0xF1,0x07,0x8B,0x47,0x3A,0xE8,0xDC,0x07,0xBE,0xC5,0x52,0xE8, -0xE5,0x07,0x8B,0x47,0x3C,0xE8,0xD0,0x07,0xE8,0xD9,0x07,0xBE,0xFB,0x52,0xE8,0xD6, -0x07,0x8B,0x47,0x48,0xE8,0xC1,0x07,0xBE,0xE0,0x52,0xE8,0xCA,0x07,0x8B,0x47,0x42, -0xE8,0xB5,0x07,0xBE,0xE9,0x52,0xE8,0xBE,0x07,0x8B,0x47,0x44,0xE8,0xA9,0x07,0xBE, -0x5E,0x53,0xE8,0xB2,0x07,0x8B,0x47,0x4C,0xE8,0x9D,0x07,0xBE,0x67,0x53,0xE8,0xA6, -0x07,0x8B,0x47,0x4E,0xE8,0x91,0x07,0xBE,0x70,0x53,0xE8,0x9A,0x07,0x8B,0x47,0x50, -0xE8,0x85,0x07,0xE8,0x8E,0x07,0xBE,0x04,0x53,0xE8,0x8B,0x07,0x8B,0x47,0x4A,0xE8, -0x76,0x07,0xBE,0xCE,0x52,0xE8,0x7F,0x07,0x8B,0x47,0x08,0xE8,0x6A,0x07,0xBE,0xD7, -0x52,0xE8,0x73,0x07,0x8B,0x47,0x40,0xE8,0x5E,0x07,0xBE,0xF2,0x52,0xE8,0x67,0x07, -0x8B,0x47,0x46,0xE8,0x52,0x07,0xE8,0x5B,0x07,0xBE,0x4C,0x53,0xE8,0x58,0x07,0x8B, -0x47,0x7A,0xE8,0x43,0x07,0xBE,0x1F,0x53,0xE8,0x4C,0x07,0x8B,0x47,0x70,0xE8,0x37, -0x07,0xBE,0x28,0x53,0xE8,0x40,0x07,0x8B,0x47,0x72,0xE8,0x2B,0x07,0xBE,0x31,0x53, -0xE8,0x34,0x07,0x8B,0x47,0x74,0xE8,0x1F,0x07,0xE8,0x28,0x07,0xBE,0x0D,0x53,0xE8, -0x25,0x07,0x8B,0x47,0x0C,0xE8,0x10,0x07,0xBE,0x16,0x53,0xE8,0x19,0x07,0x8B,0x47, -0x10,0xE8,0x04,0x07,0xBE,0x3A,0x53,0xE8,0x0D,0x07,0x8B,0x47,0x76,0xE8,0xF8,0x06, -0xBE,0x43,0x53,0xE8,0x01,0x07,0x8B,0x47,0x78,0xE8,0xEC,0x06,0xBE,0x55,0x53,0xE8, -0xF5,0x06,0x8B,0x47,0x3E,0xE8,0xE0,0x06,0xE8,0xE9,0x06,0xBE,0x79,0x53,0xE8,0xE6, -0x06,0x8B,0x47,0x52,0xE8,0xD1,0x06,0xBE,0x82,0x53,0xE8,0xDA,0x06,0x8B,0x47,0x54, -0xE8,0xC5,0x06,0xBE,0x8B,0x53,0xE8,0xCE,0x06,0x8B,0x47,0x56,0xE8,0xB9,0x06,0xBE, -0x94,0x53,0xE8,0xC2,0x06,0x8B,0x47,0x58,0xE8,0xAD,0x06,0xBE,0x9D,0x53,0xE8,0xB6, -0x06,0x8B,0x47,0x5A,0xE8,0xA1,0x06,0xBE,0xA6,0x53,0xE8,0xAA,0x06,0x8B,0x47,0x5C, -0xE8,0x95,0x06,0xE8,0x9E,0x06,0xBE,0xAF,0x53,0xE8,0x9B,0x06,0x8B,0x47,0x5E,0xE8, -0x86,0x06,0xBE,0xB8,0x53,0xE8,0x8F,0x06,0x8B,0x47,0x60,0xE8,0x7A,0x06,0xBE,0xC1, -0x53,0xE8,0x83,0x06,0x8B,0x47,0x62,0xE8,0x6E,0x06,0xBE,0xCA,0x53,0xE8,0x77,0x06, -0x8B,0x47,0x7C,0xE8,0x62,0x06,0xBE,0xD3,0x53,0xE8,0x6B,0x06,0x8B,0x47,0x7E,0xE8, -0x56,0x06,0xBE,0xDC,0x53,0xE8,0x5F,0x06,0x8B,0x87,0x80,0x00,0xE8,0x49,0x06,0xE8, -0x52,0x06,0xBE,0x24,0x54,0xE8,0x4F,0x06,0x8B,0x87,0x9E,0x00,0xE8,0x39,0x06,0xBE, -0xE5,0x53,0xE8,0x42,0x06,0x8B,0x47,0x64,0xE8,0x2D,0x06,0xBE,0xEE,0x53,0xE8,0x36, -0x06,0x8B,0x47,0x6E,0xE8,0x21,0x06,0xBE,0xF7,0x53,0xE8,0x2A,0x06,0x8B,0x87,0x8E, -0x00,0xE8,0x14,0x06,0xBE,0x00,0x54,0xE8,0x1D,0x06,0x8B,0x87,0x90,0x00,0xE8,0x07, -0x06,0xBE,0x09,0x54,0xE8,0x10,0x06,0x8B,0x87,0x92,0x00,0xE8,0xFA,0x05,0xE8,0x03, -0x06,0xBE,0x12,0x54,0xE8,0x00,0x06,0x8B,0x87,0x94,0x00,0xE8,0xEA,0x05,0xBE,0x1B, -0x54,0xE8,0xF3,0x05,0x8B,0x87,0x96,0x00,0xE8,0xDD,0x05,0xBE,0x51,0x54,0xE8,0xE6, -0x05,0x8B,0x87,0x98,0x00,0xE8,0xD0,0x05,0xBE,0x3F,0x54,0xE8,0xD9,0x05,0x8A,0x87, -0xA0,0x00,0xE8,0xA7,0x05,0xBE,0x36,0x54,0xE8,0xCC,0x05,0x8A,0x47,0x28,0xE8,0x9B, -0x05,0xBE,0x48,0x54,0xE8,0xC0,0x05,0x8A,0x87,0xA1,0x00,0xE8,0x8E,0x05,0xE8,0xB3, -0x05,0xBE,0x5A,0x54,0xE8,0xB0,0x05,0x8A,0x87,0xA2,0x00,0xE8,0x7E,0x05,0xBE,0x63, -0x54,0xE8,0xA3,0x05,0x8A,0x87,0xA3,0x00,0xE8,0x71,0x05,0xBE,0x6C,0x54,0xE8,0x96, -0x05,0x8A,0x87,0xA4,0x00,0xE8,0x64,0x05,0xBE,0x75,0x54,0xE8,0x89,0x05,0x8A,0x87, -0xA5,0x00,0xE8,0x57,0x05,0xBE,0x7E,0x54,0xE8,0x7C,0x05,0x8A,0x87,0xA6,0x00,0xE8, -0x4A,0x05,0xBE,0x87,0x54,0xE8,0x6F,0x05,0x8A,0x87,0xA7,0x00,0xE8,0x3D,0x05,0xBE, -0x90,0x54,0xE8,0x62,0x05,0x8A,0x87,0xA8,0x00,0xE8,0x30,0x05,0xE8,0x55,0x05,0xBE, -0x99,0x54,0xE8,0x52,0x05,0x8A,0x87,0xA9,0x00,0xE8,0x20,0x05,0xBE,0xA2,0x54,0xE8, -0x45,0x05,0x8A,0x87,0xAA,0x00,0xE8,0x13,0x05,0xBE,0xAB,0x54,0xE8,0x38,0x05,0x8A, -0x87,0xAB,0x00,0xE8,0x06,0x05,0xBE,0xB4,0x54,0xE8,0x2B,0x05,0x8A,0x87,0xAD,0x00, -0xE8,0xF9,0x04,0xBE,0xBD,0x54,0xE8,0x1E,0x05,0x8A,0x87,0xAE,0x00,0xE8,0xEC,0x04, -0xBE,0xC6,0x54,0xE8,0x11,0x05,0x8A,0x87,0xAF,0x00,0xE8,0xDF,0x04,0xBE,0xCF,0x54, -0xE8,0x04,0x05,0x8A,0x87,0xB0,0x00,0xE8,0xD2,0x04,0xE8,0xF7,0x04,0xBE,0xD8,0x54, -0xE8,0xF4,0x04,0x8A,0x87,0xB1,0x00,0xE8,0xC2,0x04,0xBE,0xE1,0x54,0xE8,0xE7,0x04, -0x8A,0x87,0xB2,0x00,0xE8,0xB5,0x04,0xBE,0xEA,0x54,0xE8,0xDA,0x04,0x8A,0x87,0xB3, -0x00,0xE8,0xA8,0x04,0xBE,0xF3,0x54,0xE8,0xCD,0x04,0x8A,0x87,0xBB,0x00,0xE8,0x9B, -0x04,0xE8,0xC0,0x04,0xBE,0xFC,0x54,0xE8,0xBD,0x04,0x8A,0x87,0xBC,0x00,0xE8,0x8B, -0x04,0xBE,0x05,0x55,0xE8,0xB0,0x04,0x8A,0x87,0xBE,0x00,0xE8,0x7E,0x04,0xBE,0x0E, -0x55,0xE8,0xA3,0x04,0x8A,0x87,0xBF,0x00,0xE8,0x71,0x04,0xE8,0x96,0x04,0x07,0xC3, -0x60,0x06,0x1E,0x16,0x8B,0xEC,0xFF,0x4E,0x16,0xF7,0x46,0x1A,0x00,0x02,0x74,0x01, -0xFB,0xB8,0x00,0x00,0x8E,0xD8,0x8E,0xC0,0x89,0x2E,0x2D,0x7A,0xE8,0xCB,0x00,0x81, -0x66,0x1A,0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8,0xD8,0x00,0xB8,0xE2,0x5E,0xA3, -0x2B,0x7A,0xE8,0x5D,0x00,0x80,0x3E,0x2A,0x7A,0x00,0x74,0x0A,0x81,0x4E,0x1A,0x00, -0x01,0xC6,0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61,0xCF,0x90,0x60,0x06,0x1E,0x16, -0x8B,0xEC,0xF7,0x46,0x1A,0x00,0x02,0x74,0x01,0xFB,0xB8,0x00,0x00,0x8E,0xD8,0x8E, -0xC0,0x89,0x2E,0x2D,0x7A,0x81,0x66,0x1A,0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8, -0x92,0x00,0xB8,0xE2,0x5E,0xA3,0x2B,0x7A,0xE8,0x17,0x00,0x80,0x3E,0x2A,0x7A,0x00, -0x74,0x0A,0x81,0x4E,0x1A,0x00,0x01,0xC6,0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61, -0xCF,0x90,0xB8,0xF0,0x00,0xE8,0x8C,0xED,0xFF,0x26,0x2B,0x7A,0xC3,0x90,0x06,0x53, -0x56,0x80,0x3E,0x29,0x7A,0x00,0x74,0x03,0xE8,0x3F,0x00,0xBE,0xD7,0x79,0xE8,0x25, -0x02,0x8B,0xD8,0xA3,0x27,0x7A,0x2E,0x8A,0x07,0xA2,0x29,0x7A,0xB0,0xCC,0x2E,0x88, -0x07,0x5E,0x5B,0x07,0xC3,0xC6,0x06,0x2A,0x7A,0x00,0xB8,0xEC,0x5E,0xA3,0x2B,0x7A, -0xC3,0x90,0x8B,0x2E,0x2D,0x7A,0xE8,0x2B,0x00,0xC3,0xC6,0x06,0x2A,0x7A,0x01,0xE8, -0x08,0x00,0xB8,0xEC,0x5E,0xA3,0x2B,0x7A,0xC3,0x90,0x57,0x80,0x3E,0x29,0x7A,0x00, -0x74,0x0F,0x8B,0x3E,0x27,0x7A,0xA0,0x29,0x7A,0x2E,0x88,0x05,0xC6,0x06,0x29,0x7A, -0x00,0x5F,0xC3,0x90,0xBE,0x94,0x4D,0xE8,0x06,0x02,0xBE,0xBA,0x51,0xE8,0x00,0x02, -0xFF,0x76,0x14,0x58,0xE8,0x47,0x02,0xBE,0xC0,0x51,0xE8,0xF3,0x01,0xFF,0x76,0x0E, -0x58,0xE8,0x3A,0x02,0xBE,0xC6,0x51,0xE8,0xE6,0x01,0xFF,0x76,0x12,0x58,0xE8,0x2D, -0x02,0xBE,0xCC,0x51,0xE8,0xD9,0x01,0xFF,0x76,0x10,0x58,0xE8,0x20,0x02,0xBE,0xF6, -0x51,0xE8,0xCC,0x01,0xFF,0x76,0x0A,0x58,0xE8,0x13,0x02,0xBE,0xFC,0x51,0xE8,0xBF, -0x01,0xFF,0x76,0x0C,0x58,0xE8,0x06,0x02,0xBE,0xB1,0x51,0xE8,0xB2,0x01,0xFF,0x76, -0x1A,0x58,0xE8,0xF9,0x01,0xBE,0x94,0x4D,0xE8,0xA5,0x01,0xBE,0xD2,0x51,0xE8,0x9F, -0x01,0xFF,0x76,0x18,0x58,0xE8,0xE6,0x01,0xBE,0xD8,0x51,0xE8,0x92,0x01,0xFF,0x76, -0x02,0x58,0xE8,0xD9,0x01,0xBE,0xDE,0x51,0xE8,0x85,0x01,0xFF,0x76,0x04,0x58,0xE8, -0xCC,0x01,0xBE,0xE4,0x51,0xE8,0x78,0x01,0xFF,0x76,0x00,0x58,0xE8,0xBF,0x01,0xBE, -0xEA,0x51,0xE8,0x6B,0x01,0xFF,0x76,0x06,0x58,0xE8,0xB2,0x01,0xBE,0xF0,0x51,0xE8, -0x5E,0x01,0xFF,0x76,0x08,0x58,0xE8,0xA5,0x01,0xBE,0x02,0x52,0xE8,0x51,0x01,0xFF, -0x76,0x16,0x58,0xE8,0x98,0x01,0xBE,0x6B,0x4D,0xE8,0x44,0x01,0xC3,0x90,0xBE,0xAB, -0x4D,0xE8,0x3C,0x01,0xC3,0x3C,0x00,0x74,0x05,0x3C,0x01,0x74,0x59,0xC3,0xC7,0x06, -0x0C,0x7A,0xAF,0x50,0xC7,0x06,0x0E,0x7A,0xD2,0x50,0xC7,0x06,0x10,0x7A,0xCA,0x50, -0xC7,0x06,0x12,0x7A,0xCE,0x50,0xC7,0x06,0x14,0x7A,0xD6,0x50,0xC7,0x06,0x16,0x7A, -0xDD,0x50,0xC7,0x06,0x18,0x7A,0xE5,0x50,0xC7,0x06,0x1A,0x7A,0xED,0x50,0xC7,0x06, -0x1C,0x7A,0xF0,0x50,0xC7,0x06,0x1E,0x7A,0xF2,0x50,0xC7,0x06,0x20,0x7A,0xF4,0x50, -0xC7,0x06,0x22,0x7A,0xF8,0x50,0xC6,0x06,0x24,0x7A,0x01,0xC6,0x06,0x25,0x7A,0x01, -0xC6,0x06,0x26,0x7A,0x03,0xC3,0xC7,0x06,0x0C,0x7A,0xFC,0x50,0xC7,0x06,0x0E,0x7A, -0x2F,0x51,0xC7,0x06,0x10,0x7A,0x29,0x51,0xC7,0x06,0x12,0x7A,0x2C,0x51,0xC7,0x06, -0x14,0x7A,0x31,0x51,0xC7,0x06,0x16,0x7A,0x33,0x51,0xC7,0x06,0x18,0x7A,0x37,0x51, -0xC7,0x06,0x1A,0x7A,0x38,0x51,0xC7,0x06,0x1C,0x7A,0x3B,0x51,0xC7,0x06,0x1E,0x7A, -0x3C,0x51,0xC7,0x06,0x20,0x7A,0x3D,0x51,0xC7,0x06,0x22,0x7A,0x40,0x51,0xC6,0x06, -0x24,0x7A,0x20,0xC6,0x06,0x25,0x7A,0x20,0xC6,0x06,0x26,0x7A,0x02,0xC3,0xA1,0xF8, -0x79,0x48,0x74,0x14,0xBE,0xD7,0x79,0xE8,0x3C,0x00,0x8B,0xF8,0xAC,0x3C,0x3A,0x75, -0x07,0x8E,0xC7,0xE8,0x30,0x00,0x8B,0xF8,0xC3,0x90,0x8B,0xC7,0x2B,0x06,0xFE,0x79, -0x8A,0xF0,0x24,0x0F,0x8A,0xD0,0x02,0xD0,0x02,0xD0,0x80,0xC2,0x0B,0xC0,0xEE,0x04, -0x80,0xC6,0x03,0x04,0x3D,0xC3,0x8C,0xC0,0xE8,0x93,0x00,0xB0,0x3A,0xE8,0xE4,0x00, -0x8B,0xC7,0xE8,0x89,0x00,0xC3,0x51,0x33,0xC9,0x90,0xAC,0x3C,0x20,0x74,0xFB,0x90, -0x0A,0xC0,0x74,0x26,0x2C,0x30,0x72,0x22,0x3C,0x09,0x76,0x14,0x3C,0x11,0x72,0x1A, -0x2C,0x07,0x3C,0x0F,0x76,0x0A,0x3C,0x2A,0x72,0x10,0x2C,0x20,0x3C,0x0F,0x77,0x0A, -0x98,0xC1,0xE1,0x04,0x03,0xC8,0xAC,0xEB,0xD7,0x90,0x4E,0x8B,0xC1,0x59,0xC3,0x90, -0x06,0x8C,0xC8,0x8E,0xC0,0xE8,0x02,0x00,0x07,0xC3,0x26,0x8A,0x04,0x46,0x0A,0xC0, -0x74,0x06,0xE8,0x8F,0x00,0xEB,0xF3,0x90,0xC3,0x90,0x0B,0xC0,0x74,0x7A,0x51,0x33, -0xD2,0xB9,0xE8,0x03,0xF7,0xF1,0x8B,0xCA,0xE8,0x03,0x00,0x8B,0xC1,0x59,0xBA,0x64, -0x00,0xF6,0xF2,0xE8,0x0C,0x00,0x8A,0xC4,0x98,0xB2,0x0A,0xF6,0xF2,0xE8,0x02,0x00, -0x8A,0xC4,0x50,0x0A,0xF0,0x74,0x05,0x04,0x30,0xE8,0x58,0x00,0x58,0xC3,0x86,0xC4, -0xE8,0x07,0x00,0x86,0xC4,0xE8,0x02,0x00,0xC3,0x90,0xC1,0xC8,0x04,0xE8,0x08,0x00, -0xC1,0xC0,0x04,0xE8,0x02,0x00,0xC3,0x90,0x53,0x50,0x24,0x0F,0xBB,0xAC,0x62,0x2E, -0xD7,0xE8,0x30,0x00,0x58,0x5B,0xC3,0x90,0x86,0xC4,0xE8,0x07,0x00,0x86,0xC4,0xE8, -0x02,0x00,0xC3,0x90,0x50,0xB9,0x08,0x00,0x8A,0xE0,0x32,0xC0,0xD1,0xC0,0x04,0x30, -0xE8,0x11,0x00,0xE2,0xF5,0x58,0xC3,0x90,0xB0,0x30,0xE8,0x07,0x00,0xC3,0xB0,0x20, -0xE8,0x01,0x00,0xC3,0x56,0x8B,0x36,0xD0,0x79,0x88,0x84,0xD0,0x77,0x46,0x81,0xE6, -0xFF,0x01,0xFF,0x06,0xD4,0x79,0x89,0x36,0xD0,0x79,0x81,0x3E,0xD4,0x79,0xFE,0x01, -0x75,0x08,0x56,0xE8,0x14,0x00,0x5E,0xEB,0xF1,0x90,0x5E,0xC3,0xBA,0x02,0x02,0xEC, -0x24,0x01,0x74,0x04,0xBA,0x06,0x02,0xEC,0xC3,0x90,0x80,0x3E,0xF6,0x79,0x00,0x74, -0x09,0x60,0xB8,0x01,0x00,0xE8,0x2C,0xEA,0x61,0x90,0xBA,0x02,0x02,0xEC,0xA8,0x04, -0x74,0x28,0x8B,0x36,0xD2,0x79,0x83,0x3E,0xD4,0x79,0x00,0x74,0x1D,0x8A,0x84,0xD0, -0x77,0x46,0x81,0xE6,0xFF,0x01,0x89,0x36,0xD2,0x79,0xFF,0x0E,0xD4,0x79,0xBA,0x06, -0x02,0xEE,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x75,0xDC,0xA1,0xD4,0x79,0xC3,0x52,0xBA, -0x06,0x02,0xEE,0x5A,0xC3,0x90,0x52,0x50,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x74,0x08, -0x58,0x5A,0xE8,0xE9,0xFF,0xF9,0xC3,0x90,0x58,0x5A,0xF8,0xC3,0x52,0x50,0xBA,0x02, -0x02,0xEC,0xA8,0x04,0x74,0xFB,0x58,0x5A,0xE8,0xD3,0xFF,0xC3,0x30,0x31,0x32,0x33, -0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,0x53,0x50,0x8A,0xE0, -0x80,0xE4,0x0F,0xBB,0xAC,0x62,0xC0,0xE8,0x04,0x2E,0xD7,0xE8,0xCE,0xFF,0x8A,0xC4, -0x2E,0xD7,0xE8,0xC7,0xFF,0x58,0x5B,0xC3,0x86,0xE0,0xE8,0xDF,0xFF,0x86,0xE0,0xE8, -0xDA,0xFF,0xC3,0x90,0xBE,0x94,0x4D,0x50,0x2E,0xAC,0x3C,0x00,0x74,0x05,0xE8,0xAB, -0xFF,0xEB,0xF5,0x58,0xC3,0x90,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0xBF, -0x04,0x00,0xC7,0x46,0xFC,0x00,0x00,0xC7,0x46,0xFA,0x00,0x00,0xC7,0x46,0xF8,0x00, -0x00,0x83,0x7E,0x06,0x00,0x75,0x0E,0x56,0xE8,0xB6,0x0E,0x59,0x0B,0xC0,0x75,0x05, -0x8B,0xC7,0xE9,0x5B,0x01,0x8B,0x46,0xFC,0x89,0x46,0xFE,0x0B,0xFF,0x75,0x05,0xB8, -0x01,0x00,0xEB,0x02,0x33,0xC0,0x50,0x56,0xE8,0xA4,0x0D,0x59,0x59,0xB4,0x00,0x89, -0x46,0xFC,0x8B,0x5E,0xFC,0x83,0xFB,0x08,0x76,0x03,0xE9,0x2B,0x01,0xD1,0xE3,0x2E, -0xFF,0xA7,0x94,0x64,0xB8,0x03,0x00,0xE9,0x26,0x01,0x83,0x7E,0xFA,0x00,0x74,0x14, -0xC7,0x46,0xFA,0x00,0x00,0x8A,0x44,0x58,0x98,0x50,0x8A,0x44,0x59,0x98,0x50,0xE8, -0xC2,0x0F,0x59,0x59,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56, -0xE8,0x9B,0x08,0x59,0x83,0x7E,0x06,0x00,0x75,0x05,0x8B,0xC7,0xE9,0xF1,0x00,0x83, -0xFF,0x04,0x75,0x03,0xE9,0xE6,0x00,0x8B,0xC7,0xE9,0xE4,0x00,0x83,0x7E,0xFE,0x00, -0x75,0x03,0xBF,0x02,0x00,0xE9,0xD5,0x00,0x83,0x7E,0xFE,0x00,0x75,0x03,0xBF,0x01, -0x00,0xE9,0xC9,0x00,0x8B,0x5E,0xFE,0x83,0xFB,0x07,0x76,0x03,0xE9,0x86,0x00,0xD1, -0xE3,0x2E,0xFF,0xA7,0x84,0x64,0x33,0xFF,0xE9,0x7F,0x00,0xBF,0x04,0x00,0x80,0x7C, -0x58,0x0F,0x74,0x22,0x83,0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x44,0x58,0x6A,0x08,0x56, -0xE8,0x7E,0x0C,0x59,0x59,0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x72,0x0C,0x59, -0x59,0xC7,0x46,0xFA,0x01,0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00, -0x00,0x56,0xE8,0x19,0x08,0x59,0xEB,0x42,0xBF,0x04,0x00,0x80,0x7C,0x58,0x00,0x74, -0x22,0x83,0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x4C,0x58,0x6A,0x08,0x56,0xE8,0x41,0x0C, -0x59,0x59,0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x35,0x0C,0x59,0x59,0xC7,0x46, -0xFA,0x01,0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,0xE8, -0xDC,0x07,0x59,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xEB,0x31,0xBF,0x04,0x00,0xEB, -0x2C,0xC7,0x46,0xF8,0x01,0x00,0x6A,0x08,0x56,0xE8,0x05,0x0C,0x59,0x59,0x80,0x7C, -0x58,0x09,0x7D,0x04,0xB0,0x0F,0xEB,0x02,0xB0,0x00,0x04,0x80,0x50,0x56,0xE8,0xF0, -0x0B,0x59,0x59,0xBF,0x04,0x00,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xE9,0xA5,0xFE, -0x5F,0x5E,0xC9,0xC3,0xC6,0x63,0x45,0x64,0x45,0x64,0x45,0x64,0x45,0x64,0xCB,0x63, -0x08,0x64,0x33,0x64,0x5A,0x63,0x9C,0x63,0xA8,0x63,0x78,0x64,0xB4,0x63,0x4C,0x64, -0x4C,0x64,0x51,0x64,0x54,0x63,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x8B, -0x7E,0x08,0x6A,0x01,0x56,0xE8,0xA9,0x0B,0x59,0x59,0x8A,0x46,0x06,0xC0,0xE0,0x06, -0x04,0x80,0x50,0x56,0xE8,0x9A,0x0B,0x59,0x59,0xC7,0x46,0xFE,0x00,0x00,0x89,0x7E, -0xF8,0xEB,0x03,0xFF,0x46,0xFE,0x8B,0x5E,0xF8,0xFF,0x46,0xF8,0x80,0x3F,0x00,0x75, -0xF2,0x83,0x7E,0xFE,0x10,0x7D,0x25,0xB8,0x10,0x00,0x2B,0x46,0xFE,0xD1,0xF8,0x89, -0x46,0xFC,0xC7,0x46,0xFA,0x00,0x00,0xEB,0x0B,0x6A,0x20,0x56,0xE8,0x62,0x0B,0x59, -0x59,0xFF,0x46,0xFA,0x8B,0x46,0xFA,0x3B,0x46,0xFC,0x7C,0xED,0xEB,0x0C,0x8B,0xDF, -0x47,0x8A,0x07,0x50,0x56,0xE8,0x49,0x0B,0x59,0x59,0x80,0x3D,0x00,0x75,0xEF,0x6A, -0x02,0x56,0xE8,0x3C,0x0B,0x59,0x59,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x04,0x00, -0x00,0x56,0x57,0x8B,0x7E,0x04,0xC7,0x46,0xFE,0x00,0x00,0xBE,0x14,0x00,0xE9,0x09, -0x01,0x8B,0x5E,0xFE,0x83,0xC3,0x04,0x2B,0xDF,0x8A,0x87,0xAC,0x0B,0x88,0x44,0x5A, -0xC6,0x44,0x58,0x08,0x8A,0x46,0xFE,0x88,0x44,0x59,0xC7,0x44,0x06,0x00,0x00,0xC6, -0x44,0x19,0x00,0xC6,0x44,0x1A,0x00,0xC6,0x44,0x1B,0x00,0xC6,0x44,0x1D,0x0D,0xC6, -0x44,0x1E,0x03,0xC6,0x44,0x1F,0x00,0xC6,0x44,0x20,0x00,0xC6,0x44,0x21,0x00,0xC6, -0x44,0x5B,0x00,0xC6,0x44,0x5D,0x00,0xC6,0x44,0x5E,0x00,0xC6,0x44,0x5F,0x00,0xC6, -0x44,0x60,0x00,0xC7,0x46,0xFC,0x00,0x00,0xEB,0x0D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7, -0x40,0x30,0x00,0x00,0xFF,0x46,0xFC,0x83,0x7E,0xFC,0x10,0x7C,0xED,0xC7,0x46,0xFC, -0x00,0x00,0xEB,0x0A,0x8B,0x5E,0xFC,0xC6,0x40,0x50,0x00,0xFF,0x46,0xFC,0x83,0x7E, -0xFC,0x04,0x7C,0xF0,0xC7,0x44,0x54,0x00,0x00,0xC7,0x44,0x56,0x00,0x00,0x8A,0x44, -0x5A,0x98,0xBA,0xF8,0x00,0x23,0xD0,0xB8,0x05,0x00,0x0B,0xC2,0x89,0x46,0xFC,0x9C, -0xFA,0x8A,0x46,0xFC,0xBA,0xFE,0x00,0xEE,0xBA,0x00,0x00,0xEC,0x9D,0x24,0x08,0x88, -0x46,0xFC,0x83,0x7E,0xFC,0x00,0x75,0x02,0xEB,0x4A,0xFF,0x76,0xFE,0xE8,0x7A,0x0C, -0x59,0x68,0x35,0x02,0x56,0xE8,0x32,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x34,0x68,0x38, -0x02,0x56,0xE8,0x25,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x27,0x68,0x42,0x02,0x56,0xE8, -0x18,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x1A,0x68,0x4C,0x02,0x56,0xE8,0x0B,0x0A,0x59, -0x59,0x0B,0xC0,0x75,0x0D,0x68,0x56,0x02,0x56,0xE8,0xFE,0x09,0x59,0x59,0x0B,0xC0, -0x74,0x02,0xEB,0x00,0xFF,0x46,0xFE,0x83,0xC6,0x62,0x39,0x7E,0xFE,0x7D,0x03,0xE9, -0xEF,0xFE,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x46, -0x04,0xBA,0x62,0x00,0xF7,0xEA,0x05,0x14,0x00,0x8B,0xF0,0x83,0x7E,0x06,0x00,0x74, -0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x08,0x00,0x89,0x44,0x04,0x8A,0x46,0x08,0x88, -0x44,0x5C,0x56,0xE8,0x59,0x04,0x59,0x8B,0xF8,0x8B,0xC7,0x89,0x44,0x56,0x89,0x44, -0x54,0x8A,0x44,0x5D,0x88,0x44,0x2F,0x0B,0xFF,0x75,0x1D,0x68,0xC2,0x0F,0x6A,0x01, -0x56,0xE8,0x02,0xFE,0x83,0xC4,0x06,0xEB,0x00,0x6A,0x01,0x56,0xE8,0x47,0xFC,0x59, -0x59,0x0B,0xC0,0x75,0xF4,0xBF,0x01,0x00,0x89,0x7E,0xFA,0xB9,0x05,0x00,0xBB,0xCB, -0x6A,0x2E,0x8B,0x07,0x3B,0x46,0xFA,0x74,0x07,0x43,0x43,0xE2,0xF4,0xE9,0xA4,0x03, -0x2E,0xFF,0x67,0x0A,0xC7,0x44,0x06,0x02,0x00,0xC7,0x44,0x08,0xF4,0x08,0x8B,0x5E, -0x04,0xD1,0xE3,0x8B,0x87,0xFC,0x08,0x89,0x44,0x0A,0x33,0xC0,0x8B,0xF8,0x89,0x44, -0x54,0xE9,0x80,0x03,0x56,0xE8,0xBB,0x05,0x59,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88, -0x44,0x60,0xE9,0x6F,0x03,0x83,0x7C,0x04,0x08,0x75,0x30,0x80,0x7C,0x5C,0x01,0x75, -0x15,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xE4,0x08,0x56,0xE8, -0xF7,0x08,0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF, -0xB7,0xC4,0x08,0x56,0xE8,0xE2,0x08,0x59,0x59,0xEB,0x2E,0x80,0x7C,0x5C,0x01,0x75, -0x15,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xD4,0x08,0x56,0xE8, -0xC7,0x08,0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF, -0xB7,0xB4,0x08,0x56,0xE8,0xB2,0x08,0x59,0x59,0x6A,0x01,0x56,0xE8,0x87,0xFB,0x59, -0x59,0x8B,0xD8,0x83,0xFB,0x03,0x77,0x2A,0xD1,0xE3,0x2E,0xFF,0xA7,0xC3,0x6A,0xBF, -0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x5E,0xEB,0x18,0x8A,0x44,0x5D,0x04,0xFF,0x24, -0x07,0x88,0x44,0x5D,0xEB,0x0C,0x8A,0x44,0x5D,0xFE,0xC0,0x24,0x07,0x88,0x44,0x5D, -0xEB,0x00,0xE9,0xCF,0x02,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7, -0xFD,0x02,0x56,0xE8,0x63,0x08,0x59,0x59,0x68,0x1D,0x03,0x56,0xE8,0x5A,0x08,0x59, -0x59,0x6A,0x01,0x56,0xE8,0x2F,0xFB,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x77,0x36, -0xD1,0xE3,0x2E,0xFF,0xA7,0xBB,0x6A,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x5F, -0xEB,0x24,0x8A,0x44,0x5D,0x04,0xFF,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22,0xC2,0x88, -0x44,0x5D,0xEB,0x12,0x8A,0x44,0x5D,0xFE,0xC0,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22, -0xC2,0x88,0x44,0x5D,0xEB,0x00,0xE9,0x6B,0x02,0x8B,0x5C,0x06,0x83,0xC3,0xFE,0xD1, -0xE3,0x8B,0x40,0x08,0x89,0x04,0x8B,0x1C,0xFF,0x77,0x06,0x6A,0x00,0x56,0xE8,0x85, -0xFC,0x83,0xC4,0x06,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x40,0x08,0x89,0x44,0x02, -0x8B,0x5C,0x02,0xFF,0x77,0x06,0x6A,0x01,0x56,0xE8,0x6A,0xFC,0x83,0xC4,0x06,0x6A, -0x01,0x56,0xE8,0xB1,0xFA,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x76,0x03,0xE9,0x1F, -0x02,0xD1,0xE3,0x2E,0xFF,0xA7,0xB3,0x6A,0x8B,0x5C,0x02,0x8B,0x47,0x04,0x89,0x44, -0x02,0x8B,0x5C,0x02,0x80,0x3F,0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4, -0x00,0x3B,0x44,0x04,0x7D,0xE2,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B, -0x44,0x02,0x89,0x47,0x08,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40, -0x08,0xE9,0xDE,0x01,0x8B,0x5C,0x02,0x8B,0x47,0x02,0x89,0x44,0x02,0x8B,0x5C,0x02, -0x80,0x3F,0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4,0x00,0x3B,0x44,0x04, -0x7D,0xE2,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B,0x44,0x02,0x89,0x47, -0x08,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40,0x08,0xE9,0xA2,0x01, -0xBF,0x01,0x00,0xE9,0x9C,0x01,0x8B,0x5C,0x02,0x8A,0x07,0xB4,0x00,0x89,0x46,0xF8, -0xB9,0x0C,0x00,0xBB,0x83,0x6A,0x2E,0x8B,0x07,0x3B,0x46,0xF8,0x74,0x07,0x43,0x43, -0xE2,0xF4,0xE9,0x77,0x01,0x2E,0xFF,0x67,0x18,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x5C, -0x02,0x03,0xD8,0x8B,0x47,0x08,0x8B,0x5C,0x06,0xFF,0x44,0x06,0xD1,0xE3,0x89,0x40, -0x08,0x8B,0x1C,0x80,0x7F,0x01,0x00,0x74,0x12,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B, -0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xE9,0x40,0x01,0xFF,0x4C, -0x06,0xE9,0x3A,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6, -0x00,0x8B,0xDA,0x88,0x40,0x18,0xE9,0x25,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B, -0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xFF,0x4C,0x06,0xE9,0x0D, -0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA, -0x30,0x40,0x18,0xE9,0xF8,0x00,0xB8,0xF0,0x10,0x8B,0xF8,0x89,0x44,0x54,0x8A,0x44, -0x5F,0x88,0x44,0x5D,0xE9,0xE7,0x00,0x8A,0x44,0x1C,0x98,0x3D,0x02,0x00,0x74,0x07, -0x3D,0x03,0x00,0x74,0x02,0xEB,0x07,0xC7,0x46,0xFE,0x00,0x00,0xEB,0x2B,0x8A,0x44, -0x1C,0x98,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x69,0x02,0x56,0xE8,0x6B,0x06,0x59,0x59, -0x6A,0x01,0x56,0xE8,0x40,0xF9,0x59,0x59,0x89,0x46,0xFE,0x83,0x7E,0xFE,0x00,0x74, -0x06,0x83,0x7E,0xFE,0x03,0x75,0xE9,0xEB,0x00,0x83,0x7E,0xFE,0x03,0x74,0x62,0x8A, -0x44,0x1C,0x98,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x6D,0x02,0x56,0xE8,0x3A,0x06,0x59, -0x59,0x56,0xE8,0x6B,0x97,0x59,0x89,0x46,0xFC,0x8B,0x5E,0xFC,0x83,0xEB,0xFE,0x83, -0xFB,0x03,0x77,0x33,0xD1,0xE3,0x2E,0xFF,0xA7,0x7B,0x6A,0x68,0xAC,0x02,0x56,0xE8, -0x17,0x06,0x59,0x59,0xEB,0x23,0x68,0x8F,0x02,0x56,0xE8,0x0C,0x06,0x59,0x59,0xEB, -0x18,0x68,0x75,0x02,0x56,0xE8,0x01,0x06,0x59,0x59,0xEB,0x0D,0x68,0xC6,0x02,0x56, -0xE8,0xF6,0x05,0x59,0x59,0xEB,0x02,0xEB,0x00,0x6A,0x01,0x56,0xE8,0xC7,0xF8,0x59, -0x59,0xBF,0x01,0x00,0xEB,0x38,0x68,0xDD,0x02,0x56,0xE8,0xDC,0x05,0x59,0x59,0x6A, -0x01,0x56,0xE8,0xB1,0xF8,0x59,0x59,0xBF,0x01,0x00,0xEB,0x22,0xB8,0xD0,0x30,0x8B, -0xF8,0x89,0x44,0x54,0x8A,0x44,0x60,0x88,0x44,0x5D,0xEB,0x12,0xB8,0xE0,0x20,0x8B, -0xF8,0x89,0x44,0x54,0x8A,0x44,0x5E,0x88,0x44,0x5D,0xEB,0x02,0xEB,0x00,0xEB,0x02, -0xEB,0x00,0xEB,0x00,0xE9,0x41,0xFC,0x5F,0x5E,0xC9,0xC3,0xFB,0x69,0x06,0x6A,0x11, -0x6A,0x1C,0x6A,0x00,0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x41,0x00,0x42,0x00,0x43, -0x00,0x44,0x00,0x80,0x00,0x81,0x00,0x82,0x00,0xFF,0x00,0xF9,0x68,0x36,0x6A,0x5C, -0x6A,0x87,0x69,0x34,0x69,0x76,0x69,0x4C,0x6A,0x49,0x69,0x34,0x69,0x61,0x69,0x49, -0x69,0x2E,0x69,0xD6,0x68,0x58,0x68,0x94,0x68,0xD0,0x68,0xD7,0x67,0xE2,0x67,0xF4, -0x67,0xD7,0x67,0x7F,0x67,0x8A,0x67,0x96,0x67,0x7F,0x67,0x00,0x00,0x01,0x00,0xF0, -0x10,0xE0,0x20,0xD0,0x30,0x09,0x68,0xD4,0x66,0xA5,0x67,0x05,0x67,0xF4,0x66,0xC8, -0x04,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x8A,0x44,0x59,0x98,0x89,0x46,0xFC,0x6A, -0x09,0x8B,0x46,0xFC,0x05,0x84,0x01,0x50,0xE8,0x93,0x08,0x59,0x59,0x8B,0xF8,0x8B, -0xC7,0x25,0x00,0xF0,0x3D,0x00,0x10,0x75,0x55,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xF0, -0x00,0x75,0x4B,0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44, -0x04,0x3B,0x46,0xFE,0x7D,0x05,0x33,0xC0,0xE9,0xEF,0x00,0x8B,0xC7,0x25,0x0F,0x00, -0xBA,0x0F,0x00,0x2B,0xD0,0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xE9,0xDB,0x00,0xC7, -0x44,0x02,0x04,0x09,0x8A,0x46,0xFE,0x88,0x44,0x5F,0x88,0x44,0x5D,0x8B,0x5E,0xFC, -0xD1,0xE3,0xC7,0x87,0xFC,0x08,0x04,0x09,0xB8,0xF0,0x10,0xE9,0xBC,0x00,0x8B,0xC7, -0x25,0x00,0xF0,0x3D,0x00,0x20,0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xE0,0x00, -0x75,0x48,0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x83,0x7E,0xFE, -0x08,0x7E,0x05,0x33,0xC0,0xE9,0x92,0x00,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00, -0x2B,0xD0,0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xEB,0x7F,0x90,0xC7,0x44,0x02,0x0C, -0x09,0x8A,0x46,0xFE,0x88,0x44,0x5E,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7, -0x87,0xFC,0x08,0x0C,0x09,0xB8,0xE0,0x20,0xEB,0x60,0x8B,0xC7,0x25,0x00,0xF0,0x3D, -0x00,0x30,0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xD0,0x00,0x75,0x48,0x8B,0xC7, -0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44,0x04,0x3B,0x46,0xFE,0x7D, -0x04,0x33,0xC0,0xEB,0x35,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00,0x2B,0xD0,0x3B, -0x56,0xFE,0x74,0x04,0x33,0xC0,0xEB,0x22,0xC7,0x44,0x02,0x14,0x09,0x8A,0x46,0xFE, -0x88,0x44,0x60,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,0x87,0xFC,0x08,0x14, -0x09,0xB8,0xD0,0x30,0xEB,0x04,0x33,0xC0,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x06, -0x00,0x00,0x56,0x8B,0x76,0x04,0x6A,0x08,0x56,0xE8,0x35,0x04,0x59,0x59,0x8A,0x44, -0x58,0x04,0x80,0x50,0x56,0xE8,0x29,0x04,0x59,0x59,0x8B,0x44,0x54,0x3B,0x44,0x56, -0x75,0x0A,0x8A,0x44,0x5D,0x3A,0x44,0x2F,0x75,0x02,0xEB,0x64,0x8B,0x44,0x54,0x89, -0x44,0x56,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x88,0x44,0x2F,0x8A,0x44,0x5D,0xB4,0x00, -0xC1,0xE0,0x08,0x8B,0x54,0x54,0x0B,0xD0,0x8A,0x44,0x5D,0xB4,0x00,0xBB,0x0F,0x00, -0x2B,0xD8,0x0B,0xD3,0x89,0x56,0xFE,0x6A,0x10,0x8A,0x44,0x59,0x98,0x05,0x04,0x00, -0x99,0x05,0x40,0x01,0x83,0xD2,0x00,0x52,0x50,0xE8,0x54,0x08,0x83,0xC4,0x06,0x89, -0x56,0xFC,0x89,0x46,0xFA,0x8B,0x46,0xFE,0x09,0x46,0xFA,0x83,0x4E,0xFC,0x00,0x6A, -0x19,0xFF,0x76,0xFC,0xFF,0x76,0xFA,0xE8,0x73,0x07,0x83,0xC4,0x06,0xE8,0xFE,0x07, -0x5E,0xC9,0xC3,0xC8,0x1C,0x00,0x00,0x56,0x57,0x8B,0x5E,0x04,0x8A,0x47,0x59,0x98, -0x8B,0xF0,0x8B,0x5E,0x04,0x8A,0x47,0x5D,0xB4,0x00,0x89,0x46,0xE6,0x83,0x7E,0xE6, -0x00,0x7D,0x0A,0x8B,0x5E,0x04,0x8B,0x47,0x04,0x48,0x89,0x46,0xE6,0x8B,0x5E,0x04, -0x8B,0x47,0x04,0x3B,0x46,0xE6,0x7F,0x05,0xC7,0x46,0xE6,0x00,0x00,0x8B,0x5E,0x04, -0x8A,0x46,0xE6,0x88,0x47,0x5D,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47, -0x02,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x03,0x30,0x8B,0xDE, -0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x47,0x02,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F, -0x61,0x02,0xC6,0x47,0x03,0x30,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00, -0x74,0x18,0x8B,0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B, -0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA, -0x33,0xD2,0xF7,0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA, -0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F, -0x59,0x02,0x88,0x57,0x02,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74, -0x18,0x8B,0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE, -0xD1,0xE3,0x8B,0x9F,0x61,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA,0x33, -0xD2,0xF7,0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA,0xBB, -0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61, -0x02,0x88,0x57,0x02,0x8B,0x5E,0xE6,0xD1,0xE3,0xFF,0xB7,0x12,0x02,0x6A,0x00,0xFF, -0x76,0x04,0xE8,0xD1,0xF6,0x83,0xC4,0x06,0x68,0xD3,0x0F,0x6A,0x01,0xFF,0x76,0x04, -0xE8,0xC3,0xF6,0x83,0xC4,0x06,0xFF,0x76,0xE6,0x56,0xE8,0x1F,0x93,0x59,0x59,0x89, -0x56,0xF2,0x89,0x46,0xF0,0xFF,0x76,0xE6,0x56,0xE8,0x32,0x93,0x59,0x59,0x89,0x56, -0xEE,0x89,0x46,0xEC,0x9C,0xFA,0xC4,0x5E,0xF0,0x26,0x8B,0x07,0x89,0x46,0xEA,0xC4, -0x5E,0xEC,0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE,0x9D, -0xC7,0x46,0xE4,0x01,0x00,0xE8,0x08,0xA1,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFC,0x8B, -0x46,0xFC,0x2B,0x46,0xFE,0x3D,0xE8,0x03,0x73,0x03,0xE9,0x80,0x01,0x9C,0xFA,0xBA, -0x50,0xFF,0xED,0x89,0x46,0xFC,0x8B,0x46,0xFC,0x2B,0x46,0xFE,0x89,0x46,0xF8,0xC4, -0x5E,0xF0,0x26,0x8B,0x07,0x2B,0x46,0xEA,0x89,0x46,0xF6,0xC4,0x5E,0xF0,0x26,0x8B, -0x07,0x89,0x46,0xEA,0xC4,0x5E,0xEC,0x26,0x8B,0x07,0x2B,0x46,0xE8,0x89,0x46,0xF4, -0xC4,0x5E,0xEC,0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE, -0x9D,0x81,0x7E,0xF8,0xE8,0x03,0x76,0x1C,0xFF,0x76,0xF8,0xFF,0x76,0xF6,0xE8,0x76, -0x01,0x59,0x59,0x89,0x46,0xF6,0xFF,0x76,0xF8,0xFF,0x76,0xF4,0xE8,0x68,0x01,0x59, -0x59,0x89,0x46,0xF4,0xBF,0x0E,0x00,0xEB,0x17,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59, -0x02,0xC6,0x01,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x01,0x20,0x47, -0x83,0xFF,0x11,0x76,0xE4,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x0D, -0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x47,0x0D,0x30,0x83,0x7E,0xF6, -0x09,0x77,0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF6,0x63,0x77,0x05,0xB8,0x0E, -0x00,0xEB,0x1B,0x81,0x7E,0xF6,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81, -0x7E,0xF6,0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8, -0xEB,0x25,0x8B,0x46,0xF6,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B, -0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF6, -0x33,0xD2,0xF7,0xF3,0x89,0x46,0xF6,0x83,0x7E,0xF6,0x00,0x75,0xD5,0x83,0x7E,0xF4, -0x09,0x77,0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF4,0x63,0x77,0x05,0xB8,0x0E, -0x00,0xEB,0x1B,0x81,0x7E,0xF4,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81, -0x7E,0xF4,0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8, -0xEB,0x25,0x8B,0x46,0xF4,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B, -0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF4, -0x33,0xD2,0xF7,0xF3,0x89,0x46,0xF4,0x83,0x7E,0xF4,0x00,0x75,0xD5,0x8B,0xDE,0xD1, -0xE3,0xFF,0xB7,0x59,0x02,0xFF,0x76,0x04,0xE8,0x6E,0x00,0x59,0x59,0x8B,0xDE,0xD1, -0xE3,0xFF,0xB7,0x61,0x02,0xFF,0x76,0x04,0xE8,0x5E,0x00,0x59,0x59,0x6A,0x00,0xFF, -0x76,0x04,0xE8,0x31,0xF3,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x04,0x77,0x1F,0xD1,0xE3, -0x2E,0xFF,0xA7,0xFD,0x6F,0xEB,0x22,0xC7,0x46,0xE4,0x00,0x00,0xFF,0x4E,0xE6,0xEB, -0x0C,0xC7,0x46,0xE4,0x00,0x00,0xFF,0x46,0xE6,0xEB,0x02,0xEB,0x00,0x83,0x7E,0xE4, -0x00,0x74,0x03,0xE9,0x2A,0xFE,0xE9,0xD4,0xFC,0x5F,0x5E,0xC9,0xC3,0xD5,0x6F,0xD7, -0x6F,0xE1,0x6F,0xD5,0x6F,0xEB,0x6F,0x55,0x8B,0xEC,0x8B,0x46,0x04,0xB9,0xE8,0x03, -0xF7,0xE1,0x8B,0x4E,0x06,0xF7,0xF1,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76,0x06, -0xEB,0x0E,0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x33,0x00,0x59,0x59, -0x80,0x3C,0x00,0x75,0xED,0xEB,0x00,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76, -0x06,0xEB,0x14,0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x45,0x00,0x59, -0x59,0x0B,0xC0,0x74,0x02,0xEB,0x07,0x80,0x3C,0x00,0x75,0xE7,0xEB,0x00,0x5E,0x5D, -0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE, -0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74, -0x06,0x9D,0xE8,0xAB,0x9E,0xEB,0xE9,0xBA,0x00,0x00,0x8A,0x46,0x06,0xEE,0x9D,0xEB, -0x00,0x5E,0xC9,0xC3,0xC8,0x04,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98, -0x89,0x46,0xFE,0xE8,0x00,0xA2,0x89,0x46,0xFC,0xE8,0xFA,0xA1,0x2B,0x46,0xFC,0x3D, -0xB8,0x0B,0x76,0x05,0xB8,0x01,0x00,0xEB,0x23,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE, -0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74,0x06,0x9D,0xE8,0x62,0x9E,0xEB,0xD9, -0xBA,0x00,0x00,0x8A,0x46,0x06,0xEE,0x9D,0x33,0xC0,0xEB,0x00,0x5E,0xC9,0xC3,0xC8, -0x04,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x83,0x7E,0x06,0x00,0x74,0x07,0x56,0xE8, -0x03,0x01,0x59,0xEB,0x05,0x56,0xE8,0xA2,0x00,0x59,0x88,0x46,0xFF,0x80,0x7E,0xFF, -0x08,0x77,0x06,0x8A,0x46,0xFF,0xE9,0x84,0x00,0x80,0x7E,0xFF,0x0F,0x76,0x03,0xEB, -0x79,0x90,0x8A,0x46,0xFF,0xB4,0x00,0x2D,0x0A,0x00,0x8B,0xD8,0x83,0xFB,0x04,0x77, -0x67,0xD1,0xE3,0x2E,0xFF,0xA7,0x91,0x71,0xB0,0x00,0xEB,0x61,0x56,0xE8,0x6B,0x00, -0x59,0xB4,0x00,0x25,0x0F,0x00,0x89,0x46,0xFC,0x56,0xE8,0x5E,0x00,0x59,0xB4,0x00, -0x8B,0xF8,0x56,0xE8,0x55,0x00,0x59,0xB4,0x00,0xC1,0xE0,0x08,0x8B,0xD7,0x03,0xD0, -0x8B,0xFA,0x8B,0x5E,0xFC,0xD1,0xE3,0x89,0x78,0x30,0xEB,0x2E,0x56,0xE8,0x3B,0x00, -0x59,0x88,0x44,0x5B,0xEB,0x24,0x56,0xE8,0x31,0x00,0x59,0x88,0x44,0x50,0x56,0xE8, -0x29,0x00,0x59,0x88,0x44,0x51,0x56,0xE8,0x21,0x00,0x59,0x88,0x44,0x52,0x56,0xE8, -0x19,0x00,0x59,0x88,0x44,0x53,0xEB,0x02,0xEB,0x00,0xE9,0x5B,0xFF,0x5F,0x5E,0xC9, -0xC3,0x28,0x71,0x88,0x71,0x2C,0x71,0x5C,0x71,0x66,0x71,0xC8,0x04,0x00,0x00,0x56, -0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,0x9C,0xFA,0x8A,0x46,0xFE,0xBA, -0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0x71,0x9D,0xEB, -0xE9,0xBA,0x00,0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9, -0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE, -0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0x32,0xE4,0x24, -0x01,0x9D,0x5E,0xC9,0xC3,0xC8,0x06,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A, -0x98,0x89,0x46,0xFE,0xE8,0x9F,0xA0,0x89,0x46,0xFA,0xE8,0x99,0xA0,0x2B,0x46,0xFA, -0x3D,0xB8,0x0B,0x76,0x04,0xB0,0x08,0xEB,0x24,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE, -0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0x02,0x9D,0xEB,0xDA, -0xBA,0x00,0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9,0xC3, -0x55,0x8B,0xEC,0x56,0x8B,0x56,0x04,0x8A,0x46,0x06,0xEE,0x33,0xF6,0xEB,0x03,0x50, -0x58,0x46,0x83,0xFE,0x14,0x7C,0xF8,0x5E,0x5D,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B, -0x56,0x04,0xEC,0x88,0x46,0xFF,0x33,0xF6,0xEB,0x03,0x50,0x58,0x46,0x83,0xFE,0x14, -0x7C,0xF8,0x8A,0x46,0xFF,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x57, -0x8B,0x76,0x04,0x83,0x3E,0xB0,0x0B,0x00,0x75,0x1F,0xBA,0x88,0x01,0xB0,0x00,0xEE, -0xBA,0x86,0x01,0xB0,0x00,0xEE,0x6A,0x09,0x6A,0x00,0x68,0x30,0x01,0xE8,0x7D,0x01, -0x83,0xC4,0x06,0xC7,0x06,0xB0,0x0B,0x01,0x00,0x6A,0x09,0x8B,0xC6,0x05,0x80,0x01, -0x50,0xE8,0xDA,0x00,0x59,0x59,0x8B,0xF8,0x8B,0xC7,0xC1,0xE8,0x0C,0x25,0x0F,0x00, -0x89,0x46,0xFE,0x8B,0xC7,0xC1,0xE8,0x08,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,0xF2, -0x0C,0x3B,0xC2,0x75,0x21,0x8B,0xC7,0xC1,0xE8,0x04,0x25,0x0F,0x00,0x8B,0x56,0xFE, -0x83,0xF2,0x06,0x3B,0xC2,0x75,0x0F,0x8B,0xC7,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83, -0xF2,0x09,0x3B,0xC2,0x74,0x0D,0x6A,0x07,0x56,0xE8,0x38,0x00,0x59,0x59,0xC7,0x46, -0xFE,0x07,0x00,0x8A,0x46,0xFE,0x04,0x80,0xA2,0x33,0x02,0x8B,0xC6,0xBA,0x62,0x00, -0xF7,0xEA,0x8A,0x56,0xFE,0x8B,0xD8,0x88,0x97,0x6C,0x00,0x68,0x32,0x02,0x8B,0xC6, -0xBA,0x62,0x00,0xF7,0xEA,0x05,0x14,0x00,0x50,0xE8,0x0E,0xFD,0x59,0x59,0xEB,0x00, -0x5F,0x5E,0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x06,0x83,0xE6,0x0F,0x8B, -0xC6,0xC1,0xE0,0x0C,0x8B,0xD6,0x83,0xF2,0x0C,0xC1,0xE2,0x08,0x0B,0xC2,0x8B,0xD6, -0x83,0xF2,0x06,0xC1,0xE2,0x04,0x0B,0xC2,0x8B,0xD6,0x83,0xF2,0x09,0x0B,0xC2,0x89, -0x46,0xFE,0x6A,0x19,0x6A,0x10,0x8B,0x46,0x04,0x99,0x05,0x40,0x01,0x83,0xD2,0x00, -0x52,0x50,0xE8,0x6B,0x01,0x83,0xC4,0x06,0x0B,0x46,0xFE,0x83,0xCA,0x00,0x52,0x50, -0xE8,0x9A,0x00,0x83,0xC4,0x06,0xE8,0x25,0x01,0xEB,0x00,0x5E,0xC9,0xC3,0x55,0x8B, -0xEC,0x56,0x57,0x33,0xFF,0x6A,0x01,0x68,0x86,0x01,0xE8,0xA3,0xFE,0x59,0x59,0xB1, -0x10,0x2A,0x4E,0x06,0xD3,0x66,0x04,0x33,0xF6,0xEB,0x2E,0x81,0x7E,0x04,0x00,0x80, -0x72,0x04,0xB0,0x01,0xEB,0x02,0xB0,0x00,0x50,0x68,0x88,0x01,0xE8,0x81,0xFE,0x59, -0x59,0x6A,0x03,0x68,0x86,0x01,0xE8,0x77,0xFE,0x59,0x59,0x6A,0x01,0x68,0x86,0x01, -0xE8,0x6D,0xFE,0x59,0x59,0xD1,0x66,0x04,0x46,0x3B,0x76,0x06,0x7C,0xCD,0x33,0xF6, -0xEB,0x24,0xD1,0xE7,0x6A,0x03,0x68,0x86,0x01,0xE8,0x54,0xFE,0x59,0x59,0x6A,0x01, -0x68,0x86,0x01,0xE8,0x4A,0xFE,0x59,0x59,0x68,0x88,0x01,0xE8,0x5C,0xFE,0x59,0x98, -0x25,0x01,0x00,0x0B,0xF8,0x46,0x83,0xFE,0x10,0x7C,0xD7,0x6A,0x00,0x68,0x86,0x01, -0xE8,0x2D,0xFE,0x59,0x59,0x8B,0xC7,0xEB,0x00,0x5F,0x5E,0x5D,0xC3,0x55,0x8B,0xEC, -0x56,0x57,0x8B,0x7E,0x08,0x6A,0x01,0x68,0x86,0x01,0xE8,0x13,0xFE,0x59,0x59,0xB8, -0x20,0x00,0x2B,0xC7,0x50,0xFF,0x76,0x06,0xFF,0x76,0x04,0xE8,0xA2,0x00,0x83,0xC4, -0x06,0x89,0x56,0x06,0x89,0x46,0x04,0x33,0xF6,0xEB,0x47,0x81,0x7E,0x06,0x00,0x80, -0x72,0x0C,0x75,0x06,0x83,0x7E,0x04,0x00,0x72,0x04,0xB0,0x01,0xEB,0x02,0xB0,0x00, -0x50,0x68,0x88,0x01,0xE8,0xD9,0xFD,0x59,0x59,0x6A,0x03,0x68,0x86,0x01,0xE8,0xCF, -0xFD,0x59,0x59,0x6A,0x01,0x68,0x86,0x01,0xE8,0xC5,0xFD,0x59,0x59,0x6A,0x01,0xFF, -0x76,0x06,0xFF,0x76,0x04,0xE8,0x58,0x00,0x83,0xC4,0x06,0x89,0x56,0x06,0x89,0x46, -0x04,0x46,0x3B,0xF7,0x7C,0xB5,0x6A,0x00,0x68,0x86,0x01,0xE8,0xA2,0xFD,0x59,0x59, -0x6A,0x00,0x68,0x86,0x01,0xE8,0x98,0xFD,0x59,0x59,0x5F,0x5E,0x5D,0xC3,0x55,0x8B, -0xEC,0x56,0x6A,0x01,0x68,0x86,0x01,0xE8,0x86,0xFD,0x59,0x59,0x33,0xF6,0xEB,0x00, -0x68,0x88,0x01,0xE8,0x94,0xFD,0x59,0xA8,0x01,0x75,0x08,0x8B,0xC6,0x46,0x3D,0x64, -0x00,0x7C,0xED,0x6A,0x00,0x68,0x86,0x01,0xE8,0x65,0xFD,0x59,0x59,0x5E,0x5D,0xC3, -0xC8,0x04,0x00,0x00,0x8B,0x46,0x04,0x8B,0x56,0x06,0x8B,0x4E,0x08,0xE3,0x06,0xD1, -0xE0,0xD1,0xD2,0xE2,0xFA,0x89,0x46,0xFC,0x89,0x56,0xFE,0x8B,0x56,0xFE,0x8B,0x46, -0xFC,0xEB,0x00,0xC9,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x60,0xFE,0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0x04,0xFF,0xB8,0x00,0x80,0xBA, +0x22,0xFF,0xEF,0x07,0x1F,0x61,0xCF,0x90,0x6A,0x00,0x1F,0xC6,0x06,0x93,0x12,0x1B, +0x9C,0x0E,0xE8,0x87,0xC7,0x90,0x60,0x1E,0x06,0x33,0xC0,0x8E,0xD8,0x8E,0xC0,0xBA, +0x06,0x01,0xEC,0xA8,0x04,0x74,0xE1,0xBA,0x08,0x01,0xEC,0xA2,0x8C,0x12,0xA8,0x40, +0x74,0x11,0xA1,0x88,0x12,0xA3,0x84,0x12,0xC6,0x06,0x8D,0x12,0x00,0xE8,0x12,0xFE, +0xA0,0x8C,0x12,0xA8,0x80,0x74,0x03,0xE8,0xB6,0xFE,0xB8,0x00,0x80,0xBA,0x22,0xFF, +0xEF,0x07,0x1F,0x61,0xCF,0x90,0xEE,0x86,0xE0,0xEE,0x86,0xE0,0xEC,0x86,0xE0,0xEC, +0x86,0xE0,0x80,0xE1,0xFE,0xF3,0x6C,0x90,0x80,0xE1,0xFE,0xF3,0x6E,0x90,0x05,0x00, +0x75,0x47,0xA8,0x4B,0x05,0x00,0x75,0x48,0xA8,0x4B,0x05,0x00,0xA3,0x48,0xA8,0x4B, +0x05,0x00,0x35,0x49,0xA8,0x4B,0x06,0x00,0x98,0x48,0x96,0x4B,0x06,0x00,0xBA,0x48, +0x96,0x4B,0x06,0x00,0xC3,0x48,0x96,0x4B,0x06,0x00,0xCB,0x48,0x96,0x4B,0x06,0x00, +0x20,0x49,0x96,0x4B,0x06,0x00,0x28,0x49,0x96,0x4B,0x06,0x00,0x4E,0x4A,0x9C,0x4B, +0x06,0x00,0x7B,0x4A,0x9C,0x4B,0x05,0x00,0x9E,0x4A,0xA2,0x4B,0x05,0x00,0xEC,0x4A, +0xA2,0x4B,0x00,0x00,0x1E,0x06,0x83,0x3E,0x44,0x12,0x00,0x74,0x09,0xA0,0x06,0x01, +0x24,0x30,0x3C,0x30,0x74,0x1A,0x8C,0xC8,0x8E,0xD8,0x8E,0xC0,0xBB,0xAE,0x4B,0x8B, +0x0F,0xE3,0x0D,0x8B,0x7F,0x02,0x8B,0x77,0x04,0xF3,0xA4,0x83,0xC3,0x06,0xEB,0xEF, +0x07,0x1F,0xC3,0x90,0x33,0xC0,0xA3,0x3E,0x01,0xB9,0x0C,0x01,0xBE,0x40,0x01,0x8B, +0xFE,0x81,0xC6,0xB4,0x0F,0x89,0x04,0x8B,0xC6,0x2B,0xF1,0x3B,0xC7,0x77,0xF6,0xA3, +0x3C,0x01,0xC3,0x90,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x8B,0x5E,0x00,0x3B, +0xEB,0x74,0x2B,0x8B,0x76,0x02,0x89,0x1C,0x89,0x77,0x02,0x36,0xA1,0x3C,0x01,0x89, +0x46,0x00,0x36,0x89,0x2E,0x3C,0x01,0x8B,0xEB,0xFF,0x4E,0x06,0x74,0x08,0x8B,0x6E, +0x00,0xFF,0x4E,0x06,0x75,0xF8,0x36,0x89,0x2E,0x3E,0x01,0x8B,0x66,0x04,0x61,0x07, +0x1F,0xC3,0x1E,0x06,0x60,0x36,0x8B,0x2E,0x3E,0x01,0x98,0x89,0x46,0x06,0x89,0x66, +0x04,0x3B,0x6E,0x00,0x74,0x10,0x8B,0x6E,0x00,0xFF,0x4E,0x06,0x75,0xF8,0x36,0x89, +0x2E,0x3E,0x01,0x8B,0x66,0x04,0x61,0x07,0x1F,0xC3,0xC3,0x90,0x1E,0x06,0x60,0x9C, +0xFA,0x33,0xED,0x8E,0xDD,0x8B,0x2E,0x3C,0x01,0x85,0xED,0x74,0x3D,0x8B,0x4E,0x00, +0x89,0x0E,0x3C,0x01,0x8B,0xCC,0x8D,0xA6,0x0A,0x01,0x56,0x1E,0x06,0x60,0x89,0x66, +0x04,0xC7,0x46,0x08,0x0F,0x1A,0xC7,0x46,0x06,0x01,0x00,0x8B,0x1E,0x3E,0x01,0x85, +0xDB,0x74,0x1D,0x8B,0xC5,0x87,0x07,0x89,0x46,0x00,0x89,0x5E,0x02,0x8B,0xD8,0x89, +0x6F,0x02,0x8B,0xE1,0x9D,0x61,0x07,0x1F,0xF8,0xC3,0x9D,0x61,0x07,0x1F,0xF9,0xC3, +0x89,0x2E,0x3E,0x01,0x89,0x6E,0x00,0x89,0x6E,0x02,0x87,0xE1,0x9D,0x8B,0xE1,0xEB, +0xE4,0x00,0x0D,0x0A,0x54,0x65,0x72,0x6D,0x69,0x6E,0x61,0x6C,0x73,0x20,0x73,0x75, +0x70,0x70,0x6F,0x72,0x74,0x65,0x64,0x3A,0x0D,0x0A,0x31,0x29,0x20,0x41,0x4E,0x53, +0x49,0x20,0x63,0x6F,0x6D,0x70,0x61,0x74,0x69,0x62,0x6C,0x65,0x0D,0x0A,0x32,0x29, +0x20,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x0D,0x0A,0x50,0x6C,0x65,0x61,0x73,0x65, +0x20,0x73,0x65,0x6C,0x65,0x63,0x74,0x3A,0x20,0x00,0x0D,0x0A,0x63,0x6F,0x64,0x65, +0x20,0x73,0x65,0x67,0x6D,0x65,0x6E,0x74,0x3D,0x00,0x0D,0x0A,0x4D,0x6F,0x6E,0x69, +0x74,0x6F,0x72,0x20,0x76,0x32,0x2E,0x35,0x0A,0x0D,0x0A,0x3E,0x00,0x0D,0x0A,0x50, +0x61,0x72,0x64,0x6F,0x6E,0x3F,0x00,0x0D,0x0A,0x4E,0x6F,0x20,0x61,0x64,0x64,0x72, +0x65,0x73,0x73,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x00,0x0D,0x0A, +0x3A,0x00,0x0D,0x0A,0x00,0x4C,0x6F,0x63,0x3D,0x00,0x0D,0x0A,0x46,0x41,0x54,0x41, +0x4C,0x20,0x45,0x52,0x52,0x4F,0x52,0x3D,0x00,0x0D,0x0A,0x4D,0x6F,0x6E,0x69,0x74, +0x6F,0x72,0x20,0x63,0x6F,0x6D,0x6D,0x61,0x6E,0x64,0x73,0x3A,0x2D,0x0D,0x0A,0x20, +0x20,0x20,0x44,0x2C,0x64,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78, +0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79, +0x0D,0x0A,0x20,0x20,0x20,0x4C,0x2C,0x6C,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D, +0x78,0x78,0x78,0x78,0x5D,0x20,0x2D,0x20,0x64,0x75,0x6D,0x70,0x20,0x73,0x69,0x6E, +0x67,0x6C,0x65,0x20,0x6C,0x69,0x6E,0x65,0x0D,0x0A,0x20,0x20,0x20,0x45,0x2C,0x65, +0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x2D,0x20, +0x65,0x64,0x69,0x74,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,0x0D,0x0A,0x20,0x20,0x20, +0x46,0x2C,0x66,0x5B,0x5B,0x78,0x78,0x78,0x78,0x20,0x5D,0x78,0x78,0x78,0x78,0x5D, +0x20,0x2D,0x20,0x66,0x69,0x6C,0x6C,0x20,0x6D,0x65,0x6D,0x6F,0x72,0x79,0x20,0x70, +0x61,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x0D,0x0A,0x20,0x20,0x20,0x49,0x5B, +0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D, +0x20,0x77,0x6F,0x72,0x64,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72,0x6F,0x6D, +0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x69,0x5B,0x78,0x78,0x78,0x78, +0x5D,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x79,0x74, +0x65,0x20,0x69,0x6E,0x70,0x75,0x74,0x20,0x66,0x72,0x6F,0x6D,0x20,0x70,0x6F,0x72, +0x74,0x0D,0x0A,0x20,0x20,0x20,0x4F,0x78,0x78,0x78,0x78,0x20,0x78,0x78,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75,0x74,0x20, +0x77,0x6F,0x72,0x64,0x20,0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20, +0x20,0x6F,0x78,0x78,0x78,0x78,0x20,0x78,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x2D,0x20,0x6F,0x75,0x74,0x70,0x75,0x74,0x20,0x62,0x79,0x74,0x65,0x20, +0x74,0x6F,0x20,0x70,0x6F,0x72,0x74,0x0D,0x0A,0x20,0x20,0x20,0x47,0x5B,0x5B,0x78, +0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x20,0x20,0x2D,0x20,0x67, +0x6F,0x74,0x6F,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x0D,0x0A,0x20,0x20,0x20, +0x57,0x5B,0x5B,0x78,0x78,0x78,0x78,0x3A,0x5D,0x78,0x78,0x78,0x78,0x5D,0x20,0x20, +0x20,0x2D,0x20,0x77,0x61,0x74,0x63,0x68,0x20,0x61,0x20,0x77,0x6F,0x72,0x64,0x0D, +0x0A,0x20,0x20,0x20,0x43,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69,0x6E,0x74,0x65,0x72,0x72,0x75,0x70,0x74, +0x73,0x20,0x6F,0x66,0x66,0x0D,0x0A,0x20,0x20,0x20,0x53,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x69,0x6E,0x74, +0x65,0x72,0x72,0x75,0x70,0x74,0x73,0x20,0x6F,0x6E,0x0D,0x0A,0x20,0x20,0x20,0x73, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x2D,0x20,0x73,0x69,0x6E,0x67,0x6C,0x65,0x20,0x73,0x74,0x65,0x70,0x0D,0x0A,0x20, +0x20,0x20,0x42,0x78,0x78,0x78,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65,0x61,0x6B,0x70,0x6F,0x69,0x6E,0x74,0x20, +0x73,0x65,0x74,0x0D,0x0A,0x20,0x20,0x20,0x62,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x62,0x72,0x65,0x61,0x6B, +0x70,0x6F,0x69,0x6E,0x74,0x20,0x63,0x6C,0x65,0x61,0x72,0x0D,0x0A,0x20,0x20,0x20, +0x52,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x2D,0x20,0x72,0x65,0x73,0x74,0x61,0x72,0x74,0x20,0x62,0x72,0x65,0x61,0x6B, +0x70,0x6F,0x69,0x6E,0x74,0x0D,0x0A,0x20,0x20,0x20,0x72,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x72,0x65,0x67, +0x69,0x73,0x74,0x65,0x72,0x73,0x20,0x61,0x74,0x20,0x62,0x72,0x6B,0x70,0x74,0x0D, +0x0A,0x20,0x20,0x20,0x58,0x2C,0x78,0x20,0x6E,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x2D,0x20,0x65,0x78,0x61,0x6D,0x69,0x6E,0x65,0x20,0x63, +0x68,0x61,0x6E,0x6E,0x65,0x6C,0x20,0x6E,0x0D,0x0A,0x20,0x20,0x20,0x48,0x2C,0x3F, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2D,0x20, +0x74,0x68,0x69,0x73,0x20,0x6D,0x65,0x73,0x73,0x61,0x67,0x65,0x00,0x1B,0x5B,0x32, +0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x41,0x4E,0x53,0x49,0x20,0x54,0x65,0x72,0x6D, +0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x0A,0x00,0x1B,0x5B,0x4B,0x00,0x1B,0x5B,0x4A,0x00, +0x1B,0x5B,0x32,0x4A,0x1B,0x5B,0x31,0x3B,0x31,0x48,0x00,0x1B,0x5B,0x44,0x20,0x1B, +0x5B,0x44,0x00,0x1B,0x5B,0x31,0x3B,0x37,0x32,0x48,0x00,0x1B,0x5B,0x00,0x3B,0x00, +0x48,0x00,0x1B,0x5B,0x73,0x00,0x1B,0x5B,0x75,0x00,0x1B,0x7A,0x2B,0x0B,0x7F,0x1B, +0x7A,0x2E,0x0C,0x7F,0x1B,0x7A,0x2D,0x08,0x7F,0x1B,0x7A,0x2C,0x0A,0x7F,0x1B,0x7A, +0x22,0x08,0x7F,0x1A,0x57,0x79,0x73,0x65,0x20,0x33,0x30,0x20,0x54,0x65,0x72,0x6D, +0x69,0x6E,0x61,0x6C,0x0D,0x0A,0x00,0x1B,0x54,0x00,0x1B,0x59,0x00,0x1A,0x00,0x1E, +0x00,0x08,0x20,0x08,0x00,0x00,0x1B,0x3D,0x00,0x00,0x00,0x1B,0x46,0x00,0x0D,0x00, +0x3F,0x44,0x64,0x45,0x65,0x46,0x66,0x47,0x67,0x48,0x68,0x49,0x69,0x4F,0x6F,0x43, +0x63,0x53,0x73,0x42,0x62,0x52,0x72,0x57,0x77,0x58,0x78,0x4C,0x6C,0x3C,0x60,0xD4, +0x57,0xD4,0x57,0x50,0x58,0x50,0x58,0xD6,0x59,0xD6,0x59,0xB4,0x59,0xB4,0x59,0x3C, +0x60,0x3C,0x60,0x6C,0x57,0x48,0x57,0x26,0x57,0x06,0x57,0x90,0x57,0x90,0x57,0x98, +0x57,0x48,0x5F,0x0C,0x5F,0x58,0x5F,0x33,0x5F,0x40,0x5F,0xA0,0x57,0xA0,0x57,0xFE, +0x59,0xFE,0x59,0xDC,0x57,0xDC,0x57,0x88,0x61,0x98,0x61,0xC0,0x61,0xCC,0x61,0xD8, +0x61,0xF6,0x61,0x02,0x62,0x22,0x62,0xF8,0x56,0x4A,0x62,0x58,0x62,0x60,0x59,0x20, +0x20,0x66,0x6C,0x61,0x67,0x73,0x3D,0x00,0x20,0x20,0x61,0x78,0x3D,0x00,0x20,0x20, +0x62,0x78,0x3D,0x00,0x20,0x20,0x63,0x78,0x3D,0x00,0x20,0x20,0x64,0x78,0x3D,0x00, +0x20,0x20,0x63,0x73,0x3D,0x00,0x20,0x20,0x64,0x73,0x3D,0x00,0x20,0x20,0x65,0x73, +0x3D,0x00,0x20,0x20,0x73,0x73,0x3D,0x00,0x20,0x20,0x64,0x69,0x3D,0x00,0x20,0x20, +0x73,0x69,0x3D,0x00,0x20,0x20,0x62,0x70,0x3D,0x00,0x20,0x20,0x73,0x70,0x3D,0x00, +0x20,0x20,0x69,0x70,0x3D,0x00,0x20,0x63,0x68,0x61,0x6E,0x65,0x6C,0x3D,0x00,0x20, +0x20,0x20,0x20,0x73,0x65,0x67,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74,0x72,0x3D, +0x00,0x20,0x74,0x69,0x5F,0x74,0x6F,0x73,0x3D,0x00,0x20,0x74,0x69,0x5F,0x6D,0x61, +0x78,0x3D,0x00,0x20,0x74,0x69,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74,0x69,0x5F, +0x73,0x69,0x7A,0x3D,0x00,0x20,0x74,0x69,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x74, +0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x74,0x69,0x5F,0x66,0x6C,0x67,0x3D,0x00, +0x20,0x74,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x70,0x63,0x6E, +0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73, +0x74,0x66,0x3D,0x00,0x20,0x72,0x69,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x72,0x69, +0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x73,0x69,0x7A,0x3D,0x00,0x20, +0x72,0x69,0x5F,0x74,0x6F,0x74,0x3D,0x00,0x20,0x72,0x69,0x5F,0x6D,0x69,0x6E,0x3D, +0x00,0x20,0x72,0x69,0x5F,0x66,0x6C,0x67,0x3D,0x00,0x20,0x72,0x69,0x5F,0x74,0x6F, +0x73,0x3D,0x00,0x20,0x72,0x69,0x5F,0x74,0x68,0x72,0x3D,0x00,0x20,0x74,0x68,0x5F, +0x73,0x74,0x66,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x74,0x72,0x3D,0x00,0x20,0x74, +0x68,0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x74,0x68,0x5F,0x73,0x69,0x7A,0x3D,0x00, +0x20,0x74,0x68,0x5F,0x74,0x72,0x67,0x3D,0x00,0x20,0x74,0x68,0x5F,0x66,0x6C,0x67, +0x3D,0x00,0x20,0x74,0x68,0x5F,0x63,0x6E,0x74,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73, +0x74,0x72,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x74,0x66,0x3D,0x00,0x20,0x72,0x68, +0x5F,0x62,0x61,0x73,0x3D,0x00,0x20,0x72,0x68,0x5F,0x73,0x69,0x7A,0x3D,0x00,0x20, +0x72,0x68,0x5F,0x73,0x70,0x61,0x3D,0x00,0x20,0x72,0x68,0x5F,0x61,0x73,0x6F,0x3D, +0x00,0x20,0x72,0x68,0x5F,0x72,0x6F,0x6F,0x3D,0x00,0x20,0x72,0x68,0x5F,0x66,0x6C, +0x67,0x3D,0x00,0x20,0x6D,0x5F,0x63,0x61,0x72,0x65,0x3D,0x00,0x20,0x70,0x74,0x5F, +0x66,0x6C,0x6F,0x3D,0x00,0x20,0x61,0x73,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x72, +0x6D,0x5F,0x66,0x6C,0x6F,0x3D,0x00,0x20,0x20,0x20,0x71,0x5F,0x69,0x6E,0x3D,0x00, +0x20,0x20,0x71,0x5F,0x6F,0x75,0x74,0x3D,0x00,0x20,0x71,0x5F,0x64,0x72,0x61,0x6E, +0x3D,0x00,0x20,0x20,0x71,0x5F,0x74,0x69,0x6D,0x3D,0x00,0x20,0x20,0x20,0x71,0x5F, +0x66,0x63,0x3D,0x00,0x20,0x71,0x5F,0x73,0x74,0x61,0x74,0x3D,0x00,0x20,0x71,0x5F, +0x64,0x61,0x74,0x61,0x3D,0x00,0x20,0x71,0x5F,0x6D,0x6F,0x64,0x6D,0x3D,0x00,0x20, +0x68,0x61,0x6E,0x64,0x5F,0x6F,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x62,0x3D, +0x00,0x20,0x68,0x61,0x6E,0x64,0x5F,0x65,0x3D,0x00,0x20,0x68,0x61,0x6E,0x64,0x5F, +0x69,0x3D,0x00,0x20,0x20,0x6F,0x70,0x6F,0x73,0x74,0x3D,0x00,0x20,0x20,0x74,0x69, +0x6D,0x65,0x6F,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x31,0x3D,0x00,0x20,0x63, +0x75,0x73,0x74,0x6D,0x32,0x3D,0x00,0x20,0x63,0x75,0x73,0x74,0x6D,0x64,0x3D,0x00, +0x20,0x74,0x78,0x72,0x61,0x74,0x65,0x3D,0x00,0x20,0x72,0x78,0x72,0x61,0x74,0x65, +0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x61,0x70,0x3D,0x00,0x20,0x63,0x5F,0x61,0x64, +0x64,0x72,0x3D,0x00,0x20,0x63,0x5F,0x61,0x69,0x73,0x72,0x3D,0x00,0x20,0x63,0x5F, +0x78,0x74,0x61,0x67,0x3D,0x00,0x20,0x63,0x5F,0x64,0x65,0x66,0x72,0x3D,0x00,0x20, +0x63,0x5F,0x66,0x6C,0x73,0x68,0x3D,0x00,0x20,0x74,0x78,0x6D,0x61,0x78,0x73,0x3D, +0x00,0x20,0x72,0x69,0x5F,0x65,0x6D,0x73,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6C,0x73, +0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x65,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F, +0x66,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x6D,0x63,0x72,0x3D,0x00,0x20,0x20, +0x63,0x5F,0x6C,0x63,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x64,0x73,0x73,0x3D,0x00, +0x20,0x63,0x5F,0x64,0x73,0x73,0x69,0x3D,0x00,0x20,0x63,0x5F,0x64,0x73,0x73,0x72, +0x3D,0x00,0x20,0x20,0x63,0x5F,0x69,0x73,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x63, +0x61,0x72,0x3D,0x00,0x20,0x20,0x63,0x5F,0x65,0x66,0x72,0x3D,0x00,0x20,0x63,0x5F, +0x65,0x72,0x73,0x74,0x3D,0x00,0x20,0x63,0x5F,0x65,0x63,0x6E,0x74,0x3D,0x00,0x20, +0x63,0x5F,0x62,0x72,0x6B,0x63,0x3D,0x00,0x20,0x63,0x5F,0x62,0x6F,0x6B,0x63,0x3D, +0x00,0x20,0x63,0x5F,0x72,0x65,0x70,0x6C,0x3D,0x00,0x20,0x63,0x5F,0x63,0x63,0x73, +0x72,0x3D,0x00,0x20,0x63,0x5F,0x73,0x74,0x74,0x31,0x3D,0x00,0x20,0x63,0x5F,0x73, +0x74,0x74,0x32,0x3D,0x00,0x2B,0xC0,0x8E,0xD8,0x8E,0xC0,0xE8,0xC2,0x00,0xE8,0xE5, +0x00,0xFA,0xBF,0x84,0x00,0xC7,0x05,0xDC,0x56,0x8C,0x4D,0x02,0xBF,0x0C,0x00,0xC7, +0x05,0x6E,0x5E,0x8C,0x4D,0x02,0xBF,0x04,0x00,0xC7,0x05,0xBA,0x5E,0x8C,0x4D,0x02, +0xE8,0xF1,0x00,0x90,0xE8,0x49,0x01,0xE8,0x16,0x00,0xF4,0x90,0xE8,0xE5,0x00,0xBE, +0xBA,0x4D,0xE8,0x09,0x0C,0xA0,0x93,0x12,0xE8,0x5D,0x0C,0xE8,0xC2,0x09,0xEB,0xE4, +0xE8,0xD5,0x0C,0xE8,0xC4,0x0C,0x0A,0xC0,0x74,0xF6,0x8B,0x1E,0xF8,0x79,0x3C,0x0D, +0x74,0x2E,0x3C,0x08,0x74,0x17,0x3C,0x7F,0x74,0x13,0x83,0xFB,0x20,0x7F,0xE1,0x88, +0x87,0xD6,0x79,0x43,0x89,0x1E,0xF8,0x79,0xE8,0x77,0x0C,0xEB,0xD3,0x0B,0xDB,0x74, +0xCF,0x4B,0x89,0x1E,0xF8,0x79,0x8B,0x36,0x16,0x7A,0xE8,0xC1,0x0B,0xEB,0xC1,0x90, +0xE8,0x02,0x00,0xEB,0xBB,0xC6,0x87,0xD6,0x79,0x00,0x0B,0xDB,0x74,0x1E,0xA0,0xD6, +0x79,0xBF,0x60,0x51,0xB9,0x1D,0x00,0x8B,0xD9,0x06,0x0E,0x07,0xF2,0xAE,0x07,0x75, +0x17,0x41,0x2B,0xD9,0xD1,0xE3,0x2E,0xFF,0x97,0x7D,0x51,0x90,0x33,0xC0,0xA3,0xF8, +0x79,0xBE,0x89,0x4D,0xE8,0x87,0x0B,0xC3,0xBE,0x8D,0x4D,0xE8,0x80,0x0B,0xEB,0xEC, +0xBA,0x00,0x02,0xB0,0x93,0xEE,0xB0,0x55,0xEE,0xBA,0x10,0x02,0xB0,0x93,0xEE,0xB0, +0xAA,0xEE,0xBA,0x00,0x02,0xEC,0x3C,0x55,0x75,0x08,0xBA,0x10,0x02,0xEC,0x3C,0xAA, +0x74,0x03,0xE8,0x2F,0xF6,0xC3,0xBA,0x04,0x02,0xB0,0x1A,0xEE,0xB0,0x20,0xEE,0xB0, +0x30,0xEE,0xB0,0x40,0xEE,0xB0,0x80,0xEE,0xBA,0x00,0x02,0xB0,0x13,0xEE,0xB0,0x07, +0xEE,0xBA,0x08,0x02,0xB0,0x80,0xEE,0xBA,0x02,0x02,0xB0,0xBB,0xEE,0xBA,0x04,0x02, +0xB0,0x05,0xEE,0xC3,0xC6,0x06,0xCA,0x13,0x01,0xC7,0x06,0xF8,0x79,0x00,0x00,0xC6, +0x06,0xF6,0x79,0x01,0xC7,0x06,0xD0,0x79,0x00,0x00,0xC7,0x06,0xD2,0x79,0x00,0x00, +0xC7,0x06,0xD4,0x79,0x00,0x00,0xC7,0x06,0xFA,0x79,0x00,0x00,0xC7,0x06,0xFC,0x79, +0x00,0x00,0xC7,0x06,0xFE,0x79,0x00,0x00,0xC7,0x06,0x00,0x7A,0x00,0x00,0xC7,0x06, +0x02,0x7A,0xCE,0x59,0x8C,0x0E,0x04,0x7A,0xC7,0x06,0x06,0x7A,0x00,0x00,0xC7,0x06, +0x27,0x7A,0x00,0x00,0xC6,0x06,0x29,0x7A,0x00,0xC6,0x06,0x2A,0x7A,0x00,0xC3,0x90, +0xBE,0x22,0x4D,0xE8,0xC8,0x0A,0xE8,0x3F,0x00,0x2C,0x31,0x3C,0x01,0x77,0xF7,0xE8, +0x81,0x09,0x8B,0x36,0x0C,0x7A,0xE8,0xB5,0x0A,0xBE,0x6A,0x4D,0xE8,0xAF,0x0A,0x0E, +0x58,0xE8,0xF8,0x0A,0xBE,0x7A,0x4D,0xE8,0xA4,0x0A,0xC3,0x90,0x60,0xD1,0xE3,0x83, +0xFB,0x18,0x73,0x11,0x1E,0xBA,0x00,0x00,0x8E,0xDA,0x2E,0xFF,0x97,0xB7,0x51,0x8B, +0xEC,0x89,0x46,0x10,0x1F,0x61,0xCF,0x90,0xE8,0x4F,0x0B,0x0A,0xC0,0x75,0x05,0xE8, +0x56,0x0B,0xEB,0xF4,0xC3,0x90,0x83,0x3E,0xF8,0x79,0x01,0x74,0x16,0xBE,0xD7,0x79, +0xE8,0x31,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x04,0x3C,0x20,0x75,0x05,0xE8,0x23, +0x0A,0xEE,0xC3,0xE9,0xD2,0xFE,0x83,0x3E,0xF8,0x79,0x01,0x74,0xF6,0xBE,0xD7,0x79, +0xE8,0x11,0x0A,0x8B,0xD0,0xAC,0x3C,0x2C,0x74,0x08,0x3C,0x20,0x74,0x04,0xE9,0xB7, +0xFE,0x90,0xE8,0xFF,0x09,0xEF,0xC3,0x90,0x8B,0x16,0x06,0x7A,0x83,0x3E,0xF8,0x79, +0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xEB,0x09,0x8B,0xD0,0xA3,0x06,0x7A,0xB0,0x20, +0xE8,0x57,0x0B,0x8B,0x16,0x06,0x7A,0xEC,0xE8,0x6F,0x0B,0xC3,0x8B,0x16,0x06,0x7A, +0x83,0x3E,0xF8,0x79,0x01,0x74,0x0B,0xBE,0xD7,0x79,0xE8,0xC7,0x09,0x8B,0xD0,0xA3, +0x06,0x7A,0xB0,0x20,0xE8,0x33,0x0B,0x8B,0x16,0x06,0x7A,0xED,0xE8,0x67,0x0B,0xC3, +0xFA,0xC6,0x06,0xF6,0x79,0x00,0xC3,0x90,0xC6,0x06,0xF6,0x79,0x01,0xFB,0xC3,0x90, +0x06,0xE8,0x58,0x09,0xB0,0x20,0xE8,0x11,0x0B,0x26,0x8B,0x05,0xE8,0x47,0x0B,0xB0, +0x08,0xE8,0x06,0x0B,0xE8,0x03,0x0B,0xE8,0x00,0x0B,0xE8,0xFD,0x0A,0xB8,0x01,0x00, +0xE8,0xCF,0xF4,0xBA,0x02,0x02,0xEC,0x24,0x01,0x75,0x02,0xEB,0xDC,0xBA,0x06,0x02, +0xEC,0x07,0xC3,0x90,0xC7,0x06,0x08,0x7A,0x10,0x00,0xEB,0x06,0xC7,0x06,0x08,0x7A, +0x01,0x00,0x06,0x8E,0x06,0xFC,0x79,0x8B,0x3E,0xFA,0x79,0xE8,0x0E,0x09,0xE8,0x0B, +0x00,0x89,0x3E,0xFA,0x79,0x8C,0x06,0xFC,0x79,0x07,0xC3,0x90,0xBE,0xB2,0x4D,0xE8, +0x7C,0x09,0x8B,0x16,0x08,0x7A,0x52,0xE8,0x2A,0x09,0xE8,0x0F,0x0A,0xE8,0x0C,0x0A, +0x33,0xDB,0xB9,0x10,0x00,0x90,0x26,0x8A,0x01,0xE8,0xBC,0x09,0xE8,0xFD,0x09,0x43, +0xE2,0xF4,0xE8,0xF7,0x09,0xE8,0xF4,0x09,0x33,0xDB,0xB9,0x10,0x00,0x90,0x26,0x8A, +0x01,0x3C,0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xE3,0x09,0x43, +0xE2,0xEC,0xBE,0xB2,0x4D,0xE8,0x36,0x09,0x83,0xC7,0x10,0x5A,0x4A,0x75,0xB7,0xC3, +0x06,0x8E,0x06,0x00,0x7A,0x8B,0x3E,0xFE,0x79,0xE8,0xA0,0x08,0x89,0x3E,0xFE,0x79, +0x8C,0x06,0x00,0x7A,0x57,0x8B,0x36,0x0E,0x7A,0xE8,0x12,0x09,0xC7,0x06,0x08,0x7A, +0x10,0x00,0xBA,0x00,0x02,0xE8,0xE8,0x00,0xE8,0x81,0xFF,0x5F,0xBA,0x00,0x00,0xE8, +0xDE,0x00,0xBE,0xB5,0x4D,0xE8,0xF6,0x08,0x8C,0xC0,0xE8,0x3F,0x09,0xB0,0x3A,0xE8, +0x90,0x09,0x8B,0xC7,0xE8,0x35,0x09,0xE8,0x7E,0x08,0xE8,0xC3,0x00,0x90,0xE8,0xB7, +0x09,0xE8,0xA6,0x09,0x0A,0xC0,0x74,0xF6,0x3C,0x0B,0x75,0x06,0x83,0xEF,0x10,0xEB, +0x19,0x90,0x3C,0x0A,0x75,0x06,0x83,0xC7,0x10,0xEB,0x0F,0x90,0x3C,0x0C,0x75,0x04, +0x47,0xEB,0x07,0x90,0x3C,0x08,0x75,0x24,0x4F,0x90,0x8B,0x36,0xFE,0x79,0x8B,0xC7, +0x2B,0xC6,0x3D,0x00,0x01,0x72,0xA5,0x3D,0x10,0x01,0x72,0x04,0x83,0xEE,0x20,0x90, +0x83,0xC6,0x10,0x89,0x36,0xFE,0x79,0x57,0x8B,0xFE,0xEB,0x80,0x3C,0x2E,0x75,0x08, +0xBA,0x01,0x13,0xE8,0x6A,0x00,0x07,0xC3,0xC6,0x06,0x0A,0x7A,0x02,0x32,0xC9,0x90, +0x3C,0x30,0x72,0x4C,0x3C,0x39,0x76,0x0C,0x24,0x5F,0x3C,0x41,0x72,0x42,0x3C,0x46, +0x77,0x3E,0x2C,0x07,0x2C,0x30,0x50,0xE8,0xCC,0x08,0x58,0x02,0xC8,0xFE,0x0E,0x0A, +0x7A,0x74,0x0F,0xC0,0xE1,0x04,0xE8,0x2F,0x09,0xE8,0x1E,0x09,0x0A,0xC0,0x74,0xF6, +0xEB,0xCE,0x26,0x88,0x0D,0xE8,0xE0,0x07,0x8A,0xD0,0xE8,0x23,0x00,0x8A,0xC1,0x3C, +0x20,0x72,0x05,0x3C,0x7E,0x76,0x03,0x90,0xB0,0x2E,0xE8,0xD5,0x08,0xE9,0x70,0xFF, +0xE8,0xC5,0x07,0xE8,0x0A,0x00,0x26,0x8A,0x05,0xE8,0x7C,0x08,0xE9,0x1D,0xFF,0x90, +0xF6,0x06,0x26,0x7A,0x02,0x75,0x02,0x86,0xF2,0x52,0x8B,0x36,0x1A,0x7A,0xE8,0x0D, +0x08,0x5A,0x52,0x8A,0xC6,0x02,0x06,0x24,0x7A,0xF6,0x06,0x26,0x7A,0x01,0x75,0x06, +0xE8,0x9F,0x08,0xEB,0x0D,0x90,0x32,0xE4,0xE8,0x0D,0x08,0x8B,0x36,0x1C,0x7A,0xE8, +0xEC,0x07,0x5A,0x8A,0xC2,0x02,0x06,0x25,0x7A,0xF6,0x06,0x26,0x7A,0x01,0x75,0x06, +0xE8,0x7F,0x08,0xEB,0x06,0x90,0x32,0xE4,0xE8,0xED,0x07,0x8B,0x36,0x1E,0x7A,0xE8, +0xCC,0x07,0xC3,0x90,0x06,0x8E,0x06,0x04,0x7A,0x8B,0x3E,0x02,0x7A,0xE8,0x3C,0x07, +0x89,0x3E,0x02,0x7A,0x8C,0x06,0x04,0x7A,0x07,0xFF,0x1E,0x02,0x7A,0xC3,0xBE,0x97, +0x4D,0xE8,0xAA,0x07,0xCB,0x90,0x06,0x57,0xBE,0xD7,0x79,0xE8,0x66,0x07,0x8B,0xD8, +0xE8,0x61,0x07,0x8B,0xC8,0x2B,0xCB,0x78,0x11,0x8E,0xC3,0xBF,0x00,0x00,0xB8,0xFF, +0xFF,0x51,0xB9,0x08,0x00,0xF3,0xAB,0x59,0xE2,0xF7,0x5F,0x07,0xC3,0x90,0x06,0xBE, +0xD7,0x79,0xE8,0x3F,0x07,0x8B,0xD8,0xD1,0xE3,0x2E,0x8B,0x9F,0x44,0x00,0xBE,0x26, +0x52,0xE8,0xF1,0x08,0x8B,0xC3,0xE8,0xDD,0x08,0xB8,0x01,0x00,0xE8,0x73,0xF2,0xE8, +0xE0,0x08,0xBE,0x2F,0x52,0xE8,0xDD,0x08,0x8B,0x47,0x18,0xE8,0xC8,0x08,0xBE,0x77, +0x52,0xE8,0xD1,0x08,0x8B,0x47,0x26,0xE8,0xBC,0x08,0xBE,0x53,0x52,0xE8,0xC5,0x08, +0x8B,0x47,0x1E,0xE8,0xB0,0x08,0xBE,0x5C,0x52,0xE8,0xB9,0x08,0x8B,0x47,0x20,0xE8, +0xA4,0x08,0xBE,0x6E,0x52,0xE8,0xAD,0x08,0x8B,0x47,0x24,0xE8,0x98,0x08,0xBE,0x80, +0x52,0xE8,0xA1,0x08,0x8B,0x47,0x2A,0xE8,0x8C,0x08,0xE8,0x95,0x08,0xBE,0x38,0x52, +0xE8,0x92,0x08,0x8B,0x07,0xE8,0x7E,0x08,0xBE,0x41,0x52,0xE8,0x87,0x08,0x8B,0x47, +0x1A,0xE8,0x72,0x08,0xBE,0x4A,0x52,0xE8,0x7B,0x08,0x8B,0x47,0x1C,0xE8,0x66,0x08, +0xBE,0x65,0x52,0xE8,0x6F,0x08,0x8B,0x47,0x22,0xE8,0x5A,0x08,0xE8,0x63,0x08,0xBE, +0xD1,0x52,0xE8,0x60,0x08,0x8B,0x47,0x38,0xE8,0x4B,0x08,0xBE,0xAD,0x52,0xE8,0x54, +0x08,0x8B,0x47,0x30,0xE8,0x3F,0x08,0xBE,0xB6,0x52,0xE8,0x48,0x08,0x8B,0x47,0x32, +0xE8,0x33,0x08,0xBE,0xA4,0x52,0xE8,0x3C,0x08,0x8B,0x47,0x2E,0xE8,0x27,0x08,0xBE, +0xBF,0x52,0xE8,0x30,0x08,0x8B,0x47,0x34,0xE8,0x1B,0x08,0xE8,0x24,0x08,0xBE,0x89, +0x52,0xE8,0x21,0x08,0x8B,0x47,0x04,0xE8,0x0C,0x08,0xBE,0x92,0x52,0xE8,0x15,0x08, +0x8B,0x47,0x14,0xE8,0x00,0x08,0xBE,0x9B,0x52,0xE8,0x09,0x08,0x8B,0x47,0x2C,0xE8, +0xF4,0x07,0xBE,0xC8,0x52,0xE8,0xFD,0x07,0x8B,0x47,0x36,0xE8,0xE8,0x07,0xBE,0xDA, +0x52,0xE8,0xF1,0x07,0x8B,0x47,0x3A,0xE8,0xDC,0x07,0xBE,0xE3,0x52,0xE8,0xE5,0x07, +0x8B,0x47,0x3C,0xE8,0xD0,0x07,0xE8,0xD9,0x07,0xBE,0x19,0x53,0xE8,0xD6,0x07,0x8B, +0x47,0x48,0xE8,0xC1,0x07,0xBE,0xFE,0x52,0xE8,0xCA,0x07,0x8B,0x47,0x42,0xE8,0xB5, +0x07,0xBE,0x07,0x53,0xE8,0xBE,0x07,0x8B,0x47,0x44,0xE8,0xA9,0x07,0xBE,0x7C,0x53, +0xE8,0xB2,0x07,0x8B,0x47,0x4C,0xE8,0x9D,0x07,0xBE,0x85,0x53,0xE8,0xA6,0x07,0x8B, +0x47,0x4E,0xE8,0x91,0x07,0xBE,0x8E,0x53,0xE8,0x9A,0x07,0x8B,0x47,0x50,0xE8,0x85, +0x07,0xE8,0x8E,0x07,0xBE,0x22,0x53,0xE8,0x8B,0x07,0x8B,0x47,0x4A,0xE8,0x76,0x07, +0xBE,0xEC,0x52,0xE8,0x7F,0x07,0x8B,0x47,0x08,0xE8,0x6A,0x07,0xBE,0xF5,0x52,0xE8, +0x73,0x07,0x8B,0x47,0x40,0xE8,0x5E,0x07,0xBE,0x10,0x53,0xE8,0x67,0x07,0x8B,0x47, +0x46,0xE8,0x52,0x07,0xE8,0x5B,0x07,0xBE,0x6A,0x53,0xE8,0x58,0x07,0x8B,0x47,0x7A, +0xE8,0x43,0x07,0xBE,0x3D,0x53,0xE8,0x4C,0x07,0x8B,0x47,0x70,0xE8,0x37,0x07,0xBE, +0x46,0x53,0xE8,0x40,0x07,0x8B,0x47,0x72,0xE8,0x2B,0x07,0xBE,0x4F,0x53,0xE8,0x34, +0x07,0x8B,0x47,0x74,0xE8,0x1F,0x07,0xE8,0x28,0x07,0xBE,0x2B,0x53,0xE8,0x25,0x07, +0x8B,0x47,0x0C,0xE8,0x10,0x07,0xBE,0x34,0x53,0xE8,0x19,0x07,0x8B,0x47,0x10,0xE8, +0x04,0x07,0xBE,0x58,0x53,0xE8,0x0D,0x07,0x8B,0x47,0x76,0xE8,0xF8,0x06,0xBE,0x61, +0x53,0xE8,0x01,0x07,0x8B,0x47,0x78,0xE8,0xEC,0x06,0xBE,0x73,0x53,0xE8,0xF5,0x06, +0x8B,0x47,0x3E,0xE8,0xE0,0x06,0xE8,0xE9,0x06,0xBE,0x97,0x53,0xE8,0xE6,0x06,0x8B, +0x47,0x52,0xE8,0xD1,0x06,0xBE,0xA0,0x53,0xE8,0xDA,0x06,0x8B,0x47,0x54,0xE8,0xC5, +0x06,0xBE,0xA9,0x53,0xE8,0xCE,0x06,0x8B,0x47,0x56,0xE8,0xB9,0x06,0xBE,0xB2,0x53, +0xE8,0xC2,0x06,0x8B,0x47,0x58,0xE8,0xAD,0x06,0xBE,0xBB,0x53,0xE8,0xB6,0x06,0x8B, +0x47,0x5A,0xE8,0xA1,0x06,0xBE,0xC4,0x53,0xE8,0xAA,0x06,0x8B,0x47,0x5C,0xE8,0x95, +0x06,0xE8,0x9E,0x06,0xBE,0xCD,0x53,0xE8,0x9B,0x06,0x8B,0x47,0x5E,0xE8,0x86,0x06, +0xBE,0xD6,0x53,0xE8,0x8F,0x06,0x8B,0x47,0x60,0xE8,0x7A,0x06,0xBE,0xDF,0x53,0xE8, +0x83,0x06,0x8B,0x47,0x62,0xE8,0x6E,0x06,0xBE,0xE8,0x53,0xE8,0x77,0x06,0x8B,0x47, +0x7C,0xE8,0x62,0x06,0xBE,0xF1,0x53,0xE8,0x6B,0x06,0x8B,0x47,0x7E,0xE8,0x56,0x06, +0xBE,0xFA,0x53,0xE8,0x5F,0x06,0x8B,0x87,0x80,0x00,0xE8,0x49,0x06,0xE8,0x52,0x06, +0xBE,0x42,0x54,0xE8,0x4F,0x06,0x8B,0x87,0x9E,0x00,0xE8,0x39,0x06,0xBE,0x03,0x54, +0xE8,0x42,0x06,0x8B,0x47,0x64,0xE8,0x2D,0x06,0xBE,0x0C,0x54,0xE8,0x36,0x06,0x8B, +0x47,0x6E,0xE8,0x21,0x06,0xBE,0x15,0x54,0xE8,0x2A,0x06,0x8B,0x87,0x8E,0x00,0xE8, +0x14,0x06,0xBE,0x1E,0x54,0xE8,0x1D,0x06,0x8B,0x87,0x90,0x00,0xE8,0x07,0x06,0xBE, +0x27,0x54,0xE8,0x10,0x06,0x8B,0x87,0x92,0x00,0xE8,0xFA,0x05,0xE8,0x03,0x06,0xBE, +0x30,0x54,0xE8,0x00,0x06,0x8B,0x87,0x94,0x00,0xE8,0xEA,0x05,0xBE,0x39,0x54,0xE8, +0xF3,0x05,0x8B,0x87,0x96,0x00,0xE8,0xDD,0x05,0xBE,0x6F,0x54,0xE8,0xE6,0x05,0x8B, +0x87,0x98,0x00,0xE8,0xD0,0x05,0xBE,0x5D,0x54,0xE8,0xD9,0x05,0x8A,0x87,0xA0,0x00, +0xE8,0xA7,0x05,0xBE,0x54,0x54,0xE8,0xCC,0x05,0x8A,0x47,0x28,0xE8,0x9B,0x05,0xBE, +0x66,0x54,0xE8,0xC0,0x05,0x8A,0x87,0xA1,0x00,0xE8,0x8E,0x05,0xE8,0xB3,0x05,0xBE, +0x78,0x54,0xE8,0xB0,0x05,0x8A,0x87,0xA2,0x00,0xE8,0x7E,0x05,0xBE,0x81,0x54,0xE8, +0xA3,0x05,0x8A,0x87,0xA3,0x00,0xE8,0x71,0x05,0xBE,0x8A,0x54,0xE8,0x96,0x05,0x8A, +0x87,0xA4,0x00,0xE8,0x64,0x05,0xBE,0x93,0x54,0xE8,0x89,0x05,0x8A,0x87,0xA5,0x00, +0xE8,0x57,0x05,0xBE,0x9C,0x54,0xE8,0x7C,0x05,0x8A,0x87,0xA6,0x00,0xE8,0x4A,0x05, +0xBE,0xA5,0x54,0xE8,0x6F,0x05,0x8A,0x87,0xA7,0x00,0xE8,0x3D,0x05,0xBE,0xAE,0x54, +0xE8,0x62,0x05,0x8A,0x87,0xA8,0x00,0xE8,0x30,0x05,0xE8,0x55,0x05,0xBE,0xB7,0x54, +0xE8,0x52,0x05,0x8A,0x87,0xA9,0x00,0xE8,0x20,0x05,0xBE,0xC0,0x54,0xE8,0x45,0x05, +0x8A,0x87,0xAA,0x00,0xE8,0x13,0x05,0xBE,0xC9,0x54,0xE8,0x38,0x05,0x8A,0x87,0xAB, +0x00,0xE8,0x06,0x05,0xBE,0xD2,0x54,0xE8,0x2B,0x05,0x8A,0x87,0xAD,0x00,0xE8,0xF9, +0x04,0xBE,0xDB,0x54,0xE8,0x1E,0x05,0x8A,0x87,0xAE,0x00,0xE8,0xEC,0x04,0xBE,0xE4, +0x54,0xE8,0x11,0x05,0x8A,0x87,0xAF,0x00,0xE8,0xDF,0x04,0xBE,0xED,0x54,0xE8,0x04, +0x05,0x8A,0x87,0xB0,0x00,0xE8,0xD2,0x04,0xE8,0xF7,0x04,0xBE,0xF6,0x54,0xE8,0xF4, +0x04,0x8A,0x87,0xB1,0x00,0xE8,0xC2,0x04,0xBE,0xFF,0x54,0xE8,0xE7,0x04,0x8A,0x87, +0xB2,0x00,0xE8,0xB5,0x04,0xBE,0x08,0x55,0xE8,0xDA,0x04,0x8A,0x87,0xB3,0x00,0xE8, +0xA8,0x04,0xBE,0x11,0x55,0xE8,0xCD,0x04,0x8A,0x87,0xBB,0x00,0xE8,0x9B,0x04,0xE8, +0xC0,0x04,0xBE,0x1A,0x55,0xE8,0xBD,0x04,0x8A,0x87,0xBC,0x00,0xE8,0x8B,0x04,0xBE, +0x23,0x55,0xE8,0xB0,0x04,0x8A,0x87,0xBE,0x00,0xE8,0x7E,0x04,0xBE,0x2C,0x55,0xE8, +0xA3,0x04,0x8A,0x87,0xBF,0x00,0xE8,0x71,0x04,0xE8,0x96,0x04,0x07,0xC3,0x60,0x06, +0x1E,0x16,0x8B,0xEC,0xFF,0x4E,0x16,0xF7,0x46,0x1A,0x00,0x02,0x74,0x01,0xFB,0xB8, +0x00,0x00,0x8E,0xD8,0x8E,0xC0,0x89,0x2E,0x2D,0x7A,0xE8,0xCB,0x00,0x81,0x66,0x1A, +0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8,0xD8,0x00,0xB8,0x00,0x5F,0xA3,0x2B,0x7A, +0xE8,0x5D,0x00,0x80,0x3E,0x2A,0x7A,0x00,0x74,0x0A,0x81,0x4E,0x1A,0x00,0x01,0xC6, +0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61,0xCF,0x90,0x60,0x06,0x1E,0x16,0x8B,0xEC, +0xF7,0x46,0x1A,0x00,0x02,0x74,0x01,0xFB,0xB8,0x00,0x00,0x8E,0xD8,0x8E,0xC0,0x89, +0x2E,0x2D,0x7A,0x81,0x66,0x1A,0xFF,0xFE,0xC6,0x06,0x2A,0x7A,0x00,0xE8,0x92,0x00, +0xB8,0x00,0x5F,0xA3,0x2B,0x7A,0xE8,0x17,0x00,0x80,0x3E,0x2A,0x7A,0x00,0x74,0x0A, +0x81,0x4E,0x1A,0x00,0x01,0xC6,0x06,0x2A,0x7A,0x00,0x17,0x1F,0x07,0x61,0xCF,0x90, +0xB8,0xF0,0x00,0xE8,0x8C,0xED,0xFF,0x26,0x2B,0x7A,0xC3,0x90,0x06,0x53,0x56,0x80, +0x3E,0x29,0x7A,0x00,0x74,0x03,0xE8,0x3F,0x00,0xBE,0xD7,0x79,0xE8,0x25,0x02,0x8B, +0xD8,0xA3,0x27,0x7A,0x2E,0x8A,0x07,0xA2,0x29,0x7A,0xB0,0xCC,0x2E,0x88,0x07,0x5E, +0x5B,0x07,0xC3,0xC6,0x06,0x2A,0x7A,0x00,0xB8,0x0A,0x5F,0xA3,0x2B,0x7A,0xC3,0x90, +0x8B,0x2E,0x2D,0x7A,0xE8,0x2B,0x00,0xC3,0xC6,0x06,0x2A,0x7A,0x01,0xE8,0x08,0x00, +0xB8,0x0A,0x5F,0xA3,0x2B,0x7A,0xC3,0x90,0x57,0x80,0x3E,0x29,0x7A,0x00,0x74,0x0F, +0x8B,0x3E,0x27,0x7A,0xA0,0x29,0x7A,0x2E,0x88,0x05,0xC6,0x06,0x29,0x7A,0x00,0x5F, +0xC3,0x90,0xBE,0xB2,0x4D,0xE8,0x06,0x02,0xBE,0xD8,0x51,0xE8,0x00,0x02,0xFF,0x76, +0x14,0x58,0xE8,0x47,0x02,0xBE,0xDE,0x51,0xE8,0xF3,0x01,0xFF,0x76,0x0E,0x58,0xE8, +0x3A,0x02,0xBE,0xE4,0x51,0xE8,0xE6,0x01,0xFF,0x76,0x12,0x58,0xE8,0x2D,0x02,0xBE, +0xEA,0x51,0xE8,0xD9,0x01,0xFF,0x76,0x10,0x58,0xE8,0x20,0x02,0xBE,0x14,0x52,0xE8, +0xCC,0x01,0xFF,0x76,0x0A,0x58,0xE8,0x13,0x02,0xBE,0x1A,0x52,0xE8,0xBF,0x01,0xFF, +0x76,0x0C,0x58,0xE8,0x06,0x02,0xBE,0xCF,0x51,0xE8,0xB2,0x01,0xFF,0x76,0x1A,0x58, +0xE8,0xF9,0x01,0xBE,0xB2,0x4D,0xE8,0xA5,0x01,0xBE,0xF0,0x51,0xE8,0x9F,0x01,0xFF, +0x76,0x18,0x58,0xE8,0xE6,0x01,0xBE,0xF6,0x51,0xE8,0x92,0x01,0xFF,0x76,0x02,0x58, +0xE8,0xD9,0x01,0xBE,0xFC,0x51,0xE8,0x85,0x01,0xFF,0x76,0x04,0x58,0xE8,0xCC,0x01, +0xBE,0x02,0x52,0xE8,0x78,0x01,0xFF,0x76,0x00,0x58,0xE8,0xBF,0x01,0xBE,0x08,0x52, +0xE8,0x6B,0x01,0xFF,0x76,0x06,0x58,0xE8,0xB2,0x01,0xBE,0x0E,0x52,0xE8,0x5E,0x01, +0xFF,0x76,0x08,0x58,0xE8,0xA5,0x01,0xBE,0x20,0x52,0xE8,0x51,0x01,0xFF,0x76,0x16, +0x58,0xE8,0x98,0x01,0xBE,0x89,0x4D,0xE8,0x44,0x01,0xC3,0x90,0xBE,0xC9,0x4D,0xE8, +0x3C,0x01,0xC3,0x3C,0x00,0x74,0x05,0x3C,0x01,0x74,0x59,0xC3,0xC7,0x06,0x0C,0x7A, +0xCD,0x50,0xC7,0x06,0x0E,0x7A,0xF0,0x50,0xC7,0x06,0x10,0x7A,0xE8,0x50,0xC7,0x06, +0x12,0x7A,0xEC,0x50,0xC7,0x06,0x14,0x7A,0xF4,0x50,0xC7,0x06,0x16,0x7A,0xFB,0x50, +0xC7,0x06,0x18,0x7A,0x03,0x51,0xC7,0x06,0x1A,0x7A,0x0B,0x51,0xC7,0x06,0x1C,0x7A, +0x0E,0x51,0xC7,0x06,0x1E,0x7A,0x10,0x51,0xC7,0x06,0x20,0x7A,0x12,0x51,0xC7,0x06, +0x22,0x7A,0x16,0x51,0xC6,0x06,0x24,0x7A,0x01,0xC6,0x06,0x25,0x7A,0x01,0xC6,0x06, +0x26,0x7A,0x03,0xC3,0xC7,0x06,0x0C,0x7A,0x1A,0x51,0xC7,0x06,0x0E,0x7A,0x4D,0x51, +0xC7,0x06,0x10,0x7A,0x47,0x51,0xC7,0x06,0x12,0x7A,0x4A,0x51,0xC7,0x06,0x14,0x7A, +0x4F,0x51,0xC7,0x06,0x16,0x7A,0x51,0x51,0xC7,0x06,0x18,0x7A,0x55,0x51,0xC7,0x06, +0x1A,0x7A,0x56,0x51,0xC7,0x06,0x1C,0x7A,0x59,0x51,0xC7,0x06,0x1E,0x7A,0x5A,0x51, +0xC7,0x06,0x20,0x7A,0x5B,0x51,0xC7,0x06,0x22,0x7A,0x5E,0x51,0xC6,0x06,0x24,0x7A, +0x20,0xC6,0x06,0x25,0x7A,0x20,0xC6,0x06,0x26,0x7A,0x02,0xC3,0xA1,0xF8,0x79,0x48, +0x74,0x14,0xBE,0xD7,0x79,0xE8,0x3C,0x00,0x8B,0xF8,0xAC,0x3C,0x3A,0x75,0x07,0x8E, +0xC7,0xE8,0x30,0x00,0x8B,0xF8,0xC3,0x90,0x8B,0xC7,0x2B,0x06,0xFE,0x79,0x8A,0xF0, +0x24,0x0F,0x8A,0xD0,0x02,0xD0,0x02,0xD0,0x80,0xC2,0x0B,0xC0,0xEE,0x04,0x80,0xC6, +0x03,0x04,0x3D,0xC3,0x8C,0xC0,0xE8,0x93,0x00,0xB0,0x3A,0xE8,0xE4,0x00,0x8B,0xC7, +0xE8,0x89,0x00,0xC3,0x51,0x33,0xC9,0x90,0xAC,0x3C,0x20,0x74,0xFB,0x90,0x0A,0xC0, +0x74,0x26,0x2C,0x30,0x72,0x22,0x3C,0x09,0x76,0x14,0x3C,0x11,0x72,0x1A,0x2C,0x07, +0x3C,0x0F,0x76,0x0A,0x3C,0x2A,0x72,0x10,0x2C,0x20,0x3C,0x0F,0x77,0x0A,0x98,0xC1, +0xE1,0x04,0x03,0xC8,0xAC,0xEB,0xD7,0x90,0x4E,0x8B,0xC1,0x59,0xC3,0x90,0x06,0x8C, +0xC8,0x8E,0xC0,0xE8,0x02,0x00,0x07,0xC3,0x26,0x8A,0x04,0x46,0x0A,0xC0,0x74,0x06, +0xE8,0x8F,0x00,0xEB,0xF3,0x90,0xC3,0x90,0x0B,0xC0,0x74,0x7A,0x51,0x33,0xD2,0xB9, +0xE8,0x03,0xF7,0xF1,0x8B,0xCA,0xE8,0x03,0x00,0x8B,0xC1,0x59,0xBA,0x64,0x00,0xF6, +0xF2,0xE8,0x0C,0x00,0x8A,0xC4,0x98,0xB2,0x0A,0xF6,0xF2,0xE8,0x02,0x00,0x8A,0xC4, +0x50,0x0A,0xF0,0x74,0x05,0x04,0x30,0xE8,0x58,0x00,0x58,0xC3,0x86,0xC4,0xE8,0x07, +0x00,0x86,0xC4,0xE8,0x02,0x00,0xC3,0x90,0xC1,0xC8,0x04,0xE8,0x08,0x00,0xC1,0xC0, +0x04,0xE8,0x02,0x00,0xC3,0x90,0x53,0x50,0x24,0x0F,0xBB,0xCA,0x62,0x2E,0xD7,0xE8, +0x30,0x00,0x58,0x5B,0xC3,0x90,0x86,0xC4,0xE8,0x07,0x00,0x86,0xC4,0xE8,0x02,0x00, +0xC3,0x90,0x50,0xB9,0x08,0x00,0x8A,0xE0,0x32,0xC0,0xD1,0xC0,0x04,0x30,0xE8,0x11, +0x00,0xE2,0xF5,0x58,0xC3,0x90,0xB0,0x30,0xE8,0x07,0x00,0xC3,0xB0,0x20,0xE8,0x01, +0x00,0xC3,0x56,0x8B,0x36,0xD0,0x79,0x88,0x84,0xD0,0x77,0x46,0x81,0xE6,0xFF,0x01, +0xFF,0x06,0xD4,0x79,0x89,0x36,0xD0,0x79,0x81,0x3E,0xD4,0x79,0xFE,0x01,0x75,0x08, +0x56,0xE8,0x14,0x00,0x5E,0xEB,0xF1,0x90,0x5E,0xC3,0xBA,0x02,0x02,0xEC,0x24,0x01, +0x74,0x04,0xBA,0x06,0x02,0xEC,0xC3,0x90,0x80,0x3E,0xF6,0x79,0x00,0x74,0x09,0x60, +0xB8,0x01,0x00,0xE8,0x2C,0xEA,0x61,0x90,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x74,0x28, +0x8B,0x36,0xD2,0x79,0x83,0x3E,0xD4,0x79,0x00,0x74,0x1D,0x8A,0x84,0xD0,0x77,0x46, +0x81,0xE6,0xFF,0x01,0x89,0x36,0xD2,0x79,0xFF,0x0E,0xD4,0x79,0xBA,0x06,0x02,0xEE, +0xBA,0x02,0x02,0xEC,0xA8,0x04,0x75,0xDC,0xA1,0xD4,0x79,0xC3,0x52,0xBA,0x06,0x02, +0xEE,0x5A,0xC3,0x90,0x52,0x50,0xBA,0x02,0x02,0xEC,0xA8,0x04,0x74,0x08,0x58,0x5A, +0xE8,0xE9,0xFF,0xF9,0xC3,0x90,0x58,0x5A,0xF8,0xC3,0x52,0x50,0xBA,0x02,0x02,0xEC, +0xA8,0x04,0x74,0xFB,0x58,0x5A,0xE8,0xD3,0xFF,0xC3,0x30,0x31,0x32,0x33,0x34,0x35, +0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,0x53,0x50,0x8A,0xE0,0x80,0xE4, +0x0F,0xBB,0xCA,0x62,0xC0,0xE8,0x04,0x2E,0xD7,0xE8,0xCE,0xFF,0x8A,0xC4,0x2E,0xD7, +0xE8,0xC7,0xFF,0x58,0x5B,0xC3,0x86,0xE0,0xE8,0xDF,0xFF,0x86,0xE0,0xE8,0xDA,0xFF, +0xC3,0x90,0xBE,0xB2,0x4D,0x50,0x2E,0xAC,0x3C,0x00,0x74,0x05,0xE8,0xAB,0xFF,0xEB, +0xF5,0x58,0xC3,0x90,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0xBF,0x04,0x00, +0xC7,0x46,0xFC,0x00,0x00,0xC7,0x46,0xFA,0x00,0x00,0xC7,0x46,0xF8,0x00,0x00,0x83, +0x7E,0x06,0x00,0x75,0x0E,0x56,0xE8,0xB6,0x0E,0x59,0x0B,0xC0,0x75,0x05,0x8B,0xC7, +0xE9,0x5B,0x01,0x8B,0x46,0xFC,0x89,0x46,0xFE,0x0B,0xFF,0x75,0x05,0xB8,0x01,0x00, +0xEB,0x02,0x33,0xC0,0x50,0x56,0xE8,0xA4,0x0D,0x59,0x59,0xB4,0x00,0x89,0x46,0xFC, +0x8B,0x5E,0xFC,0x83,0xFB,0x08,0x76,0x03,0xE9,0x2B,0x01,0xD1,0xE3,0x2E,0xFF,0xA7, +0xB2,0x64,0xB8,0x03,0x00,0xE9,0x26,0x01,0x83,0x7E,0xFA,0x00,0x74,0x14,0xC7,0x46, +0xFA,0x00,0x00,0x8A,0x44,0x58,0x98,0x50,0x8A,0x44,0x59,0x98,0x50,0xE8,0xC2,0x0F, +0x59,0x59,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,0xE8,0x9B, +0x08,0x59,0x83,0x7E,0x06,0x00,0x75,0x05,0x8B,0xC7,0xE9,0xF1,0x00,0x83,0xFF,0x04, +0x75,0x03,0xE9,0xE6,0x00,0x8B,0xC7,0xE9,0xE4,0x00,0x83,0x7E,0xFE,0x00,0x75,0x03, +0xBF,0x02,0x00,0xE9,0xD5,0x00,0x83,0x7E,0xFE,0x00,0x75,0x03,0xBF,0x01,0x00,0xE9, +0xC9,0x00,0x8B,0x5E,0xFE,0x83,0xFB,0x07,0x76,0x03,0xE9,0x86,0x00,0xD1,0xE3,0x2E, +0xFF,0xA7,0xA2,0x64,0x33,0xFF,0xE9,0x7F,0x00,0xBF,0x04,0x00,0x80,0x7C,0x58,0x0F, +0x74,0x22,0x83,0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x44,0x58,0x6A,0x08,0x56,0xE8,0x7E, +0x0C,0x59,0x59,0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x72,0x0C,0x59,0x59,0xC7, +0x46,0xFA,0x01,0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56, +0xE8,0x19,0x08,0x59,0xEB,0x42,0xBF,0x04,0x00,0x80,0x7C,0x58,0x00,0x74,0x22,0x83, +0x7E,0xF8,0x00,0x75,0x1C,0xFE,0x4C,0x58,0x6A,0x08,0x56,0xE8,0x41,0x0C,0x59,0x59, +0x8A,0x44,0x58,0x04,0x80,0x50,0x56,0xE8,0x35,0x0C,0x59,0x59,0xC7,0x46,0xFA,0x01, +0x00,0x83,0x7E,0xF8,0x00,0x74,0x0A,0xC7,0x46,0xF8,0x00,0x00,0x56,0xE8,0xDC,0x07, +0x59,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xEB,0x31,0xBF,0x04,0x00,0xEB,0x2C,0xC7, +0x46,0xF8,0x01,0x00,0x6A,0x08,0x56,0xE8,0x05,0x0C,0x59,0x59,0x80,0x7C,0x58,0x09, +0x7D,0x04,0xB0,0x0F,0xEB,0x02,0xB0,0x00,0x04,0x80,0x50,0x56,0xE8,0xF0,0x0B,0x59, +0x59,0xBF,0x04,0x00,0xEB,0x05,0xBF,0x04,0x00,0xEB,0x00,0xE9,0xA5,0xFE,0x5F,0x5E, +0xC9,0xC3,0xE4,0x63,0x63,0x64,0x63,0x64,0x63,0x64,0x63,0x64,0xE9,0x63,0x26,0x64, +0x51,0x64,0x78,0x63,0xBA,0x63,0xC6,0x63,0x96,0x64,0xD2,0x63,0x6A,0x64,0x6A,0x64, +0x6F,0x64,0x72,0x63,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x76,0x04,0x8B,0x7E,0x08, +0x6A,0x01,0x56,0xE8,0xA9,0x0B,0x59,0x59,0x8A,0x46,0x06,0xC0,0xE0,0x06,0x04,0x80, +0x50,0x56,0xE8,0x9A,0x0B,0x59,0x59,0xC7,0x46,0xFE,0x00,0x00,0x89,0x7E,0xF8,0xEB, +0x03,0xFF,0x46,0xFE,0x8B,0x5E,0xF8,0xFF,0x46,0xF8,0x80,0x3F,0x00,0x75,0xF2,0x83, +0x7E,0xFE,0x10,0x7D,0x25,0xB8,0x10,0x00,0x2B,0x46,0xFE,0xD1,0xF8,0x89,0x46,0xFC, +0xC7,0x46,0xFA,0x00,0x00,0xEB,0x0B,0x6A,0x20,0x56,0xE8,0x62,0x0B,0x59,0x59,0xFF, +0x46,0xFA,0x8B,0x46,0xFA,0x3B,0x46,0xFC,0x7C,0xED,0xEB,0x0C,0x8B,0xDF,0x47,0x8A, +0x07,0x50,0x56,0xE8,0x49,0x0B,0x59,0x59,0x80,0x3D,0x00,0x75,0xEF,0x6A,0x02,0x56, +0xE8,0x3C,0x0B,0x59,0x59,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x04,0x00,0x00,0x56, +0x57,0x8B,0x7E,0x04,0xC7,0x46,0xFE,0x00,0x00,0xBE,0x14,0x00,0xE9,0x09,0x01,0x8B, +0x5E,0xFE,0x83,0xC3,0x04,0x2B,0xDF,0x8A,0x87,0xAC,0x0B,0x88,0x44,0x5A,0xC6,0x44, +0x58,0x08,0x8A,0x46,0xFE,0x88,0x44,0x59,0xC7,0x44,0x06,0x00,0x00,0xC6,0x44,0x19, +0x00,0xC6,0x44,0x1A,0x00,0xC6,0x44,0x1B,0x00,0xC6,0x44,0x1D,0x0D,0xC6,0x44,0x1E, +0x03,0xC6,0x44,0x1F,0x00,0xC6,0x44,0x20,0x00,0xC6,0x44,0x21,0x00,0xC6,0x44,0x5B, +0x00,0xC6,0x44,0x5D,0x00,0xC6,0x44,0x5E,0x00,0xC6,0x44,0x5F,0x00,0xC6,0x44,0x60, +0x00,0xC7,0x46,0xFC,0x00,0x00,0xEB,0x0D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,0x40,0x30, +0x00,0x00,0xFF,0x46,0xFC,0x83,0x7E,0xFC,0x10,0x7C,0xED,0xC7,0x46,0xFC,0x00,0x00, +0xEB,0x0A,0x8B,0x5E,0xFC,0xC6,0x40,0x50,0x00,0xFF,0x46,0xFC,0x83,0x7E,0xFC,0x04, +0x7C,0xF0,0xC7,0x44,0x54,0x00,0x00,0xC7,0x44,0x56,0x00,0x00,0x8A,0x44,0x5A,0x98, +0xBA,0xF8,0x00,0x23,0xD0,0xB8,0x05,0x00,0x0B,0xC2,0x89,0x46,0xFC,0x9C,0xFA,0x8A, +0x46,0xFC,0xBA,0xFE,0x00,0xEE,0xBA,0x00,0x00,0xEC,0x9D,0x24,0x08,0x88,0x46,0xFC, +0x83,0x7E,0xFC,0x00,0x75,0x02,0xEB,0x4A,0xFF,0x76,0xFE,0xE8,0x7A,0x0C,0x59,0x68, +0x35,0x02,0x56,0xE8,0x32,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x34,0x68,0x38,0x02,0x56, +0xE8,0x25,0x0A,0x59,0x59,0x0B,0xC0,0x75,0x27,0x68,0x42,0x02,0x56,0xE8,0x18,0x0A, +0x59,0x59,0x0B,0xC0,0x75,0x1A,0x68,0x4C,0x02,0x56,0xE8,0x0B,0x0A,0x59,0x59,0x0B, +0xC0,0x75,0x0D,0x68,0x56,0x02,0x56,0xE8,0xFE,0x09,0x59,0x59,0x0B,0xC0,0x74,0x02, +0xEB,0x00,0xFF,0x46,0xFE,0x83,0xC6,0x62,0x39,0x7E,0xFE,0x7D,0x03,0xE9,0xEF,0xFE, +0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x08,0x00,0x00,0x56,0x57,0x8B,0x46,0x04,0xBA, +0x62,0x00,0xF7,0xEA,0x05,0x14,0x00,0x8B,0xF0,0x83,0x7E,0x06,0x00,0x74,0x05,0xB8, +0x10,0x00,0xEB,0x03,0xB8,0x08,0x00,0x89,0x44,0x04,0x8A,0x46,0x08,0x88,0x44,0x5C, +0x56,0xE8,0x59,0x04,0x59,0x8B,0xF8,0x8B,0xC7,0x89,0x44,0x56,0x89,0x44,0x54,0x8A, +0x44,0x5D,0x88,0x44,0x2F,0x0B,0xFF,0x75,0x1D,0x68,0xC2,0x0F,0x6A,0x01,0x56,0xE8, +0x02,0xFE,0x83,0xC4,0x06,0xEB,0x00,0x6A,0x01,0x56,0xE8,0x47,0xFC,0x59,0x59,0x0B, +0xC0,0x75,0xF4,0xBF,0x01,0x00,0x89,0x7E,0xFA,0xB9,0x05,0x00,0xBB,0xE9,0x6A,0x2E, +0x8B,0x07,0x3B,0x46,0xFA,0x74,0x07,0x43,0x43,0xE2,0xF4,0xE9,0xA4,0x03,0x2E,0xFF, +0x67,0x0A,0xC7,0x44,0x06,0x02,0x00,0xC7,0x44,0x08,0xF4,0x08,0x8B,0x5E,0x04,0xD1, +0xE3,0x8B,0x87,0xFC,0x08,0x89,0x44,0x0A,0x33,0xC0,0x8B,0xF8,0x89,0x44,0x54,0xE9, +0x80,0x03,0x56,0xE8,0xBB,0x05,0x59,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x60, +0xE9,0x6F,0x03,0x83,0x7C,0x04,0x08,0x75,0x30,0x80,0x7C,0x5C,0x01,0x75,0x15,0x8A, +0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xE4,0x08,0x56,0xE8,0xF7,0x08, +0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xC4, +0x08,0x56,0xE8,0xE2,0x08,0x59,0x59,0xEB,0x2E,0x80,0x7C,0x5C,0x01,0x75,0x15,0x8A, +0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xD4,0x08,0x56,0xE8,0xC7,0x08, +0x59,0x59,0xEB,0x13,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xB4, +0x08,0x56,0xE8,0xB2,0x08,0x59,0x59,0x6A,0x01,0x56,0xE8,0x87,0xFB,0x59,0x59,0x8B, +0xD8,0x83,0xFB,0x03,0x77,0x2A,0xD1,0xE3,0x2E,0xFF,0xA7,0xE1,0x6A,0xBF,0x01,0x00, +0x8A,0x44,0x5D,0x88,0x44,0x5E,0xEB,0x18,0x8A,0x44,0x5D,0x04,0xFF,0x24,0x07,0x88, +0x44,0x5D,0xEB,0x0C,0x8A,0x44,0x5D,0xFE,0xC0,0x24,0x07,0x88,0x44,0x5D,0xEB,0x00, +0xE9,0xCF,0x02,0x8A,0x44,0x5D,0xB4,0x00,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0xFD,0x02, +0x56,0xE8,0x63,0x08,0x59,0x59,0x68,0x1D,0x03,0x56,0xE8,0x5A,0x08,0x59,0x59,0x6A, +0x01,0x56,0xE8,0x2F,0xFB,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x77,0x36,0xD1,0xE3, +0x2E,0xFF,0xA7,0xD9,0x6A,0xBF,0x01,0x00,0x8A,0x44,0x5D,0x88,0x44,0x5F,0xEB,0x24, +0x8A,0x44,0x5D,0x04,0xFF,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22,0xC2,0x88,0x44,0x5D, +0xEB,0x12,0x8A,0x44,0x5D,0xFE,0xC0,0x8A,0x54,0x04,0x80,0xC2,0xFF,0x22,0xC2,0x88, +0x44,0x5D,0xEB,0x00,0xE9,0x6B,0x02,0x8B,0x5C,0x06,0x83,0xC3,0xFE,0xD1,0xE3,0x8B, +0x40,0x08,0x89,0x04,0x8B,0x1C,0xFF,0x77,0x06,0x6A,0x00,0x56,0xE8,0x85,0xFC,0x83, +0xC4,0x06,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x40,0x08,0x89,0x44,0x02,0x8B,0x5C, +0x02,0xFF,0x77,0x06,0x6A,0x01,0x56,0xE8,0x6A,0xFC,0x83,0xC4,0x06,0x6A,0x01,0x56, +0xE8,0xB1,0xFA,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x03,0x76,0x03,0xE9,0x1F,0x02,0xD1, +0xE3,0x2E,0xFF,0xA7,0xD1,0x6A,0x8B,0x5C,0x02,0x8B,0x47,0x04,0x89,0x44,0x02,0x8B, +0x5C,0x02,0x80,0x3F,0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4,0x00,0x3B, +0x44,0x04,0x7D,0xE2,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B,0x44,0x02, +0x89,0x47,0x08,0x8B,0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40,0x08,0xE9, +0xDE,0x01,0x8B,0x5C,0x02,0x8B,0x47,0x02,0x89,0x44,0x02,0x8B,0x5C,0x02,0x80,0x3F, +0x44,0x75,0x0D,0x8B,0x5C,0x02,0x8A,0x47,0x01,0xB4,0x00,0x3B,0x44,0x04,0x7D,0xE2, +0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x1C,0x03,0xD8,0x8B,0x44,0x02,0x89,0x47,0x08,0x8B, +0x5C,0x06,0x4B,0xD1,0xE3,0x8B,0x44,0x02,0x89,0x40,0x08,0xE9,0xA2,0x01,0xBF,0x01, +0x00,0xE9,0x9C,0x01,0x8B,0x5C,0x02,0x8A,0x07,0xB4,0x00,0x89,0x46,0xF8,0xB9,0x0C, +0x00,0xBB,0xA1,0x6A,0x2E,0x8B,0x07,0x3B,0x46,0xF8,0x74,0x07,0x43,0x43,0xE2,0xF4, +0xE9,0x77,0x01,0x2E,0xFF,0x67,0x18,0x8B,0x46,0x04,0xD1,0xE0,0x8B,0x5C,0x02,0x03, +0xD8,0x8B,0x47,0x08,0x8B,0x5C,0x06,0xFF,0x44,0x06,0xD1,0xE3,0x89,0x40,0x08,0x8B, +0x1C,0x80,0x7F,0x01,0x00,0x74,0x12,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A, +0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xE9,0x40,0x01,0xFF,0x4C,0x06,0xE9, +0x3A,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B, +0xDA,0x88,0x40,0x18,0xE9,0x25,0x01,0x8B,0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A, +0x57,0x01,0xB6,0x00,0x8B,0xDA,0x88,0x40,0x18,0xFF,0x4C,0x06,0xE9,0x0D,0x01,0x8B, +0x5C,0x02,0x8A,0x47,0x01,0x8B,0x1C,0x8A,0x57,0x01,0xB6,0x00,0x8B,0xDA,0x30,0x40, +0x18,0xE9,0xF8,0x00,0xB8,0xF0,0x10,0x8B,0xF8,0x89,0x44,0x54,0x8A,0x44,0x5F,0x88, +0x44,0x5D,0xE9,0xE7,0x00,0x8A,0x44,0x1C,0x98,0x3D,0x02,0x00,0x74,0x07,0x3D,0x03, +0x00,0x74,0x02,0xEB,0x07,0xC7,0x46,0xFE,0x00,0x00,0xEB,0x2B,0x8A,0x44,0x1C,0x98, +0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x69,0x02,0x56,0xE8,0x6B,0x06,0x59,0x59,0x6A,0x01, +0x56,0xE8,0x40,0xF9,0x59,0x59,0x89,0x46,0xFE,0x83,0x7E,0xFE,0x00,0x74,0x06,0x83, +0x7E,0xFE,0x03,0x75,0xE9,0xEB,0x00,0x83,0x7E,0xFE,0x03,0x74,0x62,0x8A,0x44,0x1C, +0x98,0xD1,0xE0,0x8B,0xD8,0xFF,0xB7,0x6D,0x02,0x56,0xE8,0x3A,0x06,0x59,0x59,0x56, +0xE8,0x4D,0x97,0x59,0x89,0x46,0xFC,0x8B,0x5E,0xFC,0x83,0xEB,0xFE,0x83,0xFB,0x03, +0x77,0x33,0xD1,0xE3,0x2E,0xFF,0xA7,0x99,0x6A,0x68,0xAC,0x02,0x56,0xE8,0x17,0x06, +0x59,0x59,0xEB,0x23,0x68,0x8F,0x02,0x56,0xE8,0x0C,0x06,0x59,0x59,0xEB,0x18,0x68, +0x75,0x02,0x56,0xE8,0x01,0x06,0x59,0x59,0xEB,0x0D,0x68,0xC6,0x02,0x56,0xE8,0xF6, +0x05,0x59,0x59,0xEB,0x02,0xEB,0x00,0x6A,0x01,0x56,0xE8,0xC7,0xF8,0x59,0x59,0xBF, +0x01,0x00,0xEB,0x38,0x68,0xDD,0x02,0x56,0xE8,0xDC,0x05,0x59,0x59,0x6A,0x01,0x56, +0xE8,0xB1,0xF8,0x59,0x59,0xBF,0x01,0x00,0xEB,0x22,0xB8,0xD0,0x30,0x8B,0xF8,0x89, +0x44,0x54,0x8A,0x44,0x60,0x88,0x44,0x5D,0xEB,0x12,0xB8,0xE0,0x20,0x8B,0xF8,0x89, +0x44,0x54,0x8A,0x44,0x5E,0x88,0x44,0x5D,0xEB,0x02,0xEB,0x00,0xEB,0x02,0xEB,0x00, +0xEB,0x00,0xE9,0x41,0xFC,0x5F,0x5E,0xC9,0xC3,0x19,0x6A,0x24,0x6A,0x2F,0x6A,0x3A, +0x6A,0x00,0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x41,0x00,0x42,0x00,0x43,0x00,0x44, +0x00,0x80,0x00,0x81,0x00,0x82,0x00,0xFF,0x00,0x17,0x69,0x54,0x6A,0x7A,0x6A,0xA5, +0x69,0x52,0x69,0x94,0x69,0x6A,0x6A,0x67,0x69,0x52,0x69,0x7F,0x69,0x67,0x69,0x4C, +0x69,0xF4,0x68,0x76,0x68,0xB2,0x68,0xEE,0x68,0xF5,0x67,0x00,0x68,0x12,0x68,0xF5, +0x67,0x9D,0x67,0xA8,0x67,0xB4,0x67,0x9D,0x67,0x00,0x00,0x01,0x00,0xF0,0x10,0xE0, +0x20,0xD0,0x30,0x27,0x68,0xF2,0x66,0xC3,0x67,0x23,0x67,0x12,0x67,0xC8,0x04,0x00, +0x00,0x56,0x57,0x8B,0x76,0x04,0x8A,0x44,0x59,0x98,0x89,0x46,0xFC,0x6A,0x09,0x8B, +0x46,0xFC,0x05,0x84,0x01,0x50,0xE8,0x93,0x08,0x59,0x59,0x8B,0xF8,0x8B,0xC7,0x25, +0x00,0xF0,0x3D,0x00,0x10,0x75,0x55,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xF0,0x00,0x75, +0x4B,0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44,0x04,0x3B, +0x46,0xFE,0x7D,0x05,0x33,0xC0,0xE9,0xEF,0x00,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F, +0x00,0x2B,0xD0,0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xE9,0xDB,0x00,0xC7,0x44,0x02, +0x04,0x09,0x8A,0x46,0xFE,0x88,0x44,0x5F,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3, +0xC7,0x87,0xFC,0x08,0x04,0x09,0xB8,0xF0,0x10,0xE9,0xBC,0x00,0x8B,0xC7,0x25,0x00, +0xF0,0x3D,0x00,0x20,0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xE0,0x00,0x75,0x48, +0x8B,0xC7,0x25,0x00,0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x83,0x7E,0xFE,0x08,0x7E, +0x05,0x33,0xC0,0xE9,0x92,0x00,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00,0x2B,0xD0, +0x3B,0x56,0xFE,0x74,0x05,0x33,0xC0,0xEB,0x7F,0x90,0xC7,0x44,0x02,0x0C,0x09,0x8A, +0x46,0xFE,0x88,0x44,0x5E,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,0x87,0xFC, +0x08,0x0C,0x09,0xB8,0xE0,0x20,0xEB,0x60,0x8B,0xC7,0x25,0x00,0xF0,0x3D,0x00,0x30, +0x75,0x52,0x8B,0xC7,0x25,0xF0,0x00,0x3D,0xD0,0x00,0x75,0x48,0x8B,0xC7,0x25,0x00, +0x0F,0xC1,0xF8,0x08,0x89,0x46,0xFE,0x8B,0x44,0x04,0x3B,0x46,0xFE,0x7D,0x04,0x33, +0xC0,0xEB,0x35,0x8B,0xC7,0x25,0x0F,0x00,0xBA,0x0F,0x00,0x2B,0xD0,0x3B,0x56,0xFE, +0x74,0x04,0x33,0xC0,0xEB,0x22,0xC7,0x44,0x02,0x14,0x09,0x8A,0x46,0xFE,0x88,0x44, +0x60,0x88,0x44,0x5D,0x8B,0x5E,0xFC,0xD1,0xE3,0xC7,0x87,0xFC,0x08,0x14,0x09,0xB8, +0xD0,0x30,0xEB,0x04,0x33,0xC0,0xEB,0x00,0x5F,0x5E,0xC9,0xC3,0xC8,0x06,0x00,0x00, +0x56,0x8B,0x76,0x04,0x6A,0x08,0x56,0xE8,0x35,0x04,0x59,0x59,0x8A,0x44,0x58,0x04, +0x80,0x50,0x56,0xE8,0x29,0x04,0x59,0x59,0x8B,0x44,0x54,0x3B,0x44,0x56,0x75,0x0A, +0x8A,0x44,0x5D,0x3A,0x44,0x2F,0x75,0x02,0xEB,0x64,0x8B,0x44,0x54,0x89,0x44,0x56, +0x8B,0x5C,0x02,0x8A,0x47,0x01,0x88,0x44,0x2F,0x8A,0x44,0x5D,0xB4,0x00,0xC1,0xE0, +0x08,0x8B,0x54,0x54,0x0B,0xD0,0x8A,0x44,0x5D,0xB4,0x00,0xBB,0x0F,0x00,0x2B,0xD8, +0x0B,0xD3,0x89,0x56,0xFE,0x6A,0x10,0x8A,0x44,0x59,0x98,0x05,0x04,0x00,0x99,0x05, +0x40,0x01,0x83,0xD2,0x00,0x52,0x50,0xE8,0x54,0x08,0x83,0xC4,0x06,0x89,0x56,0xFC, +0x89,0x46,0xFA,0x8B,0x46,0xFE,0x09,0x46,0xFA,0x83,0x4E,0xFC,0x00,0x6A,0x19,0xFF, +0x76,0xFC,0xFF,0x76,0xFA,0xE8,0x73,0x07,0x83,0xC4,0x06,0xE8,0xFE,0x07,0x5E,0xC9, +0xC3,0xC8,0x1C,0x00,0x00,0x56,0x57,0x8B,0x5E,0x04,0x8A,0x47,0x59,0x98,0x8B,0xF0, +0x8B,0x5E,0x04,0x8A,0x47,0x5D,0xB4,0x00,0x89,0x46,0xE6,0x83,0x7E,0xE6,0x00,0x7D, +0x0A,0x8B,0x5E,0x04,0x8B,0x47,0x04,0x48,0x89,0x46,0xE6,0x8B,0x5E,0x04,0x8B,0x47, +0x04,0x3B,0x46,0xE6,0x7F,0x05,0xC7,0x46,0xE6,0x00,0x00,0x8B,0x5E,0x04,0x8A,0x46, +0xE6,0x88,0x47,0x5D,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x02,0x20, +0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x03,0x30,0x8B,0xDE,0xD1,0xE3, +0x8B,0x9F,0x61,0x02,0xC6,0x47,0x02,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02, +0xC6,0x47,0x03,0x30,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18, +0x8B,0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1, +0xE3,0x8B,0x9F,0x59,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA,0x33,0xD2, +0xF7,0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA,0xBB,0x0A, +0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02, +0x88,0x57,0x02,0x8B,0x46,0xE6,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B, +0x46,0xFA,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3, +0x8B,0x9F,0x61,0x02,0x88,0x57,0x03,0xBB,0x0A,0x00,0x8B,0x46,0xFA,0x33,0xD2,0xF7, +0xF3,0x89,0x46,0xFA,0x83,0x7E,0xFA,0x00,0x74,0x18,0x8B,0x46,0xFA,0xBB,0x0A,0x00, +0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0x88, +0x57,0x02,0x8B,0x5E,0xE6,0xD1,0xE3,0xFF,0xB7,0x12,0x02,0x6A,0x00,0xFF,0x76,0x04, +0xE8,0xD1,0xF6,0x83,0xC4,0x06,0x68,0xD3,0x0F,0x6A,0x01,0xFF,0x76,0x04,0xE8,0xC3, +0xF6,0x83,0xC4,0x06,0xFF,0x76,0xE6,0x56,0xE8,0x01,0x93,0x59,0x59,0x89,0x56,0xF2, +0x89,0x46,0xF0,0xFF,0x76,0xE6,0x56,0xE8,0x14,0x93,0x59,0x59,0x89,0x56,0xEE,0x89, +0x46,0xEC,0x9C,0xFA,0xC4,0x5E,0xF0,0x26,0x8B,0x07,0x89,0x46,0xEA,0xC4,0x5E,0xEC, +0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE,0x9D,0xC7,0x46, +0xE4,0x01,0x00,0xE8,0xEE,0xA0,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFC,0x8B,0x46,0xFC, +0x2B,0x46,0xFE,0x3D,0xE8,0x03,0x73,0x03,0xE9,0x80,0x01,0x9C,0xFA,0xBA,0x50,0xFF, +0xED,0x89,0x46,0xFC,0x8B,0x46,0xFC,0x2B,0x46,0xFE,0x89,0x46,0xF8,0xC4,0x5E,0xF0, +0x26,0x8B,0x07,0x2B,0x46,0xEA,0x89,0x46,0xF6,0xC4,0x5E,0xF0,0x26,0x8B,0x07,0x89, +0x46,0xEA,0xC4,0x5E,0xEC,0x26,0x8B,0x07,0x2B,0x46,0xE8,0x89,0x46,0xF4,0xC4,0x5E, +0xEC,0x26,0x8B,0x07,0x89,0x46,0xE8,0xBA,0x50,0xFF,0xED,0x89,0x46,0xFE,0x9D,0x81, +0x7E,0xF8,0xE8,0x03,0x76,0x1C,0xFF,0x76,0xF8,0xFF,0x76,0xF6,0xE8,0x76,0x01,0x59, +0x59,0x89,0x46,0xF6,0xFF,0x76,0xF8,0xFF,0x76,0xF4,0xE8,0x68,0x01,0x59,0x59,0x89, +0x46,0xF4,0xBF,0x0E,0x00,0xEB,0x17,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6, +0x01,0x20,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x01,0x20,0x47,0x83,0xFF, +0x11,0x76,0xE4,0x8B,0xDE,0xD1,0xE3,0x8B,0x9F,0x59,0x02,0xC6,0x47,0x0D,0x30,0x8B, +0xDE,0xD1,0xE3,0x8B,0x9F,0x61,0x02,0xC6,0x47,0x0D,0x30,0x83,0x7E,0xF6,0x09,0x77, +0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF6,0x63,0x77,0x05,0xB8,0x0E,0x00,0xEB, +0x1B,0x81,0x7E,0xF6,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81,0x7E,0xF6, +0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8,0xEB,0x25, +0x8B,0x46,0xF6,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1, +0xE3,0x8B,0x9F,0x59,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF6,0x33,0xD2, +0xF7,0xF3,0x89,0x46,0xF6,0x83,0x7E,0xF6,0x00,0x75,0xD5,0x83,0x7E,0xF4,0x09,0x77, +0x05,0xB8,0x0D,0x00,0xEB,0x26,0x83,0x7E,0xF4,0x63,0x77,0x05,0xB8,0x0E,0x00,0xEB, +0x1B,0x81,0x7E,0xF4,0xE7,0x03,0x77,0x05,0xB8,0x0F,0x00,0xEB,0x0F,0x81,0x7E,0xF4, +0x0F,0x27,0x77,0x05,0xB8,0x10,0x00,0xEB,0x03,0xB8,0x11,0x00,0x8B,0xF8,0xEB,0x25, +0x8B,0x46,0xF4,0xBB,0x0A,0x00,0x33,0xD2,0xF7,0xF3,0x80,0xC2,0x30,0x8B,0xDE,0xD1, +0xE3,0x8B,0x9F,0x61,0x02,0x88,0x11,0x4F,0xBB,0x0A,0x00,0x8B,0x46,0xF4,0x33,0xD2, +0xF7,0xF3,0x89,0x46,0xF4,0x83,0x7E,0xF4,0x00,0x75,0xD5,0x8B,0xDE,0xD1,0xE3,0xFF, +0xB7,0x59,0x02,0xFF,0x76,0x04,0xE8,0x6E,0x00,0x59,0x59,0x8B,0xDE,0xD1,0xE3,0xFF, +0xB7,0x61,0x02,0xFF,0x76,0x04,0xE8,0x5E,0x00,0x59,0x59,0x6A,0x00,0xFF,0x76,0x04, +0xE8,0x31,0xF3,0x59,0x59,0x8B,0xD8,0x83,0xFB,0x04,0x77,0x1F,0xD1,0xE3,0x2E,0xFF, +0xA7,0x1B,0x70,0xEB,0x22,0xC7,0x46,0xE4,0x00,0x00,0xFF,0x4E,0xE6,0xEB,0x0C,0xC7, +0x46,0xE4,0x00,0x00,0xFF,0x46,0xE6,0xEB,0x02,0xEB,0x00,0x83,0x7E,0xE4,0x00,0x74, +0x03,0xE9,0x2A,0xFE,0xE9,0xD4,0xFC,0x5F,0x5E,0xC9,0xC3,0xF3,0x6F,0xF5,0x6F,0xFF, +0x6F,0xF3,0x6F,0x09,0x70,0x55,0x8B,0xEC,0x8B,0x46,0x04,0xB9,0xE8,0x03,0xF7,0xE1, +0x8B,0x4E,0x06,0xF7,0xF1,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76,0x06,0xEB,0x0E, +0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x33,0x00,0x59,0x59,0x80,0x3C, +0x00,0x75,0xED,0xEB,0x00,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x8B,0x76,0x06,0xEB, +0x14,0x8B,0xDE,0x46,0x8A,0x07,0x50,0xFF,0x76,0x04,0xE8,0x45,0x00,0x59,0x59,0x0B, +0xC0,0x74,0x02,0xEB,0x07,0x80,0x3C,0x00,0x75,0xE7,0xEB,0x00,0x5E,0x5D,0xC3,0xC8, +0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,0x9C,0xFA, +0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74,0x06,0x9D, +0xE8,0x91,0x9E,0xEB,0xE9,0xBA,0x00,0x00,0x8A,0x46,0x06,0xEE,0x9D,0xEB,0x00,0x5E, +0xC9,0xC3,0xC8,0x04,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46, +0xFE,0xE8,0xE6,0xA1,0x89,0x46,0xFC,0xE8,0xE0,0xA1,0x2B,0x46,0xFC,0x3D,0xB8,0x0B, +0x76,0x05,0xB8,0x01,0x00,0xEB,0x23,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE, +0xBA,0x02,0x00,0xEC,0xA8,0x02,0x74,0x06,0x9D,0xE8,0x48,0x9E,0xEB,0xD9,0xBA,0x00, +0x00,0x8A,0x46,0x06,0xEE,0x9D,0x33,0xC0,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,0x04,0x00, +0x00,0x56,0x57,0x8B,0x76,0x04,0x83,0x7E,0x06,0x00,0x74,0x07,0x56,0xE8,0x03,0x01, +0x59,0xEB,0x05,0x56,0xE8,0xA2,0x00,0x59,0x88,0x46,0xFF,0x80,0x7E,0xFF,0x08,0x77, +0x06,0x8A,0x46,0xFF,0xE9,0x84,0x00,0x80,0x7E,0xFF,0x0F,0x76,0x03,0xEB,0x79,0x90, +0x8A,0x46,0xFF,0xB4,0x00,0x2D,0x0A,0x00,0x8B,0xD8,0x83,0xFB,0x04,0x77,0x67,0xD1, +0xE3,0x2E,0xFF,0xA7,0xAF,0x71,0xB0,0x00,0xEB,0x61,0x56,0xE8,0x6B,0x00,0x59,0xB4, +0x00,0x25,0x0F,0x00,0x89,0x46,0xFC,0x56,0xE8,0x5E,0x00,0x59,0xB4,0x00,0x8B,0xF8, +0x56,0xE8,0x55,0x00,0x59,0xB4,0x00,0xC1,0xE0,0x08,0x8B,0xD7,0x03,0xD0,0x8B,0xFA, +0x8B,0x5E,0xFC,0xD1,0xE3,0x89,0x78,0x30,0xEB,0x2E,0x56,0xE8,0x3B,0x00,0x59,0x88, +0x44,0x5B,0xEB,0x24,0x56,0xE8,0x31,0x00,0x59,0x88,0x44,0x50,0x56,0xE8,0x29,0x00, +0x59,0x88,0x44,0x51,0x56,0xE8,0x21,0x00,0x59,0x88,0x44,0x52,0x56,0xE8,0x19,0x00, +0x59,0x88,0x44,0x53,0xEB,0x02,0xEB,0x00,0xE9,0x5B,0xFF,0x5F,0x5E,0xC9,0xC3,0x46, +0x71,0xA6,0x71,0x4A,0x71,0x7A,0x71,0x84,0x71,0xC8,0x04,0x00,0x00,0x56,0x8B,0x76, +0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00, +0xEE,0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0x57,0x9D,0xEB,0xE9,0xBA, +0x00,0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9,0xC3,0xC8, +0x02,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89,0x46,0xFE,0x9C,0xFA, +0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE,0xBA,0x02,0x00,0xEC,0x32,0xE4,0x24,0x01,0x9D, +0x5E,0xC9,0xC3,0xC8,0x06,0x00,0x00,0x56,0x8B,0x76,0x04,0x8A,0x44,0x5A,0x98,0x89, +0x46,0xFE,0xE8,0x85,0xA0,0x89,0x46,0xFA,0xE8,0x7F,0xA0,0x2B,0x46,0xFA,0x3D,0xB8, +0x0B,0x76,0x04,0xB0,0x08,0xEB,0x24,0x9C,0xFA,0x8A,0x46,0xFE,0xBA,0xFE,0x00,0xEE, +0xBA,0x02,0x00,0xEC,0xA8,0x01,0x75,0x06,0x9D,0xE8,0xE8,0x9C,0xEB,0xDA,0xBA,0x00, +0x00,0xEC,0x88,0x46,0xFD,0x9D,0x8A,0x46,0xFD,0xEB,0x00,0x5E,0xC9,0xC3,0x55,0x8B, +0xEC,0x56,0x8B,0x56,0x04,0x8A,0x46,0x06,0xEE,0x33,0xF6,0xEB,0x03,0x50,0x58,0x46, +0x83,0xFE,0x14,0x7C,0xF8,0x5E,0x5D,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x56,0x04, +0xEC,0x88,0x46,0xFF,0x33,0xF6,0xEB,0x03,0x50,0x58,0x46,0x83,0xFE,0x14,0x7C,0xF8, +0x8A,0x46,0xFF,0xEB,0x00,0x5E,0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x57,0x8B,0x76, +0x04,0x83,0x3E,0xB0,0x0B,0x00,0x75,0x1F,0xBA,0x88,0x01,0xB0,0x00,0xEE,0xBA,0x86, +0x01,0xB0,0x00,0xEE,0x6A,0x09,0x6A,0x00,0x68,0x30,0x01,0xE8,0x7D,0x01,0x83,0xC4, +0x06,0xC7,0x06,0xB0,0x0B,0x01,0x00,0x6A,0x09,0x8B,0xC6,0x05,0x80,0x01,0x50,0xE8, +0xDA,0x00,0x59,0x59,0x8B,0xF8,0x8B,0xC7,0xC1,0xE8,0x0C,0x25,0x0F,0x00,0x89,0x46, +0xFE,0x8B,0xC7,0xC1,0xE8,0x08,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,0xF2,0x0C,0x3B, +0xC2,0x75,0x21,0x8B,0xC7,0xC1,0xE8,0x04,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,0xF2, +0x06,0x3B,0xC2,0x75,0x0F,0x8B,0xC7,0x25,0x0F,0x00,0x8B,0x56,0xFE,0x83,0xF2,0x09, +0x3B,0xC2,0x74,0x0D,0x6A,0x07,0x56,0xE8,0x38,0x00,0x59,0x59,0xC7,0x46,0xFE,0x07, +0x00,0x8A,0x46,0xFE,0x04,0x80,0xA2,0x33,0x02,0x8B,0xC6,0xBA,0x62,0x00,0xF7,0xEA, +0x8A,0x56,0xFE,0x8B,0xD8,0x88,0x97,0x6C,0x00,0x68,0x32,0x02,0x8B,0xC6,0xBA,0x62, +0x00,0xF7,0xEA,0x05,0x14,0x00,0x50,0xE8,0x0E,0xFD,0x59,0x59,0xEB,0x00,0x5F,0x5E, +0xC9,0xC3,0xC8,0x02,0x00,0x00,0x56,0x8B,0x76,0x06,0x83,0xE6,0x0F,0x8B,0xC6,0xC1, +0xE0,0x0C,0x8B,0xD6,0x83,0xF2,0x0C,0xC1,0xE2,0x08,0x0B,0xC2,0x8B,0xD6,0x83,0xF2, +0x06,0xC1,0xE2,0x04,0x0B,0xC2,0x8B,0xD6,0x83,0xF2,0x09,0x0B,0xC2,0x89,0x46,0xFE, +0x6A,0x19,0x6A,0x10,0x8B,0x46,0x04,0x99,0x05,0x40,0x01,0x83,0xD2,0x00,0x52,0x50, +0xE8,0x6B,0x01,0x83,0xC4,0x06,0x0B,0x46,0xFE,0x83,0xCA,0x00,0x52,0x50,0xE8,0x9A, +0x00,0x83,0xC4,0x06,0xE8,0x25,0x01,0xEB,0x00,0x5E,0xC9,0xC3,0x55,0x8B,0xEC,0x56, +0x57,0x33,0xFF,0x6A,0x01,0x68,0x86,0x01,0xE8,0xA3,0xFE,0x59,0x59,0xB1,0x10,0x2A, +0x4E,0x06,0xD3,0x66,0x04,0x33,0xF6,0xEB,0x2E,0x81,0x7E,0x04,0x00,0x80,0x72,0x04, +0xB0,0x01,0xEB,0x02,0xB0,0x00,0x50,0x68,0x88,0x01,0xE8,0x81,0xFE,0x59,0x59,0x6A, +0x03,0x68,0x86,0x01,0xE8,0x77,0xFE,0x59,0x59,0x6A,0x01,0x68,0x86,0x01,0xE8,0x6D, +0xFE,0x59,0x59,0xD1,0x66,0x04,0x46,0x3B,0x76,0x06,0x7C,0xCD,0x33,0xF6,0xEB,0x24, +0xD1,0xE7,0x6A,0x03,0x68,0x86,0x01,0xE8,0x54,0xFE,0x59,0x59,0x6A,0x01,0x68,0x86, +0x01,0xE8,0x4A,0xFE,0x59,0x59,0x68,0x88,0x01,0xE8,0x5C,0xFE,0x59,0x98,0x25,0x01, +0x00,0x0B,0xF8,0x46,0x83,0xFE,0x10,0x7C,0xD7,0x6A,0x00,0x68,0x86,0x01,0xE8,0x2D, +0xFE,0x59,0x59,0x8B,0xC7,0xEB,0x00,0x5F,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,0x56,0x57, +0x8B,0x7E,0x08,0x6A,0x01,0x68,0x86,0x01,0xE8,0x13,0xFE,0x59,0x59,0xB8,0x20,0x00, +0x2B,0xC7,0x50,0xFF,0x76,0x06,0xFF,0x76,0x04,0xE8,0xA2,0x00,0x83,0xC4,0x06,0x89, +0x56,0x06,0x89,0x46,0x04,0x33,0xF6,0xEB,0x47,0x81,0x7E,0x06,0x00,0x80,0x72,0x0C, +0x75,0x06,0x83,0x7E,0x04,0x00,0x72,0x04,0xB0,0x01,0xEB,0x02,0xB0,0x00,0x50,0x68, +0x88,0x01,0xE8,0xD9,0xFD,0x59,0x59,0x6A,0x03,0x68,0x86,0x01,0xE8,0xCF,0xFD,0x59, +0x59,0x6A,0x01,0x68,0x86,0x01,0xE8,0xC5,0xFD,0x59,0x59,0x6A,0x01,0xFF,0x76,0x06, +0xFF,0x76,0x04,0xE8,0x58,0x00,0x83,0xC4,0x06,0x89,0x56,0x06,0x89,0x46,0x04,0x46, +0x3B,0xF7,0x7C,0xB5,0x6A,0x00,0x68,0x86,0x01,0xE8,0xA2,0xFD,0x59,0x59,0x6A,0x00, +0x68,0x86,0x01,0xE8,0x98,0xFD,0x59,0x59,0x5F,0x5E,0x5D,0xC3,0x55,0x8B,0xEC,0x56, +0x6A,0x01,0x68,0x86,0x01,0xE8,0x86,0xFD,0x59,0x59,0x33,0xF6,0xEB,0x00,0x68,0x88, +0x01,0xE8,0x94,0xFD,0x59,0xA8,0x01,0x75,0x08,0x8B,0xC6,0x46,0x3D,0x64,0x00,0x7C, +0xED,0x6A,0x00,0x68,0x86,0x01,0xE8,0x65,0xFD,0x59,0x59,0x5E,0x5D,0xC3,0xC8,0x04, +0x00,0x00,0x8B,0x46,0x04,0x8B,0x56,0x06,0x8B,0x4E,0x08,0xE3,0x06,0xD1,0xE0,0xD1, +0xD2,0xE2,0xFA,0x89,0x46,0xFC,0x89,0x56,0xFE,0x8B,0x56,0xFE,0x8B,0x46,0xFC,0xEB, +0x00,0xC9,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x50,0x72,0x65,0x76,0x69,0x6F,0x75,0x73,0x20,0x4D,0x65,0x6E,0x75,0x00,0x42,0x65, 0x67,0x69,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, @@ -2130,8 +2132,6 @@ 0x53,0x00,0x50,0x72,0x65,0x73,0x73,0x20,0x80,0x20,0x66,0x6F,0x72,0x20,0x6D,0x65, 0x6E,0x75,0x00,0x28,0x63,0x6F,0x75,0x6E,0x74,0x69,0x6E,0x67,0x2E,0x2E,0x2E,0x29, 0x00,0x00,0x65,0x4E,0x64,0x20,0x4F,0x66,0x20,0x43,0x6F,0x44,0x65,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/i2cmd.c linux/drivers/char/ip2/i2cmd.c --- v2.3.99-pre5/linux/drivers/char/ip2/i2cmd.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/ip2/i2cmd.c Mon Apr 24 13:39:35 2000 @@ -139,7 +139,7 @@ //static UCHAR ct86[]={ 2, BTH, 0x56,0 }; // RCV_ENABLE static UCHAR ct87[] = { 1, BYP, 0x57 }; // HW_TEST //static UCHAR ct88[]={ 3, BTH, 0x58,0,0 }; // RCV_THRESHOLD -//static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW +static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW //static UCHAR ct90[]={ 3, BYP, 0x5A,0,0 }; // Set SILO //static UCHAR ct91[]={ 2, BYP, 0x5B,0 }; // timed break diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/i2ellis.h linux/drivers/char/ip2/i2ellis.h --- v2.3.99-pre5/linux/drivers/char/ip2/i2ellis.h Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/ip2/i2ellis.h Tue Apr 25 17:52:01 2000 @@ -47,6 +47,7 @@ //---------------------- // Mandatory Includes: //---------------------- +#include #include "ip2types.h" #include "i2hw.h" // The hardware definitions @@ -399,6 +400,11 @@ spinlock_t read_fifo_spinlock; spinlock_t write_fifo_spinlock; +#ifdef CONFIG_DEVFS_FS + /* Device handles into devfs */ + devfs_handle_t devfs_ipl_handle; + devfs_handle_t devfs_stat_handle; +#endif } i2eBordStr, *i2eBordStrPtr; //------------------------------------------------------------------- diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/i2lib.c linux/drivers/char/ip2/i2lib.c --- v2.3.99-pre5/linux/drivers/char/ip2/i2lib.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/ip2/i2lib.c Mon Apr 24 13:39:35 2000 @@ -1086,7 +1086,7 @@ // Move the data if ( user ) { - rc=copy_from_user((char*)(DATA_OF(pInsert)), pSource, + COPY_FROM_USER(rc, (char*)(DATA_OF(pInsert)), pSource, amountToMove ); } else { memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove ); @@ -1516,8 +1516,8 @@ return; /* Bail out ASAP */ } // Channel is illegally big ? - if (channel >= pB->i2eChannelCnt || - (pCh = (((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])) == NULL) + if ((channel >= pB->i2eChannelCnt) || + (NULL==(pCh = ((i2ChanStrPtr*)pB->i2eChannelPtr)[channel]))) { iiReadBuf(pB, junkBuffer, count); WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); @@ -1541,7 +1541,8 @@ // Normal data! We crudely assume there is room for the data in our // buffer because the board wouldn't have exceeded his credit limit. - WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags);// We have 2 locks now + WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags); + // We have 2 locks now stuffIndex = pCh->Ibuf_stuff; amountToRead = IBUF_SIZE - stuffIndex; if (amountToRead > count) @@ -1552,6 +1553,7 @@ // one. iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead); + pCh->icount.rx += amountToRead; // Update the stuffIndex by the amount of data moved. Note we could // never ask for more data than would just fit. However, we might @@ -1576,6 +1578,7 @@ if (count > amountToRead) { amountToRead = count - amountToRead; iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead); + pCh->icount.rx += amountToRead; stuffIndex += amountToRead; } @@ -1632,7 +1635,7 @@ if ( !(pCh->dataSetIn & I2_CTS) ) { pCh->dataSetIn |= I2_DCTS; - ++pCh->icount.cts; + pCh->icount.cts++; dss_change = 1; } pCh->dataSetIn |= I2_CTS; @@ -1642,7 +1645,7 @@ if ( pCh->dataSetIn & I2_CTS ) { pCh->dataSetIn |= I2_DCTS; - ++pCh->icount.cts; + pCh->icount.cts++; dss_change = 1; } pCh->dataSetIn &= ~I2_CTS; @@ -1658,7 +1661,7 @@ ip2trace (CHANN, ITRC_MODEM, 2, 0 ); #endif pCh->dataSetIn |= I2_DDCD; - ++pCh->icount.dcd; + pCh->icount.dcd++; dss_change = 1; } pCh->dataSetIn |= I2_DCD; @@ -1677,7 +1680,7 @@ ip2trace (channel, ITRC_MODEM, 5, 0 ); #endif pCh->dataSetIn |= I2_DDCD; - ++pCh->icount.dcd; + pCh->icount.dcd++; dss_change = 1; } pCh->dataSetIn &= ~I2_DCD; @@ -1690,7 +1693,7 @@ if ( !(pCh->dataSetIn & I2_DSR) ) { pCh->dataSetIn |= I2_DDSR; - ++pCh->icount.dsr; + pCh->icount.dsr++; dss_change = 1; } pCh->dataSetIn |= I2_DSR; @@ -1700,7 +1703,7 @@ if ( pCh->dataSetIn & I2_DSR ) { pCh->dataSetIn |= I2_DDSR; - ++pCh->icount.dsr; + pCh->icount.dsr++; dss_change = 1; } pCh->dataSetIn &= ~I2_DSR; @@ -1710,23 +1713,26 @@ if ( !(pCh->dataSetIn & I2_RI) ) { pCh->dataSetIn |= I2_DRI; - ++pCh->icount.rng; + pCh->icount.rng++; dss_change = 1; } pCh->dataSetIn |= I2_RI ; break; case STAT_RI_DN: - if ( pCh->dataSetIn & I2_RI ) - { - pCh->dataSetIn |= I2_DRI; - dss_change = 1; - } + // to be compat with serial.c + //if ( pCh->dataSetIn & I2_RI ) + //{ + // pCh->dataSetIn |= I2_DRI; + // pCh->icount.rng++; + // dss_change = 1; + //} pCh->dataSetIn &= ~I2_RI ; break; case STAT_BRK_DET: pCh->dataSetIn |= I2_BRK; + pCh->icount.brk++; dss_change = 1; break; @@ -1791,9 +1797,6 @@ case STAT_BOXIDS: pB->channelBtypes = *((bidStatPtr)pc); pc += sizeof(bidStat); -//printk("boxids: %x %x %x %x\n", -// pB->channelBtypes.bid_value[0],pB->channelBtypes.bid_value[1], -// pB->channelBtypes.bid_value[2],pB->channelBtypes.bid_value[3]); set_baud_params(pB); break; @@ -1810,18 +1813,26 @@ switch (uc & STAT_MOD_ERROR) { case STAT_ERROR: - if (uc & STAT_E_PARITY) + if (uc & STAT_E_PARITY) { pCh->dataSetIn |= I2_PAR; - if (uc & STAT_E_FRAMING) + pCh->icount.parity++; + } + if (uc & STAT_E_FRAMING){ pCh->dataSetIn |= I2_FRA; - if (uc & STAT_E_OVERRUN) + pCh->icount.frame++; + } + if (uc & STAT_E_OVERRUN){ pCh->dataSetIn |= I2_OVR; + pCh->icount.overrun++; + } break; case STAT_MODEM: + // the answer to DSS_NOW request (not change) pCh->dataSetIn = (pCh->dataSetIn & ~(I2_RI | I2_CTS | I2_DCD | I2_DSR) ) | xlatDss[uc & 0xf]; + wake_up_interruptible ( &pCh->dss_now_wait ); default: break; } @@ -1846,16 +1857,6 @@ pc += 4; /* Skip the data */ break; - case STAT_CTS_UP: - case STAT_CTS_DN: - case STAT_DCD_UP: - case STAT_DCD_DN: - case STAT_DSR_UP: - case STAT_DSR_DN: - case STAT_RI_UP: - case STAT_RI_DN: - case STAT_BRK_DET: - case STAT_BMARK: default: break; } @@ -2102,6 +2103,7 @@ #endif /* DEBUG_FIFO */ pB->debugInlineCount++; + pCh->icount.tx += flowsize; // Update current credits pCh->outfl.room -= flowsize; pCh->outfl.asof += flowsize; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/i2lib.h linux/drivers/char/ip2/i2lib.h --- v2.3.99-pre5/linux/drivers/char/ip2/i2lib.h Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/ip2/i2lib.h Mon Apr 24 13:39:35 2000 @@ -67,8 +67,8 @@ // #define MAX_CBUF_BLOCK 6 // Maximum total length of a bypass command block -#define IBUF_SIZE 500 // character capacity of input buffer per channel -#define OBUF_SIZE 2048// character capacity of output buffer per channel +#define IBUF_SIZE 512 // character capacity of input buffer per channel +#define OBUF_SIZE 1024// character capacity of output buffer per channel #define CBUF_SIZE 10 // character capacity of output bypass buffer typedef struct _i2ChanStr @@ -97,6 +97,7 @@ PWAITQ open_wait; // Pointer for OS sleep function. PWAITQ close_wait; // Pointer for OS sleep function. PWAITQ delta_msr_wait;// Pointer for OS sleep function. + PWAITQ dss_now_wait; // Pointer for OS sleep function. struct timer_list BookmarkTimer; // Used by i2DrainOutput wait_queue_head_t pBookmarkWait; // Used by i2DrainOutput @@ -215,7 +216,6 @@ void (*trace)(unsigned short,unsigned char,unsigned char,unsigned long,...); -#ifdef __KERNEL__ /* * Kernel counters for the 4 input interrupts */ @@ -227,7 +227,6 @@ struct tq_struct tqueue_input; struct tq_struct tqueue_status; struct tq_struct tqueue_hangup; -#endif spinlock_t Ibuf_spinlock; spinlock_t Obuf_spinlock; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/ip2mkdev.c linux/drivers/char/ip2/ip2mkdev.c --- v2.3.99-pre5/linux/drivers/char/ip2/ip2mkdev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/ip2mkdev.c Mon Apr 24 13:39:35 2000 @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include + +#include "ip2.h" +#include "i2ellis.h" + +char nm[256]; +i2eBordStr Board[2]; + +static void ex_details(i2eBordStrPtr); + +int main (int argc, char *argv[]) +{ + int board, box, port; + int fd; + int dev; + i2eBordStrPtr pB = Board; + + // Remove all IP2 devices + + for ( board = 0; board < 4; ++board ) + { + sprintf ( nm, "/dev/ip2ipl%d", board ); + unlink ( nm ); + sprintf ( nm, "/dev/ip2stat%d", board ); + unlink ( nm ); + } + + for ( port = 0; port < 256; ++port ) + { + sprintf ( nm, "/dev/ttyF%d", port ); + unlink ( nm ); + sprintf ( nm, "/dev/cuf%d", port ); + unlink ( nm ); + } + + // Now create management devices, and use the status device to determine how + // port devices need to exist, and then create them. + + for ( board = 0; board < 4; ++board ) + { + printf("Board %d: ", board ); + + sprintf ( nm, "/dev/ip2ipl%d", board ); + mknod ( nm, S_IFCHR|0666, (IP2_IPL_MAJOR << 8) | board * 4 ); + sprintf ( nm, "/dev/ip2stat%d", board ); + mknod ( nm, S_IFCHR|0666, (IP2_IPL_MAJOR << 8) | board * 4 + 1 ); + + fd = open ( nm, O_RDONLY ); + if ( !fd ) + { + printf ( "Unable to open status device %s\n", nm ); + exit ( 1 ); + } + if ( ioctl ( fd, 65, Board ) < 0 ) + { + printf ( "not present\n" ); + close ( fd ); + unlink ( nm ); + sprintf ( nm, "/dev/ip2ipl%d", board ); + unlink ( nm ); + } + else + { + switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) + { + case POR_ID_FIIEX: ex_details ( pB ); break; + case POR_ID_II_4: printf ( "ISA-4" ); break; + case POR_ID_II_8: printf ( "ISA-8 std" ); break; + case POR_ID_II_8R: printf ( "ISA-8 RJ11" ); break; + + default: + printf ( "Unknown board type, ID = %x", pB->i2ePom.e.porID ); + } + + for ( box = 0; box < ABS_MAX_BOXES; ++box ) + { + for ( port = 0; port < ABS_BIGGEST_BOX; ++port ) + { + if ( pB->i2eChannelMap[box] & ( 1 << port ) ) + { + dev = port + + box * ABS_BIGGEST_BOX + + board * ABS_BIGGEST_BOX * ABS_MAX_BOXES; + + sprintf ( nm, "/dev/ttyF%d", dev ); + mknod ( nm, S_IFCHR|0666, (IP2_TTY_MAJOR << 8) | dev ); + sprintf ( nm, "/dev/cuf%d", dev ); + mknod ( nm, S_IFCHR|0666, (IP2_CALLOUT_MAJOR << 8) | dev ); + + printf("."); + } + } + } + printf("\n"); + } + } +} + +static void ex_details ( i2eBordStrPtr pB ) +{ + int box; + int i; + int ports = 0; + int boxes = 0; + + for( box = 0; box < ABS_MAX_BOXES; ++box ) + { + if( pB->i2eChannelMap[box] != 0 ) ++boxes; + for( i = 0; i < ABS_BIGGEST_BOX; ++i ) + { + if( pB->i2eChannelMap[box] & 1<< i ) ++ports; + } + } + + printf("EX bx=%d pt=%d %d bit", boxes, ports, pB->i2eDataWidth16 ? 16 : 8 ); +} + + diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/ip2stat.c linux/drivers/char/ip2/ip2stat.c --- v2.3.99-pre5/linux/drivers/char/ip2/ip2stat.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/ip2stat.c Mon Apr 24 13:39:35 2000 @@ -0,0 +1,115 @@ +/******************************************************************************* +* +* (c) 1998 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Status display utility +* +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2ellis.h" +#include "i2lib.h" + +i2eBordStr Board[2]; +i2ChanStr Port[2]; + +struct driver_stats +{ + ULONG ref_count; + ULONG irq_counter; + ULONG bh_counter; +} Driver; + +char devname[20]; + +int main (int argc, char *argv[]) +{ + int fd; + int dev, i; + i2eBordStrPtr pB = Board; + i2ChanStrPtr pCh = Port; + + if ( argc != 2 ) + { + printf ( "Usage: %s \n", argv[0] ); + exit(1); + } + i = sscanf ( argv[1], "/dev/ttyF%d", &dev ); + + if ( i != 1 ) exit(1); + + //printf("%s: board %d, port %d\n", argv[1], dev / 64, dev % 64 ); + + sprintf ( devname, "/dev/ip2stat%d", dev / 64 ); + if( 0 > ( fd = open ( devname, O_RDONLY ) ) ) { + // Conventional name failed - try devfs name + sprintf ( devname, "/dev/ip2/stat%d", dev / 64 ); + if( 0 > ( fd = open ( devname, O_RDONLY ) ) ) { + // Where is our board??? + printf( "Unable to open board %d to retrieve stats\n", + dev / 64 ); + exit( 255 ); + } + } + + ioctl ( fd, 64, &Driver ); + ioctl ( fd, 65, Board ); + ioctl ( fd, dev % 64, Port ); + + printf ( "Driver statistics:-\n" ); + printf ( " Reference Count: %d\n", Driver.ref_count ); + printf ( " Interrupts to date: %ld\n", Driver.irq_counter ); + printf ( " Bottom half to date: %ld\n", Driver.bh_counter ); + + printf ( "Board statistics(%d):-\n",dev/64 ); + printf ( "FIFO: remains = %d%s\n", pB->i2eFifoRemains, + pB->i2eWaitingForEmptyFifo ? ", busy" : "" ); + printf ( "Mail: out mail = %02x\n", pB->i2eOutMailWaiting ); + printf ( " Input interrupts : %d\n", pB->i2eFifoInInts ); + printf ( " Output interrupts: %d\n", pB->i2eFifoOutInts ); + printf ( " Flow queued : %ld\n", pB->debugFlowQueued ); + printf ( " Bypass queued : %ld\n", pB->debugBypassQueued ); + printf ( " Inline queued : %ld\n", pB->debugInlineQueued ); + printf ( " Data queued : %ld\n", pB->debugDataQueued ); + printf ( " Flow packets : %ld\n", pB->debugFlowCount ); + printf ( " Bypass packets : %ld\n", pB->debugBypassCount ); + printf ( " Inline packets : %ld\n", pB->debugInlineCount ); + printf ( " Mail status : %x\n", pB->i2eStatus ); + printf ( " Output mail : %x\n", pB->i2eOutMailWaiting ); + printf ( " Fatal flag : %d\n", pB->i2eFatal ); + + printf ( "Channel statistics(%s:%d):-\n",argv[1],dev%64 ); + printf ( "ibuf: stuff = %d strip = %d\n", pCh->Ibuf_stuff, pCh->Ibuf_strip ); + printf ( "obuf: stuff = %d strip = %d\n", pCh->Obuf_stuff, pCh->Obuf_strip ); + printf ( "pbuf: stuff = %d\n", pCh->Pbuf_stuff ); + printf ( "cbuf: stuff = %d strip = %d\n", pCh->Cbuf_stuff, pCh->Cbuf_strip ); + printf ( "infl: count = %d room = %d\n", pCh->infl.asof, pCh->infl.room ); + printf ( "outfl: count = %d room = %d\n", pCh->outfl.asof, pCh->outfl.room ); + printf ( "throttled = %d ",pCh->throttled); + printf ( "bookmarks = %d ",pCh->bookMarks); + printf ( "flush_flags = %x\n",pCh->flush_flags); + printf ( "needs: "); + if (pCh->channelNeeds & NEED_FLOW) printf("FLOW "); + if (pCh->channelNeeds & NEED_INLINE) printf("INLINE "); + if (pCh->channelNeeds & NEED_BYPASS) printf("BYPASS "); + if (pCh->channelNeeds & NEED_CREDIT) printf("CREDIT "); + printf ( "\n"); + printf ( "dss: in = %x, out = %x\n",pCh->dataSetIn,pCh->dataSetOut); + +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/ip2trace.c linux/drivers/char/ip2/ip2trace.c --- v2.3.99-pre5/linux/drivers/char/ip2/ip2trace.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ip2/ip2trace.c Mon Apr 24 13:39:35 2000 @@ -0,0 +1,279 @@ +/******************************************************************************* +* +* (c) 1998 by Computone Corporation +* +******************************************************************************** +* +* +* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport +* serial I/O controllers. +* +* DESCRIPTION: Interpretive trace dump utility +* +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ip2trace.h" + +unsigned long namebuf[100]; + +struct { + int wrap, + size, + o_strip, + o_stuff, + strip, + stuff; + unsigned long buf[1000]; +} tbuf; + +struct sigaction act; + +typedef enum { kChar, kInt, kAddr, kHex } eFormat; + +int active = 1; +void quit() { active = 0; } + +int main (int argc, char *argv[]) +{ + int fd = open ( "/dev/ip2trace", O_RDONLY ); + int cnt, i; + unsigned long ts, td; + struct timeval timeout; + union ip2breadcrumb bc; + eFormat fmt = kHex; + + if ( fd < 0 ) + { + printf ( "Can't open device /dev/ip2trace\n" ); + exit ( 1 ); + } + + act.sa_handler = quit; + /*act.sa_mask = 0;*/ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + act.sa_restorer = NULL; + + sigaction ( SIGTERM, &act, NULL ); + + ioctl ( fd, 1, namebuf ); + + printf ( "iiSendPendingMail %p\n", namebuf[0] ); + printf ( "i2InitChannels %p\n", namebuf[1] ); + printf ( "i2QueueNeeds %p\n", namebuf[2] ); + printf ( "i2QueueCommands %p\n", namebuf[3] ); + printf ( "i2GetStatus %p\n", namebuf[4] ); + printf ( "i2Input %p\n", namebuf[5] ); + printf ( "i2InputFlush %p\n", namebuf[6] ); + printf ( "i2Output %p\n", namebuf[7] ); + printf ( "i2FlushOutput %p\n", namebuf[8] ); + printf ( "i2DrainWakeup %p\n", namebuf[9] ); + printf ( "i2DrainOutput %p\n", namebuf[10] ); + printf ( "i2OutputFree %p\n", namebuf[11] ); + printf ( "i2StripFifo %p\n", namebuf[12] ); + printf ( "i2StuffFifoBypass %p\n", namebuf[13] ); + printf ( "i2StuffFifoFlow %p\n", namebuf[14] ); + printf ( "i2StuffFifoInline %p\n", namebuf[15] ); + printf ( "i2ServiceBoard %p\n", namebuf[16] ); + printf ( "serviceOutgoingFifo %p\n", namebuf[17] ); + printf ( "ip2_init %p\n", namebuf[18] ); + printf ( "ip2_init_board %p\n", namebuf[19] ); + printf ( "find_eisa_board %p\n", namebuf[20] ); + printf ( "set_irq %p\n", namebuf[21] ); + printf ( "ex_details %p\n", namebuf[22] ); + printf ( "ip2_interrupt %p\n", namebuf[23] ); + printf ( "ip2_poll %p\n", namebuf[24] ); + printf ( "service_all_boards %p\n", namebuf[25] ); + printf ( "do_input %p\n", namebuf[27] ); + printf ( "do_status %p\n", namebuf[26] ); + printf ( "open_sanity_check %p\n", namebuf[27] ); + printf ( "open_block_til_ready %p\n", namebuf[28] ); + printf ( "ip2_open %p\n", namebuf[29] ); + printf ( "ip2_close %p\n", namebuf[30] ); + printf ( "ip2_hangup %p\n", namebuf[31] ); + printf ( "ip2_write %p\n", namebuf[32] ); + printf ( "ip2_putchar %p\n", namebuf[33] ); + printf ( "ip2_flush_chars %p\n", namebuf[34] ); + printf ( "ip2_write_room %p\n", namebuf[35] ); + printf ( "ip2_chars_in_buf %p\n", namebuf[36] ); + printf ( "ip2_flush_buffer %p\n", namebuf[37] ); + //printf ( "ip2_wait_until_sent %p\n", namebuf[38] ); + printf ( "ip2_throttle %p\n", namebuf[39] ); + printf ( "ip2_unthrottle %p\n", namebuf[40] ); + printf ( "ip2_ioctl %p\n", namebuf[41] ); + printf ( "get_modem_info %p\n", namebuf[42] ); + printf ( "set_modem_info %p\n", namebuf[43] ); + printf ( "get_serial_info %p\n", namebuf[44] ); + printf ( "set_serial_info %p\n", namebuf[45] ); + printf ( "ip2_set_termios %p\n", namebuf[46] ); + printf ( "ip2_set_line_discipline %p\n", namebuf[47] ); + printf ( "set_line_characteristics %p\n", namebuf[48] ); + + printf("\n-------------------------\n"); + printf("Start of trace\n"); + + while ( active ) { + cnt = read ( fd, &tbuf, sizeof tbuf ); + + if ( cnt ) { + if ( tbuf.wrap ) { + printf ( "\nTrace buffer: wrap=%d, strip=%d, stuff=%d\n", + tbuf.wrap, tbuf.strip, tbuf.stuff ); + } + for ( i = 0, bc.value = 0; i < cnt; ++i ) { + if ( !bc.hdr.codes ) { + td = tbuf.buf[i] - ts; + ts = tbuf.buf[i++]; + bc.value = tbuf.buf[i]; + + printf ( "\n(%d) Port %3d ", ts, bc.hdr.port ); + + fmt = kHex; + + switch ( bc.hdr.cat ) + { + case ITRC_INIT: + printf ( "Init %d: ", bc.hdr.label ); + break; + + case ITRC_OPEN: + printf ( "Open %d: ", bc.hdr.label ); + break; + + case ITRC_CLOSE: + printf ( "Close %d: ", bc.hdr.label ); + break; + + case ITRC_DRAIN: + printf ( "Drain %d: ", bc.hdr.label ); + fmt = kInt; + break; + + case ITRC_IOCTL: + printf ( "Ioctl %d: ", bc.hdr.label ); + break; + + case ITRC_FLUSH: + printf ( "Flush %d: ", bc.hdr.label ); + break; + + case ITRC_STATUS: + printf ( "GetS %d: ", bc.hdr.label ); + break; + + case ITRC_HANGUP: + printf ( "Hangup %d: ", bc.hdr.label ); + break; + + case ITRC_INTR: + printf ( "*Intr %d: ", bc.hdr.label ); + break; + + case ITRC_SFLOW: + printf ( "SFlow %d: ", bc.hdr.label ); + fmt = kInt; + break; + + case ITRC_SBCMD: + printf ( "Bypass CMD %d: ", bc.hdr.label ); + fmt = kInt; + break; + + case ITRC_SICMD: + printf ( "Inline CMD %d: ", bc.hdr.label ); + fmt = kInt; + break; + + case ITRC_MODEM: + printf ( "Modem %d: ", bc.hdr.label ); + break; + + case ITRC_INPUT: + printf ( "Input %d: ", bc.hdr.label ); + break; + + case ITRC_OUTPUT: + printf ( "Output %d: ", bc.hdr.label ); + fmt = kInt; + break; + + case ITRC_PUTC: + printf ( "Put char %d: ", bc.hdr.label ); + fmt = kChar; + break; + + case ITRC_QUEUE: + printf ( "Queue CMD %d: ", bc.hdr.label ); + fmt = kInt; + break; + + case ITRC_STFLW: + printf ( "Stat Flow %d: ", bc.hdr.label ); + fmt = kInt; + break; + + case ITRC_SFIFO: + printf ( "SFifo %d: ", bc.hdr.label ); + break; + + case ITRC_VERIFY: + printf ( "Verfy %d: ", bc.hdr.label ); + fmt = kHex; + break; + + case ITRC_WRITE: + printf ( "Write %d: ", bc.hdr.label ); + fmt = kChar; + break; + + case ITRC_ERROR: + printf ( "ERROR %d: ", bc.hdr.label ); + fmt = kInt; + break; + + default: + printf ( "%08x ", tbuf.buf[i] ); + break; + } + } + else + { + --bc.hdr.codes; + switch ( fmt ) + { + case kChar: + printf ( "%c (0x%02x) ", + isprint ( tbuf.buf[i] ) ? tbuf.buf[i] : '.', tbuf.buf[i] ); + break; + case kInt: + printf ( "%d ", tbuf.buf[i] ); + break; + + case kAddr: + case kHex: + printf ( "0x%x ", tbuf.buf[i] ); + break; + } + } + } + } + fflush ( stdout ); + timeout.tv_sec = 0; + timeout.tv_usec = 250; + select ( 0, NULL, NULL, NULL, &timeout ); + + } + printf("\n-------------------------\n"); + printf("End of trace\n"); + + close ( fd ); +} + diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2/ip2trace.h linux/drivers/char/ip2/ip2trace.h --- v2.3.99-pre5/linux/drivers/char/ip2/ip2trace.h Thu Aug 26 13:05:35 1999 +++ linux/drivers/char/ip2/ip2trace.h Mon Apr 24 13:39:35 2000 @@ -9,7 +9,6 @@ }; #define ITRC_NO_PORT 0xFF -#define PORTN (port->port_index) #define CHANN (pCh->port_index) #define ITRC_ERROR '!' diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2.c linux/drivers/char/ip2.c --- v2.3.99-pre5/linux/drivers/char/ip2.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/ip2.c Tue Apr 25 17:52:01 2000 @@ -6,11 +6,22 @@ // __initdata should work as advertized // +#include #include #include #include #include +#ifndef __init +#define __init +#endif +#ifndef __initfunc +#define __initfunc(a) a +#endif +#ifndef __initdata +#define __initdata +#endif + #include "./ip2/ip2types.h" #include "./ip2/fip_firm.h" // the meat @@ -18,15 +29,24 @@ ip2_loadmain(int *, int *, unsigned char *, int ); // ref into ip2main.c #ifdef MODULE +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +# define MODVERSIONS +#endif +#ifdef MODVERSIONS +# include +#endif + static int io[IP2_MAX_BOARDS]= { 0,}; static int irq[IP2_MAX_BOARDS] = { 0,}; -MODULE_AUTHOR("Doug McNash"); -MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); -MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i"); -MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards"); -MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i"); -MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards"); +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + MODULE_AUTHOR("Doug McNash"); + MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); + MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i"); + MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards"); + MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i"); + MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards"); +# endif /* LINUX_VERSION */ //====================================================================== diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ip2main.c linux/drivers/char/ip2main.c --- v2.3.99-pre5/linux/drivers/char/ip2main.c Thu Feb 10 17:11:08 2000 +++ linux/drivers/char/ip2main.c Tue Apr 25 17:52:01 2000 @@ -10,21 +10,67 @@ * DESCRIPTION: Mainline code for the device driver * *******************************************************************************/ +// ToDo: +// +// Done: +// +// 1.2.9 +// Four box EX was barfing on >128k kmalloc, made structure smaller by +// reducing output buffer size +// +// 1.2.8 +// Device file system support (MHW) +// +// 1.2.7 +// Fixed +// Reload of ip2 without unloading ip2main hangs system on cat of /proc/modules +// +// 1.2.6 +//Fixes DCD problems +// DCD was not reported when CLOCAL was set on call to TIOCMGET +// +//Enhancements: +// TIOCMGET requests and waits for status return +// No DSS interrupts enabled except for DCD when needed +// +// For internal use only +// +//#define IP2DEBUG_INIT +//#define IP2DEBUG_OPEN +//#define IP2DEBUG_WRITE +//#define IP2DEBUG_READ +//#define IP2DEBUG_IOCTL +//#define IP2DEBUG_IPL + +//#define IP2DEBUG_TRACE +//#define DEBUG_FIFO + /************/ /* Includes */ /************/ - #include -#include +// Uncomment the following if you want it compiled with modversions +#ifdef MODULE +# if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +# define MODVERSIONS +# endif +# ifdef MODVERSIONS +# include +# endif +#endif + #include #include #include #include #include - +#include #include #include +#ifdef CONFIG_DEVFS_FS +#include +#endif #include #include #include @@ -50,13 +96,84 @@ #include #include -#include -#include -#include - -#include -#define pcibios_strerror(status) \ - printk( KERN_ERR "IP2: PCI error 0x%x \n", status ); +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) +# include +# include +# include +#else +# include +#endif + +// These VERSION switches maybe inexact because I simply don't know +// when the various features appeared in the 2.1.XX kernels. +// They are good enough for 2.0 vs 2.2 and if you are fooling with +// the 2.1.XX stuff then it would be trivial for you to fix. +// Most of these macros were stolen from some other drivers +// so blame them. + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,4) +# include +# define GET_USER(error,value,addr) error = get_user(value,addr) +# define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 +# define PUT_USER(error,value,addr) error = put_user(value,addr) +# define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 + +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,5) +# include +# define pcibios_strerror(status) \ + printk( KERN_ERR "IP2: PCI error 0x%x \n", status ); +# endif + +#else /* 2.0.x and 2.1.x before 2.1.4 */ + +# define proc_register_dynamic(a,b) proc_register(a,b) + +# define GET_USER(error,value,addr) \ + do { \ + error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \ + if (error == 0) \ + value = get_user(addr); \ + } while (0) + +# define COPY_FROM_USER(error,dest,src,size) \ + do { \ + error = verify_area (VERIFY_READ, (void *) src, size); \ + if (error == 0) \ + memcpy_fromfs (dest, src, size); \ + } while (0) + +# define PUT_USER(error,value,addr) \ + do { \ + error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \ + if (error == 0) \ + put_user (value, addr); \ + } while (0) + +# define COPY_TO_USER(error,dest,src,size) \ + do { \ + error = verify_area (VERIFY_WRITE, (void *) dest, size); \ + if (error == 0) \ + memcpy_tofs (dest, src, size); \ + } while (0) + +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +#define __init +#define __initfunc(a) a +#define __initdata +#define ioremap(a,b) vremap((a),(b)) +#define iounmap(a) vfree((a)) +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();} +#define signal_pending(a) ((a)->signal & ~(a)->blocked) +#define in_interrupt() intr_count +#endif #include "./ip2/ip2types.h" #include "./ip2/ip2trace.h" @@ -84,12 +201,17 @@ /* String constants to identify ourselves */ static char *pcName = "Computone IntelliPort Plus multiport driver"; -static char *pcVersion = "1.2.4"; +static char *pcVersion = "1.2.9"; /* String constants for port names */ static char *pcDriver_name = "ip2"; -static char *pcTty = "ttyf"; +#ifdef CONFIG_DEVFS_FS +static char *pcTty = "ttf/%d"; +static char *pcCallout = "cuf/%d"; +#else +static char *pcTty = "ttyF"; static char *pcCallout = "cuf"; +#endif static char *pcIpl = "ip2ipl"; /* Serial subtype definitions */ @@ -141,12 +263,15 @@ static void ip2_wait_until_sent(PTTY,int); static void set_params (i2ChanStrPtr, struct termios *); -static int get_modem_info(i2ChanStrPtr, unsigned int *); static int set_modem_info(i2ChanStrPtr, unsigned int, unsigned int *); static int get_serial_info(i2ChanStrPtr, struct serial_struct *); static int set_serial_info(i2ChanStrPtr, struct serial_struct *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +static int ip2_ipl_read(struct inode *, char *, size_t , loff_t *); +#else static ssize_t ip2_ipl_read(struct file *, char *, size_t, loff_t *) ; +#endif static ssize_t ip2_ipl_write(struct file *, const char *, size_t, loff_t *); static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG); static int ip2_ipl_open(struct inode *, struct file *); @@ -241,13 +366,14 @@ /* Configuration area for modprobe */ #ifdef MODULE -MODULE_AUTHOR("Doug McNash"); -MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + MODULE_AUTHOR("Doug McNash"); + MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); +# endif /* LINUX_VERSION */ #endif /* MODULE */ static int poll_only = 0; -static int Pci_index = 0; static int Eisa_irq = 0; static int Eisa_slot = 0; @@ -371,8 +497,6 @@ #ifdef IP2DEBUG_INIT printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion ); #endif - - /* Stop poll timer if we had one. */ if ( TimerOn ) { del_timer ( &PollTimer ); @@ -382,7 +506,7 @@ /* Reset the boards we have. */ for( i = 0; i < IP2_MAX_BOARDS; ++i ) { if ( i2BoardPtrTable[i] ) { - iiReset ( i2BoardPtrTable[i] ); + iiReset( i2BoardPtrTable[i] ); } } @@ -392,6 +516,10 @@ iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); +#ifdef CONFIG_DEVFS_FS + devfs_unregister (i2BoardPtrTable[i]->devfs_ipl_handle); + devfs_unregister (i2BoardPtrTable[i]->devfs_stat_handle); +#endif } /* Disable and remove interrupt handler. */ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { @@ -405,7 +533,12 @@ if ( ( err = tty_unregister_driver ( &ip2_callout_driver ) ) ) { printk(KERN_ERR "IP2: failed to unregister callout driver (%d)\n", err); } - if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) { +#ifdef CONFIG_DEVFS_FS + if ( ( err = devfs_unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) +#else + if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) +#endif + { printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err); } remove_proc_entry("ip2mem", &proc_root); @@ -450,9 +583,14 @@ int __init old_ip2_init(void) { +#ifdef CONFIG_DEVFS_FS + static devfs_handle_t devfs_handle = NULL; + int j, box; +#endif int i; int err; int status = 0; + static int loaded = 0; i2eBordStrPtr pB = NULL; int rc = -1; @@ -463,6 +601,15 @@ /* Announce our presence */ printk( KERN_INFO "%s version %s\n", pcName, pcVersion ); + // ip2 can be unloaded and reloaded for no good reason + // we can't let that happen here or bad things happen + // second load hoses board but not system - fixme later + if (loaded) { + printk( KERN_INFO "Still loaded\n" ); + return 0; + } + loaded++; + /* if all irq config is zero we shall poll_only */ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { poll_only |= ip2config.irq[i]; @@ -502,11 +649,14 @@ break; case PCI: #ifdef CONFIG_PCI - if (pci_present()) { - struct pci_dev *pci_dev_i = NULL; - pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE, - PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i); - if (pci_dev_i != NULL) { +#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */ + if (pcibios_present()) { + unsigned char pci_bus, pci_devfn; + int Pci_index = 0; + status = pcibios_find_device(PCI_VENDOR_ID_COMPUTONE, + PCI_DEVICE_ID_COMPUTONE_IP2EX, Pci_index, + &pci_bus, &pci_devfn); + if (status == 0) { unsigned int addr; unsigned char pci_irq; @@ -517,6 +667,41 @@ * one. */ ++Pci_index; + + pcibios_read_config_dword(pci_bus, pci_devfn, + PCI_BASE_ADDRESS_1, &addr); + if ( addr & 1 ) { + ip2config.addr[i]=(USHORT)(addr&0xfffe); + } else { + printk( KERN_ERR "IP2: PCI I/O address error\n"); + } + pcibios_read_config_byte(pci_bus, pci_devfn, + PCI_INTERRUPT_LINE, &pci_irq); + + if (!is_valid_irq(pci_irq)) { + printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq); + pci_irq = 0; + } + ip2config.irq[i] = pci_irq; + } else { // ann error + ip2config.addr[i] = 0; + if (status == PCIBIOS_DEVICE_NOT_FOUND) { + printk( KERN_ERR "IP2: PCI board %d not found\n", i ); + } else { + pcibios_strerror(status); + } + } + } +#else /* LINUX_VERSION_CODE > 2.1.99 */ + if (pci_present()) { + struct pci_dev *pci_dev_i = NULL; + pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE, + PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i); + if (pci_dev_i != NULL) { + unsigned int addr; + unsigned char pci_irq; + + ip2config.type[i] = PCI; status = pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr); if ( addr & 1 ) { @@ -541,6 +726,7 @@ } } } +#endif /* ! 2_0_X */ #else printk( KERN_ERR "IP2: PCI card specified but PCI support not\n"); printk( KERN_ERR "IP2: configured in this kernel.\n"); @@ -591,8 +777,10 @@ /* Initialise the relevant fields. */ ip2_tty_driver.magic = TTY_DRIVER_MAGIC; ip2_tty_driver.name = pcTty; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) ip2_tty_driver.driver_name = pcDriver_name; ip2_tty_driver.read_proc = ip2_read_proc; +#endif ip2_tty_driver.major = IP2_TTY_MAJOR; ip2_tty_driver.minor_start = 0; ip2_tty_driver.num = IP2_MAX_PORTS; @@ -600,7 +788,11 @@ ip2_tty_driver.subtype = SERIAL_TYPE_NORMAL; ip2_tty_driver.init_termios = tty_std_termios; ip2_tty_driver.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; +#ifdef CONFIG_DEVFS_FS + ip2_tty_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; +#else ip2_tty_driver.flags = TTY_DRIVER_REAL_RAW; +#endif ip2_tty_driver.refcount = &ref_count; ip2_tty_driver.table = TtyTable; ip2_tty_driver.termios = Termios; @@ -629,8 +821,10 @@ */ ip2_callout_driver = ip2_tty_driver; ip2_callout_driver.name = pcCallout; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) ip2_callout_driver.driver_name = pcDriver_name; ip2_callout_driver.read_proc = NULL; +#endif ip2_callout_driver.major = IP2_CALLOUT_MAJOR; ip2_callout_driver.subtype = SERIAL_TYPE_CALLOUT; @@ -646,7 +840,12 @@ printk(KERN_ERR "IP2: failed to register callout driver (%d)\n", err); } else /* Register the IPL driver. */ - if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) { +#ifdef CONFIG_DEVFS_FS + if (( err = devfs_register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ))) +#else + if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) +#endif + { printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err ); } else /* Register the read_procmem thing */ @@ -660,10 +859,54 @@ /* Register the interrupt handler or poll handler, depending upon the * specified interrupt. */ +#ifdef CONFIG_DEVFS_FS + if (!devfs_handle) + devfs_handle = devfs_mk_dir (NULL, "ip2", 3, NULL); +#endif + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { +#ifdef CONFIG_DEVFS_FS + char name[16]; +#endif + if ( 0 == ip2config.addr[i] ) { continue; } + +#ifdef CONFIG_DEVFS_FS + sprintf( name, "ipl%d", i ); + i2BoardPtrTable[i]->devfs_ipl_handle = + devfs_register (devfs_handle, name, 0, + DEVFS_FL_NONE, + IP2_IPL_MAJOR, 4 * i, + S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, + 0, 0, &ip2_ipl, NULL); + + sprintf( name, "stat%d", i ); + i2BoardPtrTable[i]->devfs_stat_handle = + devfs_register (devfs_handle, name, 0, + DEVFS_FL_NONE, + IP2_IPL_MAJOR, 4 * i + 1, + S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, + 0, 0, &ip2_ipl, NULL); + + for ( box = 0; box < ABS_MAX_BOXES; ++box ) + { + for ( j = 0; j < ABS_BIGGEST_BOX; ++j ) + { + if ( pB->i2eChannelMap[box] & (1 << j) ) + { + tty_register_devfs(&ip2_tty_driver, + 0, j + ABS_BIGGEST_BOX * + (box+i*ABS_MAX_BOXES)); + tty_register_devfs(&ip2_callout_driver, + 0, j + ABS_BIGGEST_BOX * + (box+i*ABS_MAX_BOXES)); + } + } + } +#endif + if (poll_only) { ip2config.irq[i] = CIR_POLL; } @@ -932,7 +1175,6 @@ static void set_irq( int boardnum, int boardIrq ) { - i2ChanStrPtr pCh; unsigned char tempCommand[16]; i2eBordStrPtr pB = i2BoardPtrTable[boardnum]; unsigned long flags; @@ -946,8 +1188,6 @@ * is done. If polling we must send 0 as the interrupt parameter. */ - pCh = (i2ChanStrPtr) pB->i2eChannelPtr; - // We will get an interrupt here at the end of this function iiDisableMailIrq(pB); @@ -1129,7 +1369,7 @@ unsigned long flags; #ifdef IP2DEBUG_TRACE - ip2trace(PORTN, ITRC_INPUT, 21, 0 ); + ip2trace(CHANN, ITRC_INPUT, 21, 0 ); #endif // Data input if ( pCh->pTTY != NULL ) { @@ -1141,7 +1381,7 @@ READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags) } else { #ifdef IP2DEBUG_TRACE - ip2trace(PORTN, ITRC_INPUT, 22, 0 ); + ip2trace(CHANN, ITRC_INPUT, 22, 0 ); #endif i2InputFlush( pCh ); } @@ -1168,7 +1408,7 @@ status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) ); #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_STATUS, 21, 1, status ); + ip2trace (CHANN, ITRC_STATUS, 21, 1, status ); #endif if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) { @@ -1230,7 +1470,7 @@ } #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_STATUS, 26, 0 ); + ip2trace (CHANN, ITRC_STATUS, 26, 0 ); #endif } @@ -1305,11 +1545,8 @@ open_sanity_check ( pCh, pCh->pMyBord ); #endif - i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP); + i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, CMD_DTRUP,CMD_RTSUP,CMD_DCD_REP); pCh->dataSetOut |= (I2_DTR | I2_RTS); - i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP); - i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, - CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP); serviceOutgoingFifo( pCh->pMyBord ); /* Block here until the port is ready (per serial and istallion) */ @@ -1401,7 +1638,7 @@ printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n"); #endif #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE), + ip2trace (CHANN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE), (pCh->flags & ASYNC_CLOSING) ); #endif /* check for signal */ @@ -1413,7 +1650,7 @@ } --pCh->wopen; //why count? #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_OPEN, 4, 0 ); + ip2trace (CHANN, ITRC_OPEN, 4, 0 ); #endif if (rc != 0 ) { return rc; @@ -1452,7 +1689,7 @@ serviceOutgoingFifo( pCh->pMyBord ); #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_OPEN, ITRC_RETURN, 0 ); + ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 ); #endif return 0; } @@ -1477,7 +1714,7 @@ } #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_CLOSE, ITRC_ENTER, 0 ); + ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 ); #endif #ifdef IP2DEBUG_OPEN @@ -1488,14 +1725,14 @@ MOD_DEC_USE_COUNT; #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_CLOSE, 2, 1, 2 ); + ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 ); #endif return; } if ( tty->count > 1 ) { /* not the last close */ MOD_DEC_USE_COUNT; #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_CLOSE, 2, 1, 3 ); + ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 ); #endif return; } @@ -1528,14 +1765,13 @@ i2InputFlush( pCh ); /* disable DSS reporting */ - i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP); + i2QueueCommands(PTYPE_INLINE, pCh, 100, 4, + CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP); if ( !tty || (tty->termios->c_cflag & HUPCL) ) { i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN); pCh->dataSetOut &= ~(I2_DTR | I2_RTS); i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25)); } - i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, - CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP); serviceOutgoingFifo ( pCh->pMyBord ); @@ -1565,7 +1801,7 @@ MOD_DEC_USE_COUNT; #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_CLOSE, ITRC_RETURN, 1, 1 ); + ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 ); #endif return; } @@ -1585,7 +1821,7 @@ i2ChanStrPtr pCh = tty->driver_data; #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_HANGUP, ITRC_ENTER, 0 ); + ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 ); #endif ip2_flush_buffer(tty); @@ -1610,7 +1846,7 @@ wake_up_interruptible ( &pCh->open_wait ); #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_HANGUP, ITRC_RETURN, 0 ); + ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 ); #endif } @@ -1640,7 +1876,7 @@ unsigned long flags; #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 ); + ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 ); #endif /* Flush out any buffered data left over from ip2_putchar() calls. */ @@ -1652,7 +1888,7 @@ WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent ); + ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent ); #endif return bytesSent > 0 ? bytesSent : 0; } @@ -1674,7 +1910,7 @@ unsigned long flags; #ifdef IP2DEBUG_TRACE -// ip2trace (PORTN, ITRC_PUTC, ITRC_ENTER, 1, ch ); +// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch ); #endif WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); @@ -1686,7 +1922,7 @@ WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); #ifdef IP2DEBUG_TRACE -// ip2trace (PORTN, ITRC_PUTC, ITRC_RETURN, 1, ch ); +// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch ); #endif } @@ -1708,7 +1944,7 @@ WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); if ( pCh->Pbuf_stuff ) { #ifdef IP2DEBUG_TRACE -// ip2trace (PORTN, ITRC_PUTC, 10, 1, strip ); +// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip ); #endif // // We may need to restart i2Output if it does not fullfill this request @@ -1742,7 +1978,7 @@ READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_WRITE, 11, 1, bytesFree ); + ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree ); #endif return ((bytesFree > 0) ? bytesFree : 0); @@ -1764,7 +2000,7 @@ int rc; unsigned long flags; #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff ); + ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff ); #endif #ifdef IP2DEBUG_WRITE printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n", @@ -1796,7 +2032,7 @@ unsigned long flags; #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_FLUSH, ITRC_ENTER, 0 ); + ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 ); #endif #ifdef IP2DEBUG_WRITE printk (KERN_DEBUG "IP2: flush buffer\n" ); @@ -1807,7 +2043,7 @@ i2FlushOutput( pCh ); ip2_owake(tty); #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_FLUSH, ITRC_RETURN, 0 ); + ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 ); #endif } @@ -1943,17 +2179,18 @@ static int ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg ) { - i2ChanStrPtr pCh = DevTable[MINOR(tty->device)]; + i2ChanStrPtr pCh = DevTable[MINOR(tty->device)]; struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct *p_cuser; /* user space */ int rc = 0; + unsigned long flags; if ( pCh == NULL ) { return -ENODEV; } #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg ); + ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg ); #endif #ifdef IP2DEBUG_IOCTL @@ -1963,7 +2200,7 @@ switch(cmd) { case TIOCGSERIAL: #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 2, 1, rc ); + ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc ); #endif rc = get_serial_info(pCh, (struct serial_struct *) arg); if (rc) @@ -1972,7 +2209,7 @@ case TIOCSSERIAL: #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 3, 1, rc ); + ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc ); #endif rc = set_serial_info(pCh, (struct serial_struct *) arg); if (rc) @@ -2010,7 +2247,7 @@ case TCSBRK: /* SVID version: non-zero arg --> no break */ rc = tty_check_change(tty); #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 4, 1, rc ); + ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc ); #endif if (!rc) { ip2_wait_until_sent(tty,0); @@ -2024,7 +2261,7 @@ case TCSBRKP: /* support for POSIX tcsendbreak() */ rc = tty_check_change(tty); #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 5, 1, rc ); + ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc ); #endif if (!rc) { ip2_wait_until_sent(tty,0); @@ -2036,18 +2273,18 @@ case TIOCGSOFTCAR: #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 6, 1, rc ); + ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc ); #endif - rc=put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + PUT_USER(rc,C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); if (rc) return rc; break; case TIOCSSOFTCAR: #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 7, 1, rc ); + ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc ); #endif - rc=get_user(arg,(unsigned long *) arg); + GET_USER(rc,arg,(unsigned long *) arg); if (rc) return rc; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) @@ -2057,18 +2294,37 @@ case TIOCMGET: #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 8, 1, rc ); + ip2trace (CHANN, ITRC_IOCTL, 8, 1, rc ); #endif - rc = get_modem_info(pCh, (unsigned int *) arg); - if (rc) - return rc; +/* + FIXME - the following code is causing a NULL pointer dereference in + 2.3.51 in an interrupt handler. It's suppose to prompt the board + to return the DSS signal status immediately. Why doesn't it do + the same thing in 2.2.14? +*/ +/* + i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW); + serviceOutgoingFifo( pCh->pMyBord ); + interruptible_sleep_on(&pCh->dss_now_wait); + if (signal_pending(current)) { + return -EINTR; + } +*/ + PUT_USER(rc, + ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0) + | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0) + | ((pCh->dataSetIn & I2_DCD) ? TIOCM_CAR : 0) + | ((pCh->dataSetIn & I2_RI) ? TIOCM_RNG : 0) + | ((pCh->dataSetIn & I2_DSR) ? TIOCM_DSR : 0) + | ((pCh->dataSetIn & I2_CTS) ? TIOCM_CTS : 0), + (unsigned int *) arg); break; case TIOCMBIS: case TIOCMBIC: case TIOCMSET: #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 9, 0 ); + ip2trace (CHANN, ITRC_IOCTL, 9, 0 ); #endif rc = set_modem_info(pCh, cmd, (unsigned int *) arg); break; @@ -2079,24 +2335,34 @@ * for masking). Caller should use TIOCGICOUNT to see which one it was */ case TIOCMIWAIT: + save_flags(flags);cli(); cprev = pCh->icount; /* note the counters on entry */ + restore_flags(flags); + i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4, + CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP); + serviceOutgoingFifo( pCh->pMyBord ); for(;;) { #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 10, 0 ); + ip2trace (CHANN, ITRC_IOCTL, 10, 0 ); #endif interruptible_sleep_on(&pCh->delta_msr_wait); +#ifdef IP2DEBUG_TRACE + ip2trace (CHANN, ITRC_IOCTL, 11, 0 ); +#endif /* see if a signal did it */ if (signal_pending(current)) { rc = -ERESTARTSYS; break; } + save_flags(flags);cli(); cnow = pCh->icount; /* atomic copy */ + restore_flags(flags); if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { rc = -EIO; /* no change => rc */ break; } - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + 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)) ) { @@ -2105,7 +2371,13 @@ } cprev = cnow; } - /* NOTREACHED */ + i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3, + CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP); + if ( ! (pCh->flags & ASYNC_CHECK_CD)) { + i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DCD_NREP); + } + serviceOutgoingFifo( pCh->pMyBord ); + return rc; break; /* @@ -2118,14 +2390,23 @@ */ case TIOCGICOUNT: #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 11, 1, rc ); + ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc ); #endif + save_flags(flags);cli(); cnow = pCh->icount; + restore_flags(flags); p_cuser = (struct serial_icounter_struct *) arg; - put_user(cnow.cts, &p_cuser->cts); - put_user(cnow.dsr, &p_cuser->dsr); - put_user(cnow.rng, &p_cuser->rng); - put_user(cnow.dcd, &p_cuser->dcd); + PUT_USER(rc,cnow.cts, &p_cuser->cts); + PUT_USER(rc,cnow.dsr, &p_cuser->dsr); + PUT_USER(rc,cnow.rng, &p_cuser->rng); + PUT_USER(rc,cnow.dcd, &p_cuser->dcd); + PUT_USER(rc,cnow.rx, &p_cuser->rx); + PUT_USER(rc,cnow.tx, &p_cuser->tx); + PUT_USER(rc,cnow.frame, &p_cuser->frame); + PUT_USER(rc,cnow.overrun, &p_cuser->overrun); + PUT_USER(rc,cnow.parity, &p_cuser->parity); + PUT_USER(rc,cnow.brk, &p_cuser->brk); + PUT_USER(rc,cnow.buf_overrun, &p_cuser->buf_overrun); break; /* @@ -2142,43 +2423,16 @@ default: #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, 12, 0 ); + ip2trace (CHANN, ITRC_IOCTL, 12, 0 ); #endif rc = -ENOIOCTLCMD; break; } #ifdef IP2DEBUG_TRACE - ip2trace (PORTN, ITRC_IOCTL, ITRC_RETURN, 0 ); + ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 ); #endif return rc; } -/******************************************************************************/ -/* Function: get_modem_info() */ -/* Parameters: Pointer to channel structure */ -/* Pointer to destination for data */ -/* Returns: Nothing */ -/* */ -/* Description: */ -/* This returns the current settings of the dataset signal inputs to the user */ -/* program. */ -/******************************************************************************/ -static int -get_modem_info(i2ChanStrPtr pCh, unsigned int *value) -{ - unsigned short status; - unsigned int result; - int rc; - - status = pCh->dataSetIn; // snapshot settings - result = ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0) - | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0) - | ((status & I2_DCD) ? TIOCM_CAR : 0) - | ((status & I2_RI) ? TIOCM_RNG : 0) - | ((status & I2_DSR) ? TIOCM_DSR : 0) - | ((status & I2_CTS) ? TIOCM_CTS : 0); - rc=put_user(result,value); - return rc; -} /******************************************************************************/ /* Function: set_modem_info() */ @@ -2197,7 +2451,7 @@ int rc; unsigned int arg; - rc=get_user(arg,value); + GET_USER(rc,arg,value); if (rc) return rc; switch(cmd) { @@ -2258,7 +2512,7 @@ get_serial_info ( i2ChanStrPtr pCh, struct serial_struct *retinfo ) { struct serial_struct tmp; - int rc=0; + int rc; if ( !retinfo ) { return -EFAULT; @@ -2279,9 +2533,8 @@ tmp.close_delay = pCh->ClosingDelay; tmp.closing_wait = pCh->ClosingWaitTime; tmp.custom_divisor = pCh->BaudDivisor; - if(copy_to_user(retinfo,&tmp,sizeof(*retinfo))) - rc= -EFAULT; - return rc; + COPY_TO_USER(rc,retinfo,&tmp,sizeof(*retinfo)); + return rc; } /******************************************************************************/ @@ -2305,7 +2558,7 @@ if ( !new_info ) { return -EFAULT; } - rc=copy_from_user(&ns, new_info, sizeof (ns) ); + COPY_FROM_USER(rc, &ns, new_info, sizeof (ns) ); if (rc) { return rc; } @@ -2631,6 +2884,7 @@ i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt)); } if (cflag & CLOCAL) { + // Status reporting fails for DCD if this is off i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP); pCh->flags &= ~ASYNC_CHECK_CD; } else { @@ -2670,10 +2924,16 @@ /******************************************************************************/ static +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +int +ip2_ipl_read(struct inode *pInode, char *pData, size_t count, loff_t *off ) + unsigned int minor = MINOR( pInode->i_rdev ); +#else ssize_t ip2_ipl_read(struct file *pFile, char *pData, size_t count, loff_t *off ) { unsigned int minor = MINOR( pFile->f_dentry->d_inode->i_rdev ); +#endif int rc = 0; #ifdef IP2DEBUG_IPL @@ -2707,9 +2967,8 @@ DumpFifoBuffer ( char *pData, int count ) { #ifdef DEBUG_FIFO - int rc=0; - if(copy_to_user(pData, DBGBuf, count)) - rc=-EFAULT; + int rc; + COPY_TO_USER(rc, pData, DBGBuf, count); printk(KERN_DEBUG "Last index %d\n", I ); @@ -2730,10 +2989,10 @@ if ( count < (sizeof(int) * 6) ) { return -EIO; } - put_user(tracewrap, pIndex ); - put_user(TRACEMAX, ++pIndex ); - put_user(tracestrip, ++pIndex ); - put_user(tracestuff, ++pIndex ); + PUT_USER(rc, tracewrap, pIndex ); + PUT_USER(rc, TRACEMAX, ++pIndex ); + PUT_USER(rc, tracestrip, ++pIndex ); + PUT_USER(rc, tracestuff, ++pIndex ); pData += sizeof(int) * 6; count -= sizeof(int) * 6; @@ -2746,21 +3005,21 @@ } chunk = TRACEMAX - tracestrip; if ( dumpcount > chunk ) { - rc=copy_to_user(pData, &tracebuf[tracestrip], - chunk * sizeof(tracebuf[0]) )?-EFAULT:0; + COPY_TO_USER(rc, pData, &tracebuf[tracestrip], + chunk * sizeof(tracebuf[0]) ); pData += chunk * sizeof(tracebuf[0]); tracestrip = 0; chunk = dumpcount - chunk; } else { chunk = dumpcount; } - rc=copy_to_user(pData, &tracebuf[tracestrip], - chunk * sizeof(tracebuf[0]) )?-EFAULT:0 + COPY_TO_USER(rc, pData, &tracebuf[tracestrip], + chunk * sizeof(tracebuf[0]) ); tracestrip += chunk; tracewrap = 0; - put_user(tracestrip, ++pIndex ); - put_user(tracestuff, ++pIndex ); + PUT_USER(rc, tracestrip, ++pIndex ); + PUT_USER(rc, tracestuff, ++pIndex ); return dumpcount; #else @@ -2824,16 +3083,15 @@ case 13: switch ( cmd ) { case 64: /* Driver - ip2stat */ - put_user(ref_count, pIndex++ ); - put_user(irq_counter, pIndex++ ); - put_user(bh_counter, pIndex++ ); + PUT_USER(rc, ref_count, pIndex++ ); + PUT_USER(rc, irq_counter, pIndex++ ); + PUT_USER(rc, bh_counter, pIndex++ ); break; case 65: /* Board - ip2stat */ if ( pB ) { - if(copy_to_user((char*)arg, (char*)pB, sizeof(i2eBordStr) )) - rc=-EFAULT; - put_user(INB(pB->i2eStatus), + COPY_TO_USER(rc, (char*)arg, (char*)pB, sizeof(i2eBordStr) ); + PUT_USER(rc, INB(pB->i2eStatus), (ULONG*)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) ); } else { rc = -ENODEV; @@ -2844,8 +3102,7 @@ pCh = DevTable[cmd]; if ( pCh ) { - if(copy_to_user((char*)arg, (char*)pCh, sizeof(i2ChanStr) )) - rc = -EFAULT; + COPY_TO_USER(rc, (char*)arg, (char*)pCh, sizeof(i2ChanStr) ); } else { rc = cmd < 64 ? -ENODEV : -EINVAL; } @@ -2857,61 +3114,60 @@ break; case 3: // Trace device if ( cmd == 1 ) { - put_user(iiSendPendingMail, pIndex++ ); - put_user(i2InitChannels, pIndex++ ); - put_user(i2QueueNeeds, pIndex++ ); - put_user(i2QueueCommands, pIndex++ ); - put_user(i2GetStatus, pIndex++ ); - put_user(i2Input, pIndex++ ); - put_user(i2InputFlush, pIndex++ ); - put_user(i2Output, pIndex++ ); - put_user(i2FlushOutput, pIndex++ ); - put_user(i2DrainWakeup, pIndex++ ); - put_user(i2DrainOutput, pIndex++ ); - put_user(i2OutputFree, pIndex++ ); - put_user(i2StripFifo, pIndex++ ); - put_user(i2StuffFifoBypass, pIndex++ ); - put_user(i2StuffFifoFlow, pIndex++ ); - put_user(i2StuffFifoInline, pIndex++ ); - put_user(i2ServiceBoard, pIndex++ ); - put_user(serviceOutgoingFifo, pIndex++ ); - // put_user(ip2_init, pIndex++ ); - put_user(ip2_init_board, pIndex++ ); - put_user(find_eisa_board, pIndex++ ); - put_user(set_irq, pIndex++ ); - put_user(ip2_interrupt, pIndex++ ); - put_user(ip2_poll, pIndex++ ); - put_user(service_all_boards, pIndex++ ); - put_user(do_input, pIndex++ ); - put_user(do_status, pIndex++ ); + PUT_USER(rc, iiSendPendingMail, pIndex++ ); + PUT_USER(rc, i2InitChannels, pIndex++ ); + PUT_USER(rc, i2QueueNeeds, pIndex++ ); + PUT_USER(rc, i2QueueCommands, pIndex++ ); + PUT_USER(rc, i2GetStatus, pIndex++ ); + PUT_USER(rc, i2Input, pIndex++ ); + PUT_USER(rc, i2InputFlush, pIndex++ ); + PUT_USER(rc, i2Output, pIndex++ ); + PUT_USER(rc, i2FlushOutput, pIndex++ ); + PUT_USER(rc, i2DrainWakeup, pIndex++ ); + PUT_USER(rc, i2DrainOutput, pIndex++ ); + PUT_USER(rc, i2OutputFree, pIndex++ ); + PUT_USER(rc, i2StripFifo, pIndex++ ); + PUT_USER(rc, i2StuffFifoBypass, pIndex++ ); + PUT_USER(rc, i2StuffFifoFlow, pIndex++ ); + PUT_USER(rc, i2StuffFifoInline, pIndex++ ); + PUT_USER(rc, i2ServiceBoard, pIndex++ ); + PUT_USER(rc, serviceOutgoingFifo, pIndex++ ); + // PUT_USER(rc, ip2_init, pIndex++ ); + PUT_USER(rc, ip2_init_board, pIndex++ ); + PUT_USER(rc, find_eisa_board, pIndex++ ); + PUT_USER(rc, set_irq, pIndex++ ); + PUT_USER(rc, ip2_interrupt, pIndex++ ); + PUT_USER(rc, ip2_poll, pIndex++ ); + PUT_USER(rc, service_all_boards, pIndex++ ); + PUT_USER(rc, do_input, pIndex++ ); + PUT_USER(rc, do_status, pIndex++ ); #ifndef IP2DEBUG_OPEN - put_user(0, pIndex++ ); + PUT_USER(rc, 0, pIndex++ ); #else - put_user(open_sanity_check, pIndex++ ); + PUT_USER(rc, open_sanity_check, pIndex++ ); #endif - put_user(ip2_open, pIndex++ ); - put_user(ip2_close, pIndex++ ); - put_user(ip2_hangup, pIndex++ ); - put_user(ip2_write, pIndex++ ); - put_user(ip2_putchar, pIndex++ ); - put_user(ip2_flush_chars, pIndex++ ); - put_user(ip2_write_room, pIndex++ ); - put_user(ip2_chars_in_buf, pIndex++ ); - put_user(ip2_flush_buffer, pIndex++ ); - - //put_user(ip2_wait_until_sent, pIndex++ ); - put_user(0, pIndex++ ); - - put_user(ip2_throttle, pIndex++ ); - put_user(ip2_unthrottle, pIndex++ ); - put_user(ip2_ioctl, pIndex++ ); - put_user(get_modem_info, pIndex++ ); - put_user(set_modem_info, pIndex++ ); - put_user(get_serial_info, pIndex++ ); - put_user(set_serial_info, pIndex++ ); - put_user(ip2_set_termios, pIndex++ ); - put_user(ip2_set_line_discipline, pIndex++ ); - put_user(set_params, pIndex++ ); + PUT_USER(rc, ip2_open, pIndex++ ); + PUT_USER(rc, ip2_close, pIndex++ ); + PUT_USER(rc, ip2_hangup, pIndex++ ); + PUT_USER(rc, ip2_write, pIndex++ ); + PUT_USER(rc, ip2_putchar, pIndex++ ); + PUT_USER(rc, ip2_flush_chars, pIndex++ ); + PUT_USER(rc, ip2_write_room, pIndex++ ); + PUT_USER(rc, ip2_chars_in_buf, pIndex++ ); + PUT_USER(rc, ip2_flush_buffer, pIndex++ ); + + //PUT_USER(rc, ip2_wait_until_sent, pIndex++ ); + PUT_USER(rc, 0, pIndex++ ); + + PUT_USER(rc, ip2_throttle, pIndex++ ); + PUT_USER(rc, ip2_unthrottle, pIndex++ ); + PUT_USER(rc, ip2_ioctl, pIndex++ ); + PUT_USER(rc, set_modem_info, pIndex++ ); + PUT_USER(rc, get_serial_info, pIndex++ ); + PUT_USER(rc, set_serial_info, pIndex++ ); + PUT_USER(rc, ip2_set_termios, pIndex++ ); + PUT_USER(rc, ip2_set_line_discipline, pIndex++ ); + PUT_USER(rc, set_params, pIndex++ ); } else { rc = -EINVAL; } @@ -3150,7 +3406,7 @@ if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/joystick/joystick.c linux/drivers/char/joystick/joystick.c --- v2.3.99-pre5/linux/drivers/char/joystick/joystick.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/joystick/joystick.c Mon Apr 24 17:55:15 2000 @@ -516,7 +516,9 @@ MOD_INC_USE_COUNT; - if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) { + new = kmalloc(sizeof(struct js_list), GFP_KERNEL); + if (!new) { + jd->close(jd); MOD_DEC_USE_COUNT; return -ENOMEM; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.3.99-pre5/linux/drivers/char/misc.c Mon Mar 27 08:08:23 2000 +++ linux/drivers/char/misc.c Thu Apr 13 07:54:32 2000 @@ -138,12 +138,12 @@ * @misc: device structure * * Register a miscellaneous device with the kernel. If the minor - * number is set to MISC_DYNAMIC_MINOR a minor number is assigned + * number is set to %MISC_DYNAMIC_MINOR a minor number is assigned * and placed in the minor field of the structure. For other cases * the minor number requested is used. * * The structure passed is linked into the kernel and may not be - * destroyed until it has been unregistered + * destroyed until it has been unregistered. * * A zero is returned on success and a negative errno code for * failure. @@ -195,7 +195,7 @@ * @misc: device to unregister * * Unregister a miscellaneous device that was previously - * successfully registered with misc_register. Success + * successfully registered with misc_register(). Success * is indicated by a zero return, a negative errno code * indicates an error. */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c --- v2.3.99-pre5/linux/drivers/char/msp3400.c Tue Mar 7 14:32:25 2000 +++ linux/drivers/char/msp3400.c Fri Apr 21 16:08:45 2000 @@ -34,6 +34,7 @@ * */ +#include #include #include #include @@ -46,7 +47,7 @@ #include #include -#ifdef __SMP__ +#ifdef CONFIG_SMP #include #include #endif @@ -59,7 +60,6 @@ #define WAIT_QUEUE wait_queue_head_t /* sound mixer stuff */ -#include #if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) # define REGISTER_MIXER 1 #endif @@ -678,7 +678,7 @@ struct CARRIER_DETECT *cd; int count, max1,max2,val1,val2, val,this; -#ifdef __SMP__ +#ifdef CONFIG_SMP lock_kernel(); #endif @@ -691,7 +691,7 @@ msp->thread = current; -#ifdef __SMP__ +#ifdef CONFIG_SMP unlock_kernel(); #endif @@ -933,7 +933,7 @@ struct msp3400c *msp = client->data; int mode,val,i,std; -#ifdef __SMP__ +#ifdef CONFIG_SMP lock_kernel(); #endif @@ -946,7 +946,7 @@ msp->thread = current; -#ifdef __SMP__ +#ifdef CONFIG_SMP unlock_kernel(); #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c --- v2.3.99-pre5/linux/drivers/char/n_hdlc.c Wed Dec 29 13:13:15 1999 +++ linux/drivers/char/n_hdlc.c Fri Apr 21 13:17:03 2000 @@ -978,6 +978,8 @@ * Return Value: * * bit mask containing info on which ops will not block + * + * Note: Called without the kernel lock held. Which is fine. */ static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c --- v2.3.99-pre5/linux/drivers/char/n_r3964.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/n_r3964.c Fri Apr 21 13:19:08 2000 @@ -1429,6 +1429,7 @@ TRACE_L("set_termios"); } +/* Called without the kernel lock held - fine */ static unsigned int r3964_poll(struct tty_struct * tty, struct file * file, struct poll_table_struct *wait) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.3.99-pre5/linux/drivers/char/n_tty.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/n_tty.c Fri Apr 21 15:21:18 2000 @@ -226,10 +226,10 @@ nr = space; if (nr > sizeof(buf)) nr = sizeof(buf); - nr -= copy_from_user(buf, inbuf, nr); - if (!nr) - return 0; - + + if (copy_from_user(buf, inbuf, nr)) + return -EFAULT; + for (i = 0, cp = buf; i < nr; i++, cp++) { switch (*cp) { case '\n': @@ -1166,6 +1166,7 @@ return (b - buf) ? b - buf : retval; } +/* Called without the kernel lock held - fine */ static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait) { unsigned int mask = 0; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/nvram.c linux/drivers/char/nvram.c --- v2.3.99-pre5/linux/drivers/char/nvram.c Sun Feb 13 19:29:03 2000 +++ linux/drivers/char/nvram.c Fri Apr 21 15:17:57 2000 @@ -372,7 +372,7 @@ if (offset >= begin + len) return( 0 ); - *start = buffer + (begin - offset); + *start = buffer + (offset - begin); return( size < begin + len - offset ? size : begin + len - offset ); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.3.99-pre5/linux/drivers/char/pc_keyb.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/char/pc_keyb.c Fri Apr 21 13:12:24 2000 @@ -59,6 +59,9 @@ static void kbd_write_command_w(int data); static void kbd_write_output_w(int data); +#ifdef CONFIG_PSMOUSE +static void aux_write_ack(int val); +#endif spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; static unsigned char handle_kbd_event(void); @@ -76,6 +79,8 @@ static int __init psaux_init(void); +#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */ + static struct aux_queue *queue; /* Mouse data buffer. */ static int aux_count = 0; /* used when we send commands to the mouse that expect an ACK. */ @@ -396,6 +401,11 @@ } mouse_reply_expected = 0; } + else if(scancode == AUX_RECONNECT){ + queue->head = queue->tail = 0; /* Flush input queue */ + aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ + return; + } add_mouse_randomness(scancode); if (aux_count) { @@ -964,6 +974,7 @@ return retval; } +/* No kernel lock held - fine */ static unsigned int aux_poll(struct file *file, poll_table * wait) { poll_wait(file, &queue->proc_list, wait); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/planb.c linux/drivers/char/planb.c --- v2.3.99-pre5/linux/drivers/char/planb.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/planb.c Wed Apr 12 09:38:53 2000 @@ -8,9 +8,7 @@ Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) - Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) - (Some codes are stolen from proposed v4l2 videodev.c - of Bill Dirks ) + Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) 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 @@ -94,11 +92,7 @@ static unsigned char saa_status(int, struct planb *); static void saa_set(unsigned char, unsigned char, struct planb *); static void saa_init_regs(struct planb *); -static void * rvmalloc(unsigned long); -static void rvfree(void *, unsigned long); -static unsigned long vmalloc_to_bus(void *); -static unsigned long vmalloc_to_phys(void *); -static int fbuffer_alloc(struct planb *); +static int grabbuf_alloc(struct planb *); static int vgrab(struct planb *, struct video_mmap *); static void add_clip(struct planb *, struct video_clip *); static void fill_cmd_buff(struct planb *); @@ -125,82 +119,36 @@ /* Memory management functions */ /*******************************/ -static void * rvmalloc(unsigned long size) +static int grabbuf_alloc(struct planb *pb) { - void *mem, *memptr; - unsigned long page; - - mem=vmalloc(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, leave no junk */ - memptr = mem; - while (size > 0) - { - page = vmalloc_to_phys(memptr); - mem_map_reserve(MAP_NR(phys_to_virt(page))); - memptr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - void *memptr; - unsigned long page; - - if (mem) - { - memptr = mem; - while (size > 0) - { - page = vmalloc_to_phys(memptr); - mem_map_unreserve(MAP_NR(phys_to_virt(page))); - memptr += PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } -} - -/* Useful for using vmalloc()ed memory as DMA target */ -static unsigned long vmalloc_to_bus(void *virt) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long a = (unsigned long)virt; - - if (pgd_none(*(pgd = pgd_offset(current->mm, a))) || - pmd_none(*(pmd = pmd_offset(pgd, a))) || - pte_none(*(pte = pte_offset(pmd, a)))) - return 0; - return virt_to_bus((void *)pte_page(*pte)) - + (a & (PAGE_SIZE - 1)); -} + int i, npage; -static unsigned long vmalloc_to_phys(void *virt) { - return virt_to_phys(bus_to_virt(vmalloc_to_bus(virt))); -} - -/* - * Create the giant waste of buffer space we need for now - * until we get DMA to user space sorted out (probably 2.3.x) - * - * We only create this as and when someone uses mmap - */ - -static int fbuffer_alloc(struct planb *pb) -{ - if(!pb->fbuffer) - pb->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS - * PLANB_MAX_FBUF); - else - printk(KERN_ERR "PlanB: Double alloc of fbuffer!\n"); - if(!pb->fbuffer) + npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1) +#ifndef PLANB_GSCANLINE + + MAX_LNUM +#endif /* PLANB_GSCANLINE */ + ); + if ((pb->rawbuf = (unsigned char**) kmalloc (npage + * sizeof(unsigned long), GFP_KERNEL)) == 0) + return -ENOMEM; + for (i = 0; i < npage; i++) { + pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL + |GFP_DMA, 0); + if (!pb->rawbuf[i]) + break; + set_bit(PG_reserved, &mem_map[MAP_NR(pb->rawbuf[i])].flags); + } + if (i-- < npage) { + printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n"); + for (; i > 0; i--) { + clear_bit(PG_reserved, + &mem_map[MAP_NR(pb->rawbuf[i])].flags); + free_pages((unsigned long)pb->rawbuf[i], 0); + } + kfree(pb->rawbuf); return -ENOBUFS; + } + pb->rawbuf_size = npage; return 0; } @@ -446,11 +394,8 @@ + PLANB_DUMMY); pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS); - pb->fbuffer = (unsigned char *)rvmalloc(MAX_GBUFFERS * PLANB_MAX_FBUF); - if (!pb->fbuffer) { - kfree(pb->priv_space); - return -ENOMEM; - } + pb->rawbuf = NULL; + pb->rawbuf_size = 0; pb->grabbing = 0; for (i = 0; i < MAX_GBUFFERS; i++) { pb->frame_stat[i] = GBUFFER_UNUSED; @@ -461,31 +406,23 @@ #ifndef PLANB_GSCANLINE pb->lsize[i] = 0; pb->lnum[i] = 0; - pb->l_fr_addr[i]=(unsigned char *)rvmalloc(PAGE_SIZE*MAX_LNUM); - if (!pb->l_fr_addr[i]) { - int j; - kfree(pb->priv_space); - rvfree((void *)pb->fbuffer, MAX_GBUFFERS - * PLANB_MAX_FBUF); - for(j = 0; j < i; j++) - rvfree((void *)pb->l_fr_addr[j], PAGE_SIZE - * MAX_LNUM); - return -ENOMEM; - } #endif /* PLANB_GSCANLINE */ } pb->gcount = 0; pb->suspend = 0; pb->last_fr = -999; pb->prev_last_fr = -999; - return 0; + + /* Reset DMA controllers */ + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + + return 0; } static void planb_prepare_close(struct planb *pb) { -#ifndef PLANB_GSCANLINE int i; -#endif /* make sure the dma's are idle */ planb_dbdma_stop(&pb->planb_base->ch2); @@ -496,16 +433,15 @@ pb->priv_space = 0; pb->cmd_buff_inited = 0; } - if(pb->fbuffer) - rvfree((void *)pb->fbuffer, MAX_GBUFFERS*PLANB_MAX_FBUF); - pb->fbuffer = NULL; -#ifndef PLANB_GSCANLINE - for(i = 0; i < MAX_GBUFFERS; i++) { - if(pb->l_fr_addr[i]) - rvfree((void *)pb->l_fr_addr[i], PAGE_SIZE * MAX_LNUM); - pb->l_fr_addr[i] = NULL; + if(pb->rawbuf) { + for (i = 0; i < pb->rawbuf_size; i++) { + clear_bit(PG_reserved, + &mem_map[MAP_NR(pb->rawbuf[i])].flags); + free_pages((unsigned long)pb->rawbuf[i], 0); + } + kfree(pb->rawbuf); } -#endif /* PLANB_GSCANLINE */ + pb->rawbuf = NULL; } /*****************************/ @@ -940,12 +876,8 @@ 0, 0, }; -#define PLANB_PALETTE_MAX 15 -#define SWAP4(x) (((x>>24) & 0x000000ff) |\ - ((x>>8) & 0x0000ff00) |\ - ((x<<8) & 0x00ff0000) |\ - ((x<<24) & 0xff000000)) +#define PLANB_PALETTE_MAX 15 static inline int overlay_is_active(struct planb *pb) { @@ -962,9 +894,10 @@ unsigned int fr = mp->frame; unsigned int format; - if(pb->fbuffer==NULL) { - if(fbuffer_alloc(pb)) - return -ENOBUFS; + if(pb->rawbuf==NULL) { + int err; + if((err=grabbuf_alloc(pb))) + return err; } IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing, @@ -984,12 +917,10 @@ return -EINVAL; planb_lock(pb); - pb->gbuffer[fr] = (unsigned char *)(pb->fbuffer + PLANB_MAX_FBUF * fr); if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] || format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) { -#ifdef PLANB_GSCANLINE int i; -#else +#ifndef PLANB_GSCANLINE unsigned int osize = pb->gwidth[fr] * pb->gheight[fr] * pb->gfmt[fr]; unsigned int nsize = mp->width * mp->height * format; @@ -1001,10 +932,15 @@ #ifndef PLANB_GSCANLINE if(pb->gnorm_switch[fr]) nsize = 0; - if(nsize < osize) - memset((void *)(pb->gbuffer[fr] + nsize), 0, - osize - nsize); - memset((void *)pb->l_fr_addr[fr], 0, PAGE_SIZE * pb->lnum[fr]); + if (nsize < osize) { + for(i = pb->gbuf_idx[fr]; osize > 0; i++) { + memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); + osize -= PAGE_SIZE; + } + } + for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr] + + pb->lnum[fr]; i++) + memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); #else /* XXX TODO */ /* @@ -1228,7 +1164,7 @@ unsigned long base; #endif unsigned long jump; - unsigned char *vaddr; + int pagei; volatile struct dbdma_cmd *c1; volatile struct dbdma_cmd *jump_addr; @@ -1277,11 +1213,12 @@ /* even field data: */ - vaddr = pb->gbuffer[fr]; + pagei = pb->gbuf_idx[fr]; #ifdef PLANB_GSCANLINE for (i = 0; i < nlines; i += stepsize) { tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - vmalloc_to_bus(vaddr + i * scanline), jump); + virt_to_bus(pb->rawbuf[pagei + + i * scanline / PAGE_SIZE]), jump); } #else i = 0; @@ -1289,7 +1226,7 @@ do { int j; - base = vmalloc_to_bus((void*)vaddr); + base = virt_to_bus(pb->rawbuf[pagei]); nlpp = (PAGE_SIZE - leftover1) / count / stepsize; for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, @@ -1304,11 +1241,13 @@ tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base + count * nlpp * stepsize + leftover1, jump); } else { - pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count * nlpp - * stepsize + leftover1; + pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] + + count * nlpp * stepsize + leftover1; + pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; + pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0; tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE - * pb->lnum[fr]), jump); + virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] + + pb->lnum[fr]]), jump); if(++pb->lnum[fr] > MAX_LNUM) pb->lnum[fr]--; } @@ -1316,7 +1255,7 @@ i += stepsize; } } - vaddr += PAGE_SIZE; + pagei++; } while(i < nlines); tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); c1 = jump_addr; @@ -1341,18 +1280,19 @@ #ifdef PLANB_GSCANLINE for (i = 1; i < nlines; i += stepsize) { tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - vmalloc_to_bus(vaddr + i * scanline), jump); + virt_to_bus(pb->rawbuf[pagei + + i * scanline / PAGE_SIZE]), jump); } #else i = 1; leftover1 = 0; - vaddr = pb->gbuffer[fr]; + pagei = pb->gbuf_idx[fr]; if(nlines <= 1) goto skip; do { int j; - base = vmalloc_to_bus((void*)vaddr); + base = virt_to_bus(pb->rawbuf[pagei]); nlpp = (PAGE_SIZE - leftover1) / count / stepsize; if(leftover1 >= count) { tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, @@ -1369,11 +1309,14 @@ leftover1 = 0; else { if(lov0 > count) { - pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count - * (nlpp * stepsize + 1) + leftover1; + pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] + + count * (nlpp * stepsize + 1) + leftover1; + pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; + pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize + - lov0; tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE - * pb->lnum[fr]), jump); + virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] + + pb->lnum[fr]]), jump); if(++pb->lnum[fr] > MAX_LNUM) pb->lnum[fr]--; i += stepsize; @@ -1381,7 +1324,7 @@ leftover1 = count * stepsize - lov0; } } - vaddr += PAGE_SIZE; + pagei++; } while(i < nlines); skip: tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); @@ -1390,7 +1333,7 @@ cmd_tab_data_end: tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat), - (fr << 2) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); + (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); /* stop it */ tab_cmd_dbdma(c1, DBDMA_STOP, 0); @@ -1406,13 +1349,15 @@ IDEBUG("PlanB: planb_irq()\n"); /* get/clear interrupt status bits */ + eieio(); stat = in_le32(&pb->planb_base->intr_stat); astat = stat & pb->intr_mask; - out_le32(&pb->planb_base->intr_stat, PLANB_IRQ_CMD_MASK + out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ & ~astat & stat & ~PLANB_GEN_IRQ); + IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat); if(astat & PLANB_FRM_IRQ) { - unsigned int fr = stat >> 2; + unsigned int fr = stat >> 9; #ifndef PLANB_GSCANLINE int i; #endif @@ -1425,9 +1370,16 @@ #ifndef PLANB_GSCANLINE IDEBUG("PlanB: %d * %d bytes are being copied over\n", pb->lnum[fr], pb->lsize[fr]); - for(i = 0; i < pb->lnum[fr]; i++) - memcpy(pb->l_to_addr[fr][i], pb->l_fr_addr[fr] - + PAGE_SIZE * i, pb->lsize[fr]); + for(i = 0; i < pb->lnum[fr]; i++) { + int first = pb->lsize[fr] - pb->l_to_next_size[fr][i]; + + memcpy(pb->l_to_addr[fr][i], + pb->rawbuf[pb->l_fr_addr_idx[fr] + i], + first); + memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]], + pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first, + pb->l_to_next_size[fr][i]); + } #endif pb->frame_stat[fr] = GBUFFER_DONE; pb->grabbing--; @@ -1848,6 +1800,8 @@ IDEBUG("PlanB: waiting for grab" " done (%d)\n", i); interruptible_sleep_on(&pb->capq); + if(signal_pending(current)) + return -EINTR; goto chk_grab; case GBUFFER_DONE: pb->frame_stat[i] = GBUFFER_UNUSED; @@ -2058,38 +2012,27 @@ return 0; } -/* - * This maps the vmalloced and reserved fbuffer to user space. - * - * FIXME: - * - PAGE_READONLY should suffice!? - * - remap_page_range is kind of inefficient for page by page remapping. - * But e.g. pte_alloc() does not work in modules ... :-( - */ - static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size) { - struct planb *pb=(struct planb *)dev; - unsigned long start=(unsigned long) adr; - unsigned long page; - void *pos; + int i; + struct planb *pb = (struct planb *)dev; + unsigned long start = (unsigned long)adr; - if (size>MAX_GBUFFERS*PLANB_MAX_FBUF) + if (size > MAX_GBUFFERS * PLANB_MAX_FBUF) return -EINVAL; - if (!pb->fbuffer) - { - if(fbuffer_alloc(pb)) - return -EINVAL; - } - pos = (void *)pb->fbuffer; - while (size > 0) - { - page = vmalloc_to_phys(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start+=PAGE_SIZE; - pos+=PAGE_SIZE; - size-=PAGE_SIZE; + if (!pb->rawbuf) { + int err; + if((err=grabbuf_alloc(pb))) + return err; + } + for (i = 0; i < pb->rawbuf_size; i++) { + if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]), + PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + if (size <= PAGE_SIZE) + break; + size -= PAGE_SIZE; } return 0; } @@ -2125,6 +2068,7 @@ { unsigned char saa_rev; int i, result; + unsigned long flags; memset ((void *) &pb->win, 0, sizeof (struct planb_window)); /* Simple sanity check */ @@ -2167,7 +2111,7 @@ pb->tab_size = PLANB_MAXLINES + 40; pb->suspend = 0; pb->lock = 0; - pb->lockq = NULL; + init_waitqueue_head(&pb->lockq); pb->ch1_cmd = 0; pb->ch2_cmd = 0; pb->mask = 0; @@ -2175,7 +2119,7 @@ pb->offset = 0; pb->user = 0; pb->overlay = 0; - pb->suspendq = NULL; + init_waitqueue_head(&pb->suspendq); pb->cmd_buff_inited = 0; pb->frame_buffer_phys = 0; @@ -2191,19 +2135,20 @@ /* clear interrupt mask */ pb->intr_mask = PLANB_CLR_IRQ; + save_flags(flags); cli(); result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb); - if (result==-EINVAL) { - printk(KERN_ERR "PlanB: Bad irq number (%d) or handler\n", - (int)pb->irq); - return result; - } - if (result==-EBUSY) { - printk(KERN_ERR "PlanB: I don't know why, but IRQ %d busy\n", - (int)pb->irq); - return result; - } - if (result < 0) - return result; + if (result < 0) { + if (result==-EINVAL) + printk(KERN_ERR "PlanB: Bad irq number (%d) " + "or handler\n", (int)pb->irq); + else if (result==-EBUSY) + printk(KERN_ERR "PlanB: I don't know why, " + "but IRQ %d is busy\n", (int)pb->irq); + restore_flags(flags); + return result; + } + disable_irq(pb->irq); + restore_flags(flags); /* Now add the template and register the device unit. */ memcpy(&pb->video_dev,&planb_template,sizeof(planb_template)); @@ -2216,26 +2161,27 @@ pb->picture.depth = pb->win.depth; pb->frame_stat=NULL; - pb->capq=NULL; + init_waitqueue_head(&pb->capq); for(i=0; igbuffer[i]=NULL; + pb->gbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE; pb->gwidth[i]=0; pb->gheight[i]=0; pb->gfmt[i]=0; pb->cap_cmd[i]=NULL; #ifndef PLANB_GSCANLINE - pb->l_fr_addr[i]=NULL; + pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF + / PAGE_SIZE + 1) + MAX_LNUM * i; pb->lsize[i] = 0; pb->lnum[i] = 0; #endif } - pb->fbuffer=NULL; + pb->rawbuf=NULL; pb->grabbing=0; - /* clear interrupts */ + /* enable interrupts */ out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - /* set interrupt mask */ pb->intr_mask = PLANB_FRM_IRQ; + enable_irq(pb->irq); if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER)<0) return -1; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/planb.h linux/drivers/char/planb.h --- v2.3.99-pre5/linux/drivers/char/planb.h Sat May 15 15:05:36 1999 +++ linux/drivers/char/planb.h Wed Apr 12 09:38:53 2000 @@ -8,7 +8,7 @@ Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) - Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) + Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) This program is free software; you can redistribute it and/or modify @@ -69,6 +69,7 @@ /* for capture operations */ #define MAX_GBUFFERS 2 +/* note PLANB_MAX_FBUF must be divisible by PAGE_SIZE */ #ifdef PLANB_GSCANLINE #define PLANB_MAX_FBUF 0x240000 /* 576 * 1024 * 4 */ #define TAB_FACTOR (1) @@ -132,8 +133,7 @@ volatile unsigned int intr_stat; /* 0x104: irq status */ #define PLANB_CLR_IRQ 0x00 /* clear Plan B interrupt */ #define PLANB_GEN_IRQ 0x01 /* assert Plan B interrupt */ -#define PLANB_FRM_IRQ 0x02 /* end of frame */ -#define PLANB_IRQ_CMD_MASK 0x00000003U /* reserve 2 lsbs for command */ +#define PLANB_FRM_IRQ 0x0100 /* end of frame */ unsigned int pad3[1]; /* empty? */ volatile unsigned int reg5; /* 0x10c: ??? */ unsigned int pad4[60]; /* empty? */ @@ -199,8 +199,9 @@ wait_queue_head_t capq; int last_fr; int prev_last_fr; - unsigned char *fbuffer; - unsigned char *gbuffer[MAX_GBUFFERS]; + unsigned char **rawbuf; + int rawbuf_size; + int gbuf_idx[MAX_GBUFFERS]; volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS]; volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS]; volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS]; @@ -218,8 +219,10 @@ #else #define MAX_LNUM 431 /* change this if PLANB_MAXLINES or */ /* PLANB_MAXPIXELS changes */ - unsigned char *l_fr_addr[MAX_GBUFFERS]; + int l_fr_addr_idx[MAX_GBUFFERS]; unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM]; + int l_to_next_idx[MAX_GBUFFERS][MAX_LNUM]; + int l_to_next_size[MAX_GBUFFERS][MAX_LNUM]; int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS]; #endif }; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- v2.3.99-pre5/linux/drivers/char/ppdev.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/char/ppdev.c Wed Apr 26 09:29:15 2000 @@ -569,15 +569,16 @@ return 0; } +/* No kernel lock held - fine */ static unsigned int pp_poll (struct file * file, poll_table * wait) { struct pp_struct *pp = file->private_data; unsigned int mask = 0; + poll_wait (file, &pp->irq_wait, wait); if (atomic_read (&pp->irqc)) mask |= POLLIN | POLLRDNORM; - poll_wait (file, &pp->irq_wait, wait); return mask; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/pty.c linux/drivers/char/pty.c --- v2.3.99-pre5/linux/drivers/char/pty.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/char/pty.c Tue Apr 25 16:53:13 2000 @@ -138,7 +138,7 @@ const unsigned char *buf, int count) { struct tty_struct *to = tty->link; - int c=0, n; + int c=0, n, room; char *temp_buffer; if (!to || tty->stopped) @@ -149,7 +149,9 @@ temp_buffer = &tty->flip.char_buf[0]; while (count > 0) { /* check space so we don't copy needlessly */ - n = MIN(count, to->ldisc.receive_room(to)); + n = to->ldisc.receive_room(to); + if (n > count) + n = count; if (!n) break; n = MIN(n, PTY_BUF_SIZE); @@ -161,7 +163,9 @@ } /* check again in case the buffer filled up */ - n = MIN(n, to->ldisc.receive_room(to)); + room = to->ldisc.receive_room(to); + if (n > room) + n = room; if (!n) break; buf += n; c += n; @@ -356,7 +360,11 @@ memset(&pty_driver, 0, sizeof(struct tty_driver)); pty_driver.magic = TTY_DRIVER_MAGIC; pty_driver.driver_name = "pty_master"; +#ifdef CONFIG_DEVFS_FS pty_driver.name = "pty/m%d"; +#else + pty_driver.name = "pty"; +#endif pty_driver.major = PTY_MASTER_MAJOR; pty_driver.minor_start = 0; pty_driver.num = NR_PTYS; @@ -387,7 +395,11 @@ pty_slave_driver = pty_driver; pty_slave_driver.driver_name = "pty_slave"; pty_slave_driver.proc_entry = 0; +#ifdef CONFIG_DEVFS_FS pty_slave_driver.name = "pty/s%d"; +#else + pty_slave_driver.name = "ttyp"; +#endif pty_slave_driver.subtype = PTY_TYPE_SLAVE; pty_slave_driver.major = PTY_SLAVE_MAJOR; pty_slave_driver.minor_start = 0; @@ -440,7 +452,11 @@ init_waitqueue_head(&ptm_state[i][j].open_wait); pts_driver[i] = pty_slave_driver; +#ifdef CONFIG_DEVFS_FS pts_driver[i].name = "pts/%d"; +#else + pts_driver[i].name = "pts"; +#endif pts_driver[i].proc_entry = 0; pts_driver[i].major = UNIX98_PTY_SLAVE_MAJOR+i; pts_driver[i].minor_start = 0; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.3.99-pre5/linux/drivers/char/random.c Thu Feb 10 17:11:08 2000 +++ linux/drivers/char/random.c Wed Apr 12 09:38:52 2000 @@ -763,7 +763,12 @@ void add_keyboard_randomness(unsigned char scancode) { - add_timer_randomness(&keyboard_timer_state, scancode); + static unsigned char last_scancode = 0; + /* ignore autorepeat (multiple key down w/o key up) */ + if (scancode != last_scancode) { + last_scancode = scancode; + add_timer_randomness(&keyboard_timer_state, scancode); + } } void add_mouse_randomness(__u32 mouse_data) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.3.99-pre5/linux/drivers/char/rtc.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/char/rtc.c Fri Apr 21 13:19:51 2000 @@ -550,6 +550,7 @@ } #ifndef __alpha__ +/* Called without the kernel lock - fine */ static unsigned int rtc_poll(struct file *file, poll_table *wait) { unsigned long l, flags; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.3.99-pre5/linux/drivers/char/serial.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/char/serial.c Wed Apr 26 09:11:31 2000 @@ -3159,7 +3159,7 @@ done: if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -4164,7 +4164,7 @@ PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, 0, 0, pci_siig20x_fn }, - /* Computone devices submitted by Doug McNash dmcnash@computone.com */ + /* Computone devices submitted by Doug McNash dougm@computone.com */ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, SPCI_FL_BASE0, 4, 921600, /* IOMEM */ @@ -4477,7 +4477,7 @@ #if (LINUX_VERSION_CODE > 0x20100) serial_driver.driver_name = "serial"; #endif -#if (LINUX_VERSION_CODE > 0x2032D) +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) serial_driver.name = "tts/%d"; #else serial_driver.name = "ttyS"; @@ -4525,7 +4525,7 @@ * major number and the subtype code. */ callout_driver = serial_driver; -#if (LINUX_VERSION_CODE > 0x2032D) +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) callout_driver.name = "cua/%d"; #else callout_driver.name = "cua"; @@ -4683,7 +4683,7 @@ * * The port specified is deconfigured and its resources are freed. Any * user of the port is disconnected as if carrier was dropped. Line is - * the port number returned by register_serial. + * the port number returned by register_serial(). */ void unregister_serial(int line) @@ -5023,6 +5023,6 @@ /* Local variables: - compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" + compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" End: */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c --- v2.3.99-pre5/linux/drivers/char/sh-sci.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/char/sh-sci.c Mon Apr 24 13:54:17 2000 @@ -1,4 +1,4 @@ -/* $Id: sh-sci.c,v 1.36 2000/03/22 13:32:10 gniibe Exp $ +/* $Id: sh-sci.c,v 1.40 2000/04/15 06:57:29 gniibe Exp $ * * linux/drivers/char/sh-sci.c * @@ -191,14 +191,13 @@ #if defined(CONFIG_SH_SCIF_SERIAL) if (C_CRTSCTS(port->gs.tty)) fcr_val |= 0x08; + else + ctrl_outw(0x0080, SCSPTR); /* Set RTS = 1 */ ctrl_out(fcr_val, SCFCR); #endif sci_set_baud(port); ctrl_out(SCSCR_INIT, SCSCR); /* TIE=0,RIE=0,TE=1,RE=1 */ -#if 0 /* defined(CONFIG_SH_SCIF_SERIAL) */ - ctrl_outw(0x0080, SCSPTR); /* Set RTS = 1 */ -#endif sci_enable_rx_interrupts(port); } @@ -661,7 +660,7 @@ sci_driver.subtype = SERIAL_TYPE_NORMAL; sci_driver.init_termios = tty_std_termios; sci_driver.init_termios.c_cflag = - B115200 | CS8 | CREAD | HUPCL | CLOCAL; + B115200 | CS8 | CREAD | HUPCL | CLOCAL | CRTSCTS; sci_driver.flags = TTY_DRIVER_REAL_RAW; sci_driver.refcount = &sci_refcount; sci_driver.table = sci_table; @@ -716,12 +715,6 @@ return 0; } -#ifdef MODULE -#define sci_init init_module -#else -#define sci_init rs_init -#endif - int __init sci_init(void) { struct sci_port *port; @@ -756,6 +749,8 @@ #endif return 0; /* Return -EIO when not detected */ } + +module_init(sci_init); #ifdef MODULE #undef func_enter diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/sx.c linux/drivers/char/sx.c --- v2.3.99-pre5/linux/drivers/char/sx.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/sx.c Thu Apr 13 17:06:05 2000 @@ -33,7 +33,12 @@ * * Revision history: * $Log: sx.c,v $ - * Revision 1.32 2000/03/07 90:00:00 wolff,pvdl + * Revision 1.33 2000/03/09 10:00:00 pvdl,wolff + * - Fixed module and port counting + * - Fixed signal handling + * - Fixed an Ooops + * + * Revision 1.32 2000/03/07 09:00:00 wolff,pvdl * - Fixed some sx_dprintk typos * - added detection for an invalid board/module configuration * @@ -195,8 +200,8 @@ * */ -#define RCS_ID "$Id: sx.c,v 1.32 2000/03/07 17:01:02 wolff, pvdl Exp $" -#define RCS_REV "$Revision: 1.32 $" +#define RCS_ID "$Id: sx.c,v 1.33 2000/03/08 10:01:02 wolff, pvdl Exp $" +#define RCS_REV "$Revision: 1.33 $" #include @@ -231,8 +236,9 @@ #include "sxboards.h" #include "sxwindow.h" -#include + #include +#include #include "sx.h" @@ -241,11 +247,11 @@ if you want more than 4 boards. */ - /* Why the hell am I defining these here? */ #define SX_TYPE_NORMAL 1 #define SX_TYPE_CALLOUT 2 + #ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 #define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000 #endif @@ -767,6 +773,7 @@ if (rts >= 0) t = rts? (t | OP_RTS): (t & ~OP_RTS); sx_write_channel_byte (port, hi_op, t); sx_dprintk (SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts); + func_exit (); } @@ -882,6 +889,9 @@ func_enter2(); + if (!port->gs.tty) + return 0; + /* What is this doing here? -- REW Ha! figured it out. It is to allow you to get DTR active again if you've dropped it with stty 0. Moved to set_baud, where it @@ -1043,7 +1053,7 @@ sx_disable_tx_interrupts (port); } - if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { + if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) { if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup) (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); @@ -1294,6 +1304,8 @@ sx_interrupt (0, board, NULL); + init_timer(&board->timer); + board->timer.expires = jiffies + sx_poll; add_timer (&board->timer); func_exit (); @@ -1389,7 +1401,7 @@ func_enter(); port->gs.flags &= ~ GS_ACTIVE; - if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) { + if (port->gs.tty && (port->gs.tty->termios->c_cflag & HUPCL)) { sx_setsignals (port, 0, 0); sx_reconfigure_port(port); } @@ -1452,6 +1464,8 @@ tty->driver_data = port; port->gs.tty = tty; + if (!port->gs.count) + MOD_INC_USE_COUNT; port->gs.count++; sx_dprintk (SX_DEBUG_OPEN, "starting port\n"); @@ -1463,19 +1477,13 @@ sx_dprintk (SX_DEBUG_OPEN, "done gs_init\n"); if (retval) { port->gs.count--; + if (port->gs.count) MOD_DEC_USE_COUNT; return retval; } port->gs.flags |= GS_ACTIVE; sx_setsignals (port, 1,1); - sx_dprintk (SX_DEBUG_OPEN, "before inc_use_count (count=%d.\n", - port->gs.count); - if (port->gs.count == 1) { - MOD_INC_USE_COUNT; - } - sx_dprintk (SX_DEBUG_OPEN, "after inc_use_count\n"); - #if 0 if (sx_debug & SX_DEBUG_OPEN) my_hd ((unsigned char *)port, sizeof (*port)); @@ -1487,8 +1495,8 @@ if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) { printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n"); - MOD_DEC_USE_COUNT; port->gs.count--; + if (!port->gs.count) MOD_DEC_USE_COUNT; return -EIO; } @@ -1497,8 +1505,10 @@ retval, port->gs.count); if (retval) { - MOD_DEC_USE_COUNT; - port->gs.count--; + /* + * Don't lower gs.count here because sx_close() will be called later + */ + return retval; } /* tty->low_latency = 1; */ @@ -1530,7 +1540,21 @@ exit minicom. I expect an "oops". -- REW */ static void sx_hungup (void *ptr) { + struct sx_port *port = ptr; func_enter (); + + sx_setsignals (port, 0, 0); + sx_reconfigure_port(port); + sx_send_command (port, HS_CLOSE, 0, 0); + + if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) { + if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) { + printk (KERN_ERR + "sx: sent the force_close command, but card didn't react\n"); + } else + sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n"); + } + MOD_DEC_USE_COUNT; func_exit (); } @@ -1543,6 +1567,9 @@ int to = 5 * HZ; func_enter (); + + sx_setsignals (port, 0, 0); + sx_reconfigure_port(port); sx_send_command (port, HS_CLOSE, 0, 0); while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) { @@ -1562,6 +1589,11 @@ sx_dprintk (SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n", 5 * HZ - to - 1, port->gs.count); + + if(port->gs.count) { + sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n", port->gs.count); + port->gs.count = 0; + } MOD_DEC_USE_COUNT; func_exit (); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/synclink.c linux/drivers/char/synclink.c --- v2.3.99-pre5/linux/drivers/char/synclink.c Wed Dec 29 13:13:15 1999 +++ linux/drivers/char/synclink.c Fri Apr 21 15:17:57 2000 @@ -3901,7 +3901,7 @@ done: if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } /* end of mgsl_read_proc() */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.3.99-pre5/linux/drivers/char/tty_io.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/char/tty_io.c Fri Apr 21 16:11:05 2000 @@ -367,6 +367,7 @@ return -EIO; } +/* No kernel lock held - none needed ;) */ static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait) { return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; @@ -1410,6 +1411,7 @@ return 0; } +/* No kernel lock held - fine */ static unsigned int tty_poll(struct file * filp, poll_table * wait) { struct tty_struct * tty; @@ -2015,6 +2017,8 @@ mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; break; default: + if (driver->major == PTY_MASTER_MAJOR) + flags |= DEVFS_FL_AUTO_OWNER; break; } if ( (minor < driver->minor_start) || diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.3.99-pre5/linux/drivers/char/videodev.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/char/videodev.c Thu Apr 13 07:54:32 2000 @@ -221,26 +221,26 @@ /** * video_register_device - register video4linux devices - * @vfd: Video device structure we want to register + * @vfd: video device structure we want to register * @type: type of device to register * FIXME: needs a semaphore on 2.3.x * * The registration code assigns minor numbers based on the type * requested. -ENFILE is returned in all the device slots for this - * catetory are full. If not then the minor field is set and the - * driver initialize function is called (if non NULL). + * category are full. If not then the minor field is set and the + * driver initialize function is called (if non %NULL). * * Zero is returned on success. * * Valid types are * - * VFL_TYPE_GRABBER - A frame grabber + * %VFL_TYPE_GRABBER - A frame grabber * - * VFL_TYPE_VTX - A teletext device + * %VFL_TYPE_VTX - A teletext device * - * VFL_TYPE_VBI - Vertical blank data (undecoded) + * %VFL_TYPE_VBI - Vertical blank data (undecoded) * - * VFL_TYPE_RADIO - A radio card + * %VFL_TYPE_RADIO - A radio card */ int video_register_device(struct video_device *vfd, int type) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/Config.in linux/drivers/i2o/Config.in --- v2.3.99-pre5/linux/drivers/i2o/Config.in Fri Oct 22 13:21:49 1999 +++ linux/drivers/i2o/Config.in Wed Apr 12 09:38:53 2000 @@ -3,7 +3,9 @@ tristate 'I2O support' CONFIG_I2O -dep_tristate ' I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O +if [ "$CONFIG_PCI" = "y" ]; then + dep_tristate ' I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O +fi dep_tristate ' I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O if [ "$CONFIG_NET" = "y" ]; then dep_tristate ' I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/README linux/drivers/i2o/README --- v2.3.99-pre5/linux/drivers/i2o/README Thu Nov 11 20:11:34 1999 +++ linux/drivers/i2o/README Wed Apr 12 09:38:53 2000 @@ -16,6 +16,7 @@ Debugging SCSI and Block OSM Deepak Saxena, Intel Corp. + Various core/block extensions /proc interface, bug fixes Ioctl interfaces for control Debugging LAN OSM @@ -64,24 +65,22 @@ STATUS: o The core setup works within limits. -o The scsi layer seems to almost work. I'm still chasing down the hang - bug. -o The block OSM is fairly minimal but does seem to work. +o The scsi layer seems to almost work. + I'm still chasing down the hang bug. +o The block OSM is mostly functional o LAN OSM works with FDDI and Ethernet cards. TO DO: General: -o Support multiple IOP's and tell them about each other o Provide hidden address space if asked o Long term message flow control o PCI IOP's without interrupts are not supported yet o Push FAIL handling into the core o DDM control interfaces for module load etc -o Event handling +o Add I2O 2.0 support (Deffered to 2.5 kernel) Block: -o Real error handler o Multiple major numbers o Read ahead and cache handling stuff. Talk to Ingo and people o Power management @@ -90,9 +89,11 @@ SCSI: o Find the right way to associate drives/luns/busses -Lan: Batch mode sends - Performance tuning - Event handling +Lan: +o Performance tuning +o Test Fibre Channel code +o Fix lan_set_mc_list() Tape: o Anyone seen anything implementing this ? + (D.S: Will attempt to do so if spare cycles permit) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/README.ioctl linux/drivers/i2o/README.ioctl --- v2.3.99-pre5/linux/drivers/i2o/README.ioctl Thu Nov 11 20:11:34 1999 +++ linux/drivers/i2o/README.ioctl Wed Apr 12 09:38:53 2000 @@ -20,7 +20,7 @@ This document and the I2O user space interface are currently maintained by Deepak Saxena. Please send all comments, errata, and bug fixes to -deepak@plexity.net +deepak@csociety.purdue.edu II. IOP Access diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c --- v2.3.99-pre5/linux/drivers/i2o/i2o_block.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/i2o/i2o_block.c Wed Apr 12 09:38:53 2000 @@ -1,30 +1,35 @@ /* - * I2O block device driver. + * I2O Random Block Storage Class OSM * - * (C) Copyright 1999 Red Hat Software + * (C) Copyright 1999 Red Hat Software * - * Written by Alan Cox, Building Number Three Ltd + * Written by Alan Cox, Building Number Three Ltd * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * - * This is a beta test release. Most of the good code was taken - * from the nbd driver by Pavel Machek, who in turn took some of it - * from loop.c. Isn't free software great for reusability 8) + * This is a beta test release. Most of the good code was taken + * from the nbd driver by Pavel Machek, who in turn took some of it + * from loop.c. Isn't free software great for reusability 8) + * + * Fixes/additions: + * Steve Ralston: + * Multiple device handling error fixes, + * Added a queue depth. + * Alan Cox: + * FC920 has an rmw bug. Dont or in the end marker. + * Removed queue walk, fixed for 64bitness. + * Deepak Saxena: + * Independent queues per IOP + * Support for dynamic device creation/deletion + * Code cleanup + * Support for larger I/Os through merge* functions + * (taken from DAC960 driver) * - * Fixes: - * Steve Ralston: Multiple device handling error fixes, - * Added a queue depth. - * Alan Cox: FC920 has an rmw bug. Dont or in the - * end marker. - * Removed queue walk, fixed for 64bitness. * To do: - * Multiple majors * Serial number scanning to find duplicates for FC multipathing - * Set the new max_sectors according to max message size - * Use scatter gather chains for bigger I/O sizes */ #include @@ -47,8 +52,11 @@ #include #include +#include #include #include +#include +#include #define MAJOR_NR I2O_MAJOR @@ -56,9 +64,44 @@ #define MAX_I2OB 16 -#define MAX_I2OB_DEPTH 32 +#define MAX_I2OB_DEPTH 128 #define MAX_I2OB_RETRIES 4 +//#define DRIVERDEBUG +#ifdef DRIVERDEBUG +#define DEBUG( s ) +#else +#define DEBUG( s ) printk( s ) +#endif + +/* + * Events that this OSM is interested in + */ +#define I2OB_EVENT_MASK I2O_EVT_IND_BSA_VOLUME_LOAD | \ + I2O_EVT_IND_BSA_VOLUME_UNLOAD | \ + I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \ + I2O_EVT_IND_BSA_CAPACITY_CHANGE + + +/* + * I2O Block Error Codes - should be in a header file really... + */ +#define I2O_BSA_DSC_SUCCESS 0x0000 +#define I2O_BSA_DSC_MEDIA_ERROR 0x0001 +#define I2O_BSA_DSC_ACCESS_ERROR 0x0002 +#define I2O_BSA_DSC_DEVICE_FAILURE 0x0003 +#define I2O_BSA_DSC_DEVICE_NOT_READY 0x0004 +#define I2O_BSA_DSC_MEDIA_NOT_PRESENT 0x0005 +#define I2O_BSA_DSC_MEDIA_LOCKED 0x0006 +#define I2O_BSA_DSC_MEDIA_FAILURE 0x0007 +#define I2O_BSA_DSC_PROTOCOL_FAILURE 0x0008 +#define I2O_BSA_DSC_BUS_FAILURE 0x0009 +#define I2O_BSA_DSC_ACCESS_VIOLATION 0x000A +#define I2O_BSA_DSC_WRITE_PROTECTED 0x000B +#define I2O_BSA_DSC_DEVICE_RESET 0x000C +#define I2O_BSA_DSC_VOLUME_CHANGED 0x000D +#define I2O_BSA_DSC_TIMEOUT 0x000E + /* * Some of these can be made smaller later */ @@ -71,14 +114,20 @@ static int i2ob_context; +/* + * I2O Block device descriptor + */ struct i2ob_device { struct i2o_controller *controller; struct i2o_device *i2odev; + int unit; int tid; int flags; int refcnt; struct request *head, *tail; + request_queue_t *req_queue; + int max_segments; int done_flag; }; @@ -87,53 +136,81 @@ * We should cache align these to avoid ping-ponging lines on SMP * boxes under heavy I/O load... */ - struct i2ob_request { struct i2ob_request *next; struct request *req; int num; -}; +} __cacheline_aligned; +/* + * Per IOP requst queue information + * + * We have a separate requeust_queue_t per IOP so that a heavilly + * loaded I2O block device on an IOP does not starve block devices + * across all I2O controllers. + * + */ +struct i2ob_iop_queue +{ + atomic_t queue_depth; + struct i2ob_request request_queue[MAX_I2OB_DEPTH]; + struct i2ob_request *i2ob_qhead; + request_queue_t req_queue; +}; +static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS] = {NULL}; /* * Each I2O disk is one of these. */ static struct i2ob_device i2ob_dev[MAX_I2OB<<4]; -static int i2ob_devices = 0; +static int i2ob_dev_count = 0; static struct hd_struct i2ob[MAX_I2OB<<4]; static struct gendisk i2ob_gendisk; /* Declared later */ -static atomic_t queue_depth; /* For flow control later on */ -static struct i2ob_request i2ob_queue[MAX_I2OB_DEPTH+1]; -static struct i2ob_request *i2ob_qhead; +/* + * Mutex and spin lock for event handling synchronization + * evt_msg contains the last event. + */ +DECLARE_MUTEX(i2ob_evt_sem); +static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED; +static unsigned int evt_msg[MSG_FRAME_SIZE>>2]; +DECLARE_WAIT_QUEUE_HEAD(i2ob_evt_wait); static struct timer_list i2ob_timer; static int i2ob_timer_started = 0; -#define DEBUG( s ) -/* #define DEBUG( s ) printk( s ) - */ - +static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *, + struct i2o_message *); +static void i2ob_new_device(struct i2o_controller *, struct i2o_device *); +static void i2ob_del_device(struct i2o_controller *, struct i2o_device *); +static void i2ob_reboot_event(void); static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int); static void i2ob_end_request(struct request *); -static void i2ob_request(request_queue_t * q); +static void i2ob_request(request_queue_t *); +static int i2ob_init_iop(unsigned int); +static request_queue_t* i2ob_get_queue(kdev_t); +static int i2ob_query_device(struct i2ob_device *, int, int, void*, int); +static int do_i2ob_revalidate(kdev_t, int); +static int i2ob_evt(void *); + +static int evt_pid = 0; +static int evt_running = 0; /* - * Dump messages. + * I2O OSM registration structure...keeps getting bigger and bigger :) */ -static void i2ob_dump_msg(struct i2ob_device *dev,u32 *msg,int size) +static struct i2o_handler i2o_block_handler = { - int cnt; - - printk(KERN_INFO "\n\ni2o message:\n"); - for (cnt = 0; cntreq; struct buffer_head *bh = req->bh; int count = req->nr_sectors<<9; + char *last = NULL; + unsigned short size = 0; + // printk(KERN_INFO "i2ob_send called\n"); /* Map the message to a virtual address */ msg = c->mem_offset + m; /* - * Build the message based on the request. + * Build the message based on the request. */ __raw_writel(i2ob_context|(unit<<8), msg+8); __raw_writel(ireq->num, msg+12); @@ -184,18 +264,26 @@ __raw_writel(1<<16, msg+16); while(bh!=NULL) { - /* - * Its best to do this in one not or it in - * later. mptr is in PCI space so fast to write - * sucky to read. - */ - if(bh->b_reqnext) - __raw_writel(0x10000000|(bh->b_size), mptr); + if(bh->b_data == last) { + size += bh->b_size; + last += bh->b_size; + if(bh->b_reqnext) + __raw_writel(0x14000000|(size), mptr-8); + else + __raw_writel(0xD4000000|(size), mptr-8); + } else - __raw_writel(0xD0000000|(bh->b_size), mptr); - - __raw_writel(virt_to_bus(bh->b_data), mptr+4); - mptr+=8; + { + if(bh->b_reqnext) + __raw_writel(0x10000000|(bh->b_size), mptr); + else + __raw_writel(0xD0000000|(bh->b_size), mptr); + __raw_writel(virt_to_bus(bh->b_data), mptr+4); + mptr += 8; + size = bh->b_size; + last = bh->b_data + size; + } + count -= bh->b_size; bh = bh->b_reqnext; } @@ -203,22 +291,41 @@ else if(req->cmd == WRITE) { __raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); - __raw_writel(1<<16, msg+16); + /* + * Allow replies to come back once data is cached in the controller + * This allows us to handle writes quickly thus giving more of the + * queue to reads. + */ + __raw_writel(0x00000010, msg+16); while(bh!=NULL) { - if(bh->b_reqnext) - __raw_writel(0x14000000|(bh->b_size), mptr); + if(bh->b_data == last) { + size += bh->b_size; + last += bh->b_size; + if(bh->b_reqnext) + __raw_writel(0x14000000|(size), mptr-8); + else + __raw_writel(0xD4000000|(size), mptr-8); + } else - __raw_writel(0xD4000000|(bh->b_size), mptr); + { + if(bh->b_reqnext) + __raw_writel(0x14000000|(bh->b_size), mptr); + else + __raw_writel(0xD4000000|(bh->b_size), mptr); + __raw_writel(virt_to_bus(bh->b_data), mptr+4); + mptr += 8; + size = bh->b_size; + last = bh->b_data + size; + } + count -= bh->b_size; - __raw_writel(virt_to_bus(bh->b_data), mptr+4); - mptr+=8; bh = bh->b_reqnext; } } __raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg); - if(req->current_nr_sectors > 8) + if(req->current_nr_sectors > i2ob_max_sectors[unit]) printk("Gathered sectors %ld.\n", req->current_nr_sectors); @@ -228,7 +335,7 @@ } i2o_post_message(c,m); - atomic_inc(&queue_depth); + atomic_inc(&i2ob_queues[c->unit]->queue_depth); return 0; } @@ -239,17 +346,18 @@ * must hold the lock. */ -static inline void i2ob_unhook_request(struct i2ob_request *ireq) +static inline void i2ob_unhook_request(struct i2ob_request *ireq, + unsigned int iop) { - ireq->next = i2ob_qhead; - i2ob_qhead = ireq; + ireq->next = i2ob_queues[iop]->i2ob_qhead; + i2ob_queues[iop]->i2ob_qhead = ireq; } /* * Request completion handler */ -static void i2ob_end_request(struct request *req) +static inline void i2ob_end_request(struct request *req) { /* * Loop until all of the buffers that are linked @@ -257,19 +365,74 @@ * unlocked. */ -// printk("ending request %p: ", req); - while (end_that_request_first( req, !req->errors, "i2o block" )) - { -// printk(" +\n"); - } + while (end_that_request_first( req, !req->errors, "i2o block" )); /* * It is now ok to complete the request. */ - -// printk("finishing "); end_that_request_last( req ); -// printk("done\n"); +} + +/* + * Request merging functions + */ +static inline int i2ob_new_segment(request_queue_t *q, struct request *req, + int __max_segments) +{ + int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments; + + if (__max_segments < max_segments) + max_segments = __max_segments; + + if (req->nr_segments < max_segments) { + req->nr_segments++; + q->elevator.nr_segments++; + return 1; + } + return 0; +} + +static int i2ob_back_merge(request_queue_t *q, struct request *req, + struct buffer_head *bh, int __max_segments) +{ + if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data) + return 1; + return i2ob_new_segment(q, req, __max_segments); +} + +static int i2ob_front_merge(request_queue_t *q, struct request *req, + struct buffer_head *bh, int __max_segments) +{ + if (bh->b_data + bh->b_size == req->bh->b_data) + return 1; + return i2ob_new_segment(q, req, __max_segments); +} + +static int i2ob_merge_requests(request_queue_t *q, + struct request *req, + struct request *next, + int __max_segments) +{ + int max_segments = i2ob_dev[MINOR(req->rq_dev)].max_segments; + int total_segments = req->nr_segments + next->nr_segments; + int same_segment; + + if (__max_segments < max_segments) + max_segments = __max_segments; + + same_segment = 0; + if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) + { + total_segments--; + same_segment = 1; + } + + if (total_segments > max_segments) + return 0; + + q->elevator.nr_segments -= same_segment; + req->nr_segments = total_segments; + return 1; } @@ -280,136 +443,253 @@ static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) { unsigned long flags; - struct i2ob_request *ireq; + struct i2ob_request *ireq = NULL; u8 st; u32 *m = (u32 *)msg; u8 unit = (m[2]>>8)&0xF0; /* low 4 bits are partition */ - + struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)]; + + /* + * FAILed message + */ if(m[0] & (1<<13)) { - printk("IOP fail.\n"); - printk("From %d To %d Cmd %d.\n", - (m[1]>>12)&0xFFF, - m[1]&0xFFF, - m[1]>>24); - printk("Failure Code %d.\n", m[4]>>24); - if(m[4]&(1<<16)) - printk("Format error.\n"); - if(m[4]&(1<<17)) - printk("Path error.\n"); - if(m[4]&(1<<18)) - printk("Path State.\n"); - if(m[4]&(1<<18)) - printk("Congestion.\n"); - - m=(u32 *)bus_to_virt(m[7]); - printk("Failing message is %p.\n", m); - - /* We need to up the request failure count here and maybe - abort it */ - ireq=&i2ob_queue[m[3]]; + /* + * FAILed message from controller + * We increment the error count and abort it + * + * In theory this will never happen. The I2O block class + * speficiation states that block devices never return + * FAILs but instead use the REQ status field...but + * better be on the safe side since no one really follows + * the spec to the book :) + */ + ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; + ireq->req->errors++; + + spin_lock_irqsave(&io_request_lock, flags); + i2ob_unhook_request(ireq, c->unit); + i2ob_end_request(ireq->req); + spin_unlock_irqrestore(&io_request_lock, flags); + /* Now flush the message by making it a NOP */ m[0]&=0x00FFFFFF; m[0]|=(I2O_CMD_UTIL_NOP)<<24; i2o_post_message(c,virt_to_bus(m)); - + + return; } - else + + if(msg->function == I2O_CMD_UTIL_EVT_REGISTER) + { + spin_lock(&i2ob_evt_lock); + memcpy(&evt_msg, m, msg->size); + spin_unlock(&i2ob_evt_lock); + wake_up_interruptible(&i2ob_evt_wait); + return; + } + + if(!dev->i2odev) { - if(m[2]&0x40000000) - { - int * ptr = (int *)m[3]; - if(m[4]>>24) - *ptr = -1; - else - *ptr = 1; - return; - } /* - * Lets see what is cooking. We stuffed the - * request in the context. + * This is HACK, but Intel Integrated RAID allows user + * to delete a volume that is claimed, locked, and in use + * by the OS. We have to check for a reply from a + * non-existent device and flag it as an error or the system + * goes kaput... */ + ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; + ireq->req->errors++; + printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n"); + spin_lock_irqsave(&io_request_lock, flags); + i2ob_unhook_request(ireq, c->unit); + i2ob_end_request(ireq->req); + spin_unlock_irqrestore(&io_request_lock, flags); + return; + } + + /* + * Lets see what is cooking. We stuffed the + * request in the context. + */ - ireq=&i2ob_queue[m[3]]; - st=m[4]>>24; - - if(st!=0) - { - printk(KERN_ERR "i2ob: error %08X\n", m[4]); - ireq->req->errors++; - if (ireq->req->errors < MAX_I2OB_RETRIES) - { - u32 retry_msg; - struct i2ob_device *dev; + ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; + st=m[4]>>24; - printk(KERN_ERR "i2ob: attempting retry %d for request %p\n",ireq->req->errors+1,ireq->req); - - /* - * Get a message for this retry. - */ - dev = &i2ob_dev[(unit&0xF0)]; - retry_msg = i2ob_get(dev); + if(st!=0) + { + char *bsa_errors[] = + { + "Success", + "Media Error", + "Failure communicating to device", + "Device Failure", + "Device is not ready", + "Media not present", + "Media is locked by another user", + "Media has failed", + "Failure communicating to device", + "Device bus failure", + "Device is locked by another user", + "Device is write protected", + "Device has reset", + "Volume has changed, waiting for acknowledgement" + }; + + printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, + bsa_errors[m[4]&0XFFFF]); + if(m[4]&0x00FF0000) + printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF ); + printk("\n"); - /* - * If we cannot get a message then - * forget the retry and fail the - * request. Note that since this is - * being called from the interrupt - * handler, a request has just been - * completed and there will most likely - * be space on the inbound message - * fifo so this won't happen often. - */ - if(retry_msg!=0xFFFFFFFF) - { - /* - * Decrement the queue depth since - * this request has completed and - * it will be incremented again when - * i2ob_send is called below. - */ - atomic_dec(&queue_depth); - - /* - * Send the request again. - */ - i2ob_send(retry_msg, dev,ireq,i2ob[unit].start_sect, (unit&0xF0)); - /* - * Don't fall through. - */ - return; - } - } - } - else - ireq->req->errors = 0; + ireq->req->errors++; } - + else + ireq->req->errors = 0; + /* * Dequeue the request. We use irqsave locks as one day we * may be running polled controllers from a BH... */ spin_lock_irqsave(&io_request_lock, flags); - i2ob_unhook_request(ireq); + i2ob_unhook_request(ireq, c->unit); i2ob_end_request(ireq->req); - + atomic_dec(&i2ob_queues[c->unit]->queue_depth); + /* * We may be able to do more I/O */ - - atomic_dec(&queue_depth); - i2ob_request(NULL); + i2ob_request(dev->req_queue); + spin_unlock_irqrestore(&io_request_lock, flags); } -static struct i2o_handler i2o_block_handler = +/* + * Event handler. Needs to be a separate thread b/c we may have + * to do things like scan a partition table, or query parameters + * which cannot be done from an interrupt or from a bottom half. + */ +static int i2ob_evt(void *dummy) { - i2o_block_reply, - "I2O Block OSM", - 0, - I2O_CLASS_RANDOM_BLOCK_STORAGE -}; + unsigned int evt; + unsigned int flags; + int unit; + int i; + + lock_kernel(); + exit_files(current); + daemonize(); + unlock_kernel(); + + strcpy(current->comm, "i2oblock"); + evt_running = 1; + + while(1) + { + interruptible_sleep_on(&i2ob_evt_wait); + if(signal_pending(current)) { + evt_running = 0; + return 0; + } + + printk(KERN_INFO "Doing something in i2o_block event thread\n"); + + /* + * Keep another CPU/interrupt from overwriting the + * message while we're reading it + * + * We stuffed the unit in the TxContext and grab the event mask + * None of the BSA we care about events have EventData + */ + spin_lock_irqsave(&i2ob_evt_lock, flags); + unit = evt_msg[3]; + evt = evt_msg[4]; + spin_unlock_irqrestore(&i2ob_evt_lock, flags); + + switch(evt) + { + /* + * New volume loaded on same TID, so we just re-install. + * The TID/controller don't change as it is the same + * I2O device. It's just new media that we have to + * rescan. + */ + case I2O_EVT_IND_BSA_VOLUME_LOAD: + { + i2ob_install_device(i2ob_dev[unit].i2odev->controller, + i2ob_dev[unit].i2odev, unit); + break; + } + + /* + * No media, so set all parameters to 0 and set the media + * change flag. The I2O device is still valid, just doesn't + * have media, so we don't want to clear the controller or + * device pointer. + */ + case I2O_EVT_IND_BSA_VOLUME_UNLOAD: + { + for(i = unit; i <= unit+15; i++) + { + i2ob_sizes[i] = 0; + i2ob_hardsizes[i] = 0; + i2ob_max_sectors[i] = 0; + i2ob[i].nr_sects = 0; + i2ob_gendisk.part[i].nr_sects = 0; + } + i2ob_media_change_flag[unit] = 1; + break; + } + + case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ: + printk(KERN_WARNING "%s: Attempt to eject locked media\n", + i2ob_dev[unit].i2odev->dev_name); + break; + + /* + * The capacity has changed and we are going to be + * updating the max_sectors and other information + * about this disk. We try a revalidate first. If + * the block device is in use, we don't want to + * do that as there may be I/Os bound for the disk + * at the moment. In that case we read the size + * from the device and update the information ourselves + * and the user can later force a partition table + * update through an ioctl. + */ + case I2O_EVT_IND_BSA_CAPACITY_CHANGE: + { + u64 size; + + if(do_i2ob_revalidate(MKDEV(MAJOR_NR, unit),0) != -EBUSY) + continue; + + if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 ) + i2ob_query_device(&i2ob_dev[unit], 0x0000, 4, &size, 8); + + spin_lock_irqsave(&io_request_lock, flags); + i2ob_sizes[unit] = (int)(size>>10); + i2ob_gendisk.part[unit].nr_sects = size>>9; + i2ob[unit].nr_sects = (int)(size>>9); + spin_unlock_irqrestore(&io_request_lock, flags); + break; + } + + /* + * An event we didn't ask for. Call the card manufacturer + * and tell them to fix their firmware :) + */ + default: + printk(KERN_INFO "%s: Received event we didn't register for\n" + KERN_INFO " Call I2O card manufacturer\n", + i2ob_dev[unit].i2odev->dev_name); + break; + } + }; + + return 0; +} /* * The timer handler will attempt to restart requests @@ -418,7 +698,7 @@ * had no more room in its inbound fifo. */ -static void i2ob_timer_handler(unsigned long dummy) +static void i2ob_timer_handler(unsigned long q) { unsigned long flags; @@ -437,7 +717,7 @@ /* * Restart any requests. */ - i2ob_request(NULL); + i2ob_request((request_queue_t*)q); /* * Free the lock. @@ -452,8 +732,7 @@ * on us. We must unlink CURRENT in this routine before we return, if * we use it. */ - -static void i2ob_request(request_queue_t * q) +static void i2ob_request(request_queue_t *q) { struct request *req; struct i2ob_request *ireq; @@ -461,26 +740,30 @@ struct i2ob_device *dev; u32 m; - while (!QUEUE_EMPTY) { + // printk(KERN_INFO "i2ob_request() called with queue %p\n", q); + + while (!list_empty(&q->queue_head)) { /* * On an IRQ completion if there is an inactive * request on the queue head it means it isnt yet * ready to dispatch. */ - if(CURRENT->rq_status == RQ_INACTIVE) + req = blkdev_entry_next_request(&q->queue_head); + + if(req->rq_status == RQ_INACTIVE) return; - /* - * Queue depths probably belong with some kind of - * generic IOP commit control. Certainly its not right - * its global! + unit = MINOR(req->rq_dev); + dev = &i2ob_dev[(unit&0xF0)]; + + /* + * Queue depths probably belong with some kind of + * generic IOP commit control. Certainly its not right + * its global! */ - if(atomic_read(&queue_depth)>=MAX_I2OB_DEPTH) + if(atomic_read(&i2ob_queues[dev->unit]->queue_depth)>=MAX_I2OB_DEPTH) break; - req = CURRENT; - unit = MINOR(req->rq_dev); - dev = &i2ob_dev[(unit&0xF0)]; /* Get a message */ m = i2ob_get(dev); @@ -506,6 +789,7 @@ * 500ms. */ i2ob_timer.expires = jiffies + (HZ >> 1); + i2ob_timer.data = (unsigned int)q; /* * Start it. @@ -514,68 +798,79 @@ add_timer(&i2ob_timer); } } + + /* + * Everything ok, so pull from kernel queue onto our queue + */ req->errors = 0; - blkdev_dequeue_request(req); + blkdev_dequeue_request(req); req->sem = NULL; - - ireq = i2ob_qhead; - i2ob_qhead = ireq->next; + + ireq = i2ob_queues[dev->unit]->i2ob_qhead; + i2ob_queues[dev->unit]->i2ob_qhead = ireq->next; ireq->req = req; i2ob_send(m, dev, ireq, i2ob[unit].start_sect, (unit&0xF0)); } } + /* * SCSI-CAM for ioctl geometry mapping * Duplicated with SCSI - this should be moved into somewhere common * perhaps genhd ? + * + * LBA -> CHS mapping table taken from: + * + * "Incorporating the I2O Architecture into BIOS for Intel Architecture + * Platforms" + * + * This is an I2O document that is only available to I2O members, + * not developers. + * + * From my understanding, this is how all the I2O cards do this + * + * Disk Size | Sectors | Heads | Cylinders + * ---------------+---------+-------+------------------- + * 1 < X <= 528M | 63 | 16 | X/(63 * 16 * 512) + * 528M < X <= 1G | 63 | 32 | X/(63 * 32 * 512) + * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512) + * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512) + * */ - +#define BLOCK_SIZE_528M 1081344 +#define BLOCK_SIZE_1G 2097152 +#define BLOCK_SIZE_21G 4403200 +#define BLOCK_SIZE_42G 8806400 +#define BLOCK_SIZE_84G 17612800 + static void i2o_block_biosparam( unsigned long capacity, unsigned short *cyls, unsigned char *hds, unsigned char *secs) { - unsigned long heads, sectors, cylinders, temp; + unsigned long heads, sectors, cylinders; - cylinders = 1024L; /* Set number of cylinders to max */ - sectors = 62L; /* Maximize sectors per track */ - - temp = cylinders * sectors; /* Compute divisor for heads */ - heads = capacity / temp; /* Compute value for number of heads */ - if (capacity % temp) { /* If no remainder, done! */ - heads++; /* Else, increment number of heads */ - temp = cylinders * heads; /* Compute divisor for sectors */ - sectors = capacity / temp; /* Compute value for sectors per - track */ - if (capacity % temp) { /* If no remainder, done! */ - sectors++; /* Else, increment number of sectors */ - temp = heads * sectors; /* Compute divisor for cylinders */ - cylinders = capacity / temp;/* Compute number of cylinders */ - } - } - /* if something went wrong, then apparently we have to return - a geometry with more than 1024 cylinders */ - if (cylinders == 0 || heads > 255 || sectors > 63 || cylinders >1023) - { - unsigned long temp_cyl; - + sectors = 63L; /* Maximize sectors per track */ + if(capacity <= BLOCK_SIZE_528M) + heads = 16; + else if(capacity <= BLOCK_SIZE_1G) + heads = 32; + else if(capacity <= BLOCK_SIZE_21G) heads = 64; - sectors = 32; - temp_cyl = capacity / (heads * sectors); - if (temp_cyl > 1024) - { - heads = 255; - sectors = 63; - } - cylinders = capacity / (heads * sectors); - } - *cyls = (unsigned int) cylinders; /* Stuff return values */ - *secs = (unsigned int) sectors; - *hds = (unsigned int) heads; -} + else if(capacity <= BLOCK_SIZE_42G) + heads = 128; + else + heads = 255; + + cylinders = capacity / (heads * sectors); + + *cyls = (unsigned short) cylinders; /* Stuff return values */ + *secs = (unsigned char) sectors; + *hds = (unsigned char) heads; +} + /* * Rescan the partition tables @@ -587,7 +882,7 @@ int i; minor&=0xF0; - + i2ob_dev[minor].refcnt++; if(i2ob_dev[minor].refcnt>maxu+1) { @@ -685,6 +980,21 @@ if (minor >= (MAX_I2OB<<4)) return -ENODEV; dev = &i2ob_dev[(minor&0xF0)]; + + /* + * This is to deail with the case of an application + * opening a device and then the device dissapears while + * it's in use, and then the application tries to release + * it. ex: Unmounting a deleted RAID volume at reboot. + * If we send messages, it will just cause FAILs since + * the TID no longer exists. + */ + if(!dev->i2odev) + return 0; + + /* Sync the device so we don't get errors */ + fsync_dev(inode->i_rdev); + if (dev->refcnt <= 0) printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt); dev->refcnt--; @@ -701,6 +1011,7 @@ msg[3] = (u32)query_done; msg[4] = 60<<16; i2o_post_wait(dev->controller, msg, 20, 2); + /* * Unlock the media */ @@ -714,7 +1025,7 @@ /* * Now unclaim the device. */ - if (i2o_release_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)<0) + if (i2o_release_device(dev->i2odev, &i2o_block_handler)) printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); } @@ -737,22 +1048,21 @@ if (minor >= MAX_I2OB<<4) return -ENODEV; dev=&i2ob_dev[(minor&0xF0)]; - if(dev->i2odev == NULL) + + if(!dev->i2odev) return -ENODEV; - + if(dev->refcnt++==0) { u32 msg[6]; - int *query_done; - - if(i2o_claim_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)<0) + if(i2o_claim_device(dev->i2odev, &i2o_block_handler)) { dev->refcnt--; + printk(KERN_INFO "I2O Block: Could not open device\n"); return -EBUSY; } - query_done = &dev->done_flag; /* * Mount the media if needed. Note that we don't use * the lock bit. Since we have to issue a lock if it @@ -761,18 +1071,15 @@ */ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; msg[4] = -1; msg[5] = 0; i2o_post_wait(dev->controller, msg, 24, 2); + /* * Lock the media */ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x40000000; - msg[3] = (u32)query_done; msg[4] = -1; i2o_post_wait(dev->controller, msg, 20, 2); } @@ -807,10 +1114,15 @@ int i; /* + * For logging purposes... + */ + printk(KERN_INFO "i2ob: Installing tid %d device at unit %d\n", + d->lct_data.tid, unit); + + /* * Ask for the current media data. If that isn't supported * then we ask for the device capacity data */ - if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0 || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) { @@ -822,23 +1134,35 @@ i2ob_query_device(dev, 0x0000, 6, &status, 4); i2ob_sizes[unit] = (int)(size>>10); i2ob_hardsizes[unit] = blocksize; + i2ob_gendisk.part[unit].nr_sects = size>>9; + i2ob[unit].nr_sects = (int)(size>>9); - limit=4096; /* 8 deep scatter gather */ + /* Set limit based on inbound frame size */ + limit = (d->controller->status_block->inbound_frame_size - 8)/2; + limit = limit<<9; - printk("Byte limit is %d.\n", limit); + /* + * Max number of Scatter-Gather Elements + */ + i2ob_dev[unit].max_segments = + (d->controller->status_block->inbound_frame_size - 8)/2; + + printk(KERN_INFO "Max Segments set to %d\n", + i2ob_dev[unit].max_segments); + printk(KERN_INFO "Byte limit is %d.\n", limit); for(i=unit;i<=unit+15;i++) - i2ob_max_sectors[i]=(limit>>9); - - i2ob[unit].nr_sects = (int)(size>>9); + { + i2ob_max_sectors[i]=MAX_SECTORS; + i2ob_dev[i].max_segments = + (d->controller->status_block->inbound_frame_size - 8)/2; + } i2ob_query_device(dev, 0x0000, 0, &type, 1); sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4)); - printk("%s: ", d->dev_name); - if(status&(1<<10)) - printk("RAID "); + printk(KERN_INFO "%s: ", d->dev_name); switch(type) { case 0: printk("Disk Storage");break; @@ -848,13 +1172,15 @@ default: printk("Type %d", type); } + if(status&(1<<10)) + printk("(RAID)"); if(((flags & (1<<3)) && !(status & (1<<3))) || ((flags & (1<<4)) && !(status & (1<<4)))) { - printk(" Not loaded.\n"); - return 0; + printk(KERN_INFO " Not loaded.\n"); + return 1; } - printk(" %dMb, %d byte sectors", + printk("- %dMb, %d byte sectors", (int)(size>>20), blocksize); if(status&(1<<0)) { @@ -867,12 +1193,91 @@ printk(", %dKb cache", cachesize); } printk(".\n"); - printk("%s: Maximum sectors/read set to %d.\n", + printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", d->dev_name, i2ob_max_sectors[unit]); + + /* + * If this is the first I2O block device found on this IOP, + * we need to initialize all the queue data structures + * before any I/O can be performed. If it fails, this + * device is useless. + */ + if(!i2ob_queues[c->unit]) { + if(i2ob_init_iop(c->unit)) + return 1; + } + + /* + * This will save one level of lookup/indirection in critical + * code so that we can directly get the queue ptr from the + * device instead of having to go the IOP data structure. + */ + dev->req_queue = &i2ob_queues[c->unit]->req_queue; + grok_partitions(&i2ob_gendisk, unit>>4, 1<<4, (long)(size>>9)); + + /* + * Register for the events we're interested in and that the + * device actually supports. + */ + i2o_event_register(c, d->lct_data.tid, i2ob_context, unit, + (I2OB_EVENT_MASK & d->lct_data.event_capabilities)); + + return 0; +} + +/* + * Initialize IOP specific queue structures. This is called + * once for each IOP that has a block device sitting behind it. + */ +static int i2ob_init_iop(unsigned int unit) +{ + int i; + + i2ob_queues[unit] = (struct i2ob_iop_queue*) + kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC); + if(!i2ob_queues[unit]) + { + printk(KERN_WARNING + "Could not allocate request queue for I2O block device!\n"); + return -1; + } + + for(i = 0; i< MAX_I2OB_DEPTH; i++) + { + i2ob_queues[unit]->request_queue[i].next = + &i2ob_queues[unit]->request_queue[i+1]; + i2ob_queues[unit]->request_queue[i].num = i; + } + + /* Queue is MAX_I2OB + 1... */ + i2ob_queues[unit]->request_queue[i].next = NULL; + i2ob_queues[unit]->i2ob_qhead = &i2ob_queues[unit]->request_queue[0]; + atomic_set(&i2ob_queues[unit]->queue_depth, 0); + + blk_init_queue(&i2ob_queues[unit]->req_queue, i2ob_request); + blk_queue_headactive(&i2ob_queues[unit]->req_queue, 0); + i2ob_queues[unit]->req_queue.back_merge_fn = i2ob_back_merge; + i2ob_queues[unit]->req_queue.front_merge_fn = i2ob_front_merge; + i2ob_queues[unit]->req_queue.merge_requests_fn = i2ob_merge_requests; + i2ob_queues[unit]->req_queue.queuedata = &i2ob_queues[unit]; + return 0; } +/* + * Get the request queue for the given device. + */ +static request_queue_t* i2ob_get_queue(kdev_t dev) +{ + int unit = MINOR(dev)&0xF0; + + return i2ob_dev[unit].req_queue; +} + +/* + * Probe the I2O subsytem for block class devices + */ static void i2ob_probe(void) { int i; @@ -889,12 +1294,20 @@ for(d=c->devices;d!=NULL;d=d->next) { - if(d->lct_data->class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE) + if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE) continue; - if(d->lct_data->user_tid != 0xFFF) + if(d->lct_data.user_tid != 0xFFF) continue; + if(i2o_claim_device(d, &i2o_block_handler)) + { + printk(KERN_WARNING "i2o_block: Controller %d, TID %d\n", c->unit, + d->lct_data.tid); + printk(KERN_WARNING "\tDevice refused claim! Skipping installation\n"); + continue; + } + if(uniti2odev = d; dev->controller = c; - dev->tid = d->lct_data->tid; - - /* - * Insure the device can be claimed - * before installing it. - */ - if(i2o_claim_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY )==0) + dev->unit = c->unit; + dev->tid = d->lct_data.tid; + + if(i2ob_install_device(c,d,unit)) + printk(KERN_WARNING "Could not install I2O block device\n"); + else { - printk(KERN_INFO "Claimed Dev %p Tid %d Unit %d\n",dev,dev->tid,unit); - i2ob_install_device(c,d,unit); - unit+=16; - - /* - * Now that the device has been - * installed, unclaim it so that - * it can be claimed by either - * the block or scsi driver. - */ - if(i2o_release_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)) - printk(KERN_INFO "Could not unclaim Dev %p Tid %d\n",dev,dev->tid); + unit+=16; + i2ob_dev_count++; + + /* We want to know when device goes away */ + i2o_device_notify_on(d, &i2o_block_handler); } - else - printk(KERN_INFO "TID %d not claimed\n",dev->tid); } else { if(!warned++) - printk("i2o_block: too many device, registering only %d.\n", unit>>4); + printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", unit>>4); } + i2o_release_device(d, &i2o_block_handler); } i2o_unlock_controller(c); } - i2ob_devices = unit; } /* - * Have we seen a media change ? + * New device notification handler. Called whenever a new + * I2O block storage device is added to the system. + * + * Should we spin lock around this to keep multiple devs from + * getting updated at the same time? + * */ +void i2ob_new_device(struct i2o_controller *c, struct i2o_device *d) +{ + struct i2ob_device *dev; + int unit = 0; + + printk(KERN_INFO "i2o_block: New device detected\n"); + printk(KERN_INFO " Controller %d Tid %d\n",c->unit, d->lct_data.tid); + + /* Check for available space */ + if(i2ob_dev_count>=MAX_I2OB<<4) + { + printk(KERN_ERR "i2o_block: No more devices allowed!\n"); + return; + } + for(unit = 0; unit < (MAX_I2OB<<4); unit += 16) + { + if(!i2ob_dev[unit].i2odev) + break; + } + + /* + * Creating a RAID 5 volume takes a little while and the UTIL_CLAIM + * will fail if we don't give the card enough time to do it's magic, + * so we just sleep for a little while and let it do it's thing + */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10*HZ); + + if(i2o_claim_device(d, &i2o_block_handler)) + { + printk(KERN_INFO + "i2o_block: Unable to claim device. Installation aborted\n"); + return; + } + + dev = &i2ob_dev[unit]; + dev->i2odev = d; + dev->controller = c; + dev->tid = d->lct_data.tid; + + if(i2ob_install_device(c,d,unit)) + printk(KERN_ERR "i2o_block: Could not install new device\n"); + else + { + i2ob_dev_count++; + i2o_device_notify_on(d, &i2o_block_handler); + } + + i2o_release_device(d, &i2o_block_handler); + return; +} + +/* + * Deleted device notification handler. Called when a device we + * are talking to has been deleted by the user or some other + * mysterious fource outside the kernel. + */ +void i2ob_del_device(struct i2o_controller *c, struct i2o_device *d) +{ + int unit = 0; + int i = 0; + int flags; + + spin_lock_irqsave(&io_request_lock, flags); + + /* + * Need to do this...we somtimes get two events from the IRTOS + * in a row and that causes lots of problems. + */ + i2o_device_notify_off(d, &i2o_block_handler); + + printk(KERN_INFO "I2O Block Device Deleted\n"); + + for(unit = 0; unit < MAX_I2OB<<4; unit += 16) + { + if(i2ob_dev[unit].i2odev == d) + { + printk(KERN_INFO " /dev/%s: Controller %d Tid %d\n", + d->dev_name, c->unit, d->lct_data.tid); + break; + } + } + if(unit >= MAX_I2OB<<4) + { + printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n"); + return; + } + + /* + * This will force errors when i2ob_get_queue() is called + * by the kenrel. + */ + i2ob_dev[unit].req_queue = NULL; + for(i = unit; i <= unit+15; i++) + { + i2ob_dev[i].i2odev = NULL; + i2ob_sizes[i] = 0; + i2ob_hardsizes[i] = 0; + i2ob_max_sectors[i] = 0; + i2ob[i].nr_sects = 0; + i2ob_gendisk.part[i].nr_sects = 0; + } + spin_unlock_irqrestore(&io_request_lock, flags); + + /* + * Sync the device...this will force all outstanding I/Os + * to attempt to complete, thus causing error messages. + * We have to do this as the user could immediatelly create + * a new volume that gets assigned the same minor number. + * If there are still outstanding writes to the device, + * that could cause data corruption on the new volume! + * + * The truth is that deleting a volume that you are currently + * accessing will do _bad things_ to your system. This + * handler will keep it from crashing, but must probably + * you'll have to do a 'reboot' to get the system running + * properly. Deleting disks you are using is dumb. + * Umount them first and all will be good! + * + * It's not this driver's job to protect the system from + * dumb user mistakes :) + */ + if(i2ob_dev[unit].refcnt) + fsync_dev(MKDEV(MAJOR_NR,unit)); + + /* + * Decrease usage count for module + */ + while(i2ob_dev[unit].refcnt--) + MOD_DEC_USE_COUNT; + + i2ob_dev[unit].refcnt = 0; + + i2ob_dev[i].tid = 0; + + /* + * Do we need this? + * The media didn't really change...the device is just gone + */ + i2ob_media_change_flag[unit] = 1; + + i2ob_dev_count--; + + return; +} + +/* + * Have we seen a media change ? + */ static int i2ob_media_change(kdev_t dev) { int i=MINOR(dev); @@ -960,12 +1517,14 @@ return do_i2ob_revalidate(dev, 0); } -static int i2ob_reboot_event(struct notifier_block *n, unsigned long code, void *p) +/* + * Reboot notifier. This is called by i2o_core when the system + * shuts down. + */ +static void i2ob_reboot_event(void) { int i; - if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF) - return NOTIFY_DONE; for(i=0;irefcnt!=0) { /* - * Flush the onboard cache on power down - * also unlock the media + * Flush the onboard cache */ u32 msg[5]; int *query_done = &dev->done_flag; @@ -984,6 +1542,7 @@ msg[3] = (u32)query_done; msg[4] = 60<<16; i2o_post_wait(dev->controller, msg, 20, 2); + /* * Unlock the media */ @@ -995,25 +1554,18 @@ i2o_post_wait(dev->controller, msg, 20, 2); } } - return NOTIFY_DONE; } -struct notifier_block i2ob_reboot_notifier = -{ - i2ob_reboot_event, - NULL, - 0 -}; - static struct block_device_operations i2ob_fops = { - open: i2ob_open, - release: i2ob_release, - ioctl: i2ob_ioctl, - check_media_change: i2ob_media_change, - revalidate: i2ob_revalidate, + open: i2ob_open, + release: i2ob_release, + ioctl: i2ob_ioctl, + check_media_change: i2ob_media_change, + revalidate: i2ob_revalidate, }; - + + static struct gendisk i2ob_gendisk = { MAJOR_NR, @@ -1027,6 +1579,7 @@ NULL }; + /* * And here should be modules and kernel interface * (Just smiley confuses emacs :-) @@ -1040,19 +1593,20 @@ { int i; - printk(KERN_INFO "I2O Block Storage OSM v0.07. (C) 1999 Red Hat Software.\n"); + printk(KERN_INFO "I2O Block Storage OSM v0.9\n"); + printk(KERN_INFO " (c) Copyright 1999, 2000 Red Hat Software.\n"); /* * Register the block device interfaces */ if (register_blkdev(MAJOR_NR, "i2o_block", &i2ob_fops)) { - printk("Unable to get major number %d for i2o_block\n", + printk(KERN_ERR "Unable to get major number %d for i2o_block\n", MAJOR_NR); return -EIO; } #ifdef MODULE - printk("i2o_block: registered device at major %d\n", MAJOR_NR); + printk(KERN_INFO "i2o_block: registered device at major %d\n", MAJOR_NR); #endif /* @@ -1063,6 +1617,7 @@ hardsect_size[MAJOR_NR] = i2ob_hardsizes; blk_size[MAJOR_NR] = i2ob_sizes; max_sectors[MAJOR_NR] = i2ob_max_sectors; + blk_dev[MAJOR_NR].queue = i2ob_get_queue; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request); blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); @@ -1082,17 +1637,11 @@ /* * Set up the queue */ - - for(i = 0; i< MAX_I2OB_DEPTH; i++) + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) { - i2ob_queue[i].next = &i2ob_queue[i+1]; - i2ob_queue[i].num = i; + i2ob_queues[i] = NULL; } - - /* Queue is MAX_I2OB + 1... */ - i2ob_queue[i].next = NULL; - i2ob_qhead = &i2ob_queue[0]; - + /* * Timers */ @@ -1115,15 +1664,26 @@ i2ob_context = i2o_block_handler.context; /* - * Finally see what is actually plugged in to our controllers + * Initialize event handling thread */ + init_MUTEX_LOCKED(&i2ob_evt_sem); + evt_pid = kernel_thread(i2ob_evt, NULL, CLONE_SIGHAND); + if(evt_pid < 0) + { + printk(KERN_ERR + "i2o_block: Could not initialize event thread. Aborting\n"); + i2o_remove_handler(&i2o_block_handler); + return 0; + } + /* + * Finally see what is actually plugged in to our controllers + */ for (i = 0; i < MAX_I2OB; i++) register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4, &i2ob_fops, 0); i2ob_probe(); - register_reboot_notifier(&i2ob_reboot_notifier); return 0; } @@ -1136,8 +1696,21 @@ void cleanup_module(void) { struct gendisk **gdp; + int i; - unregister_reboot_notifier(&i2ob_reboot_notifier); + /* + * Unregister for updates from any devices..otherwise we still + * get them and the core jumps to random memory :O + */ + if(i2ob_dev_count) { + struct i2o_device *d; + for(i = 0; i < MAX_I2OB; i++) + if((d=i2ob_dev[i<<4].i2odev)) { + i2o_device_notify_off(d, &i2o_block_handler); + i2o_event_register(d->controller, d->lct_data.tid, + i2ob_context, i<<4, 0); + } + } /* * Flush the OSM @@ -1150,6 +1723,21 @@ */ if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0) printk("i2o_block: cleanup_module failed\n"); + + if(evt_running) { + i = kill_proc(evt_pid, SIGTERM, 1); + if(!i) { + int count = 5 * 100; + while(evt_running && --count) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + + if(!count) + printk(KERN_ERR "Giving up on i2oblock thread...\n"); + } + } + /* * Why isnt register/unregister gendisk in the kernel ??? diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c --- v2.3.99-pre5/linux/drivers/i2o/i2o_config.c Thu Feb 10 17:11:09 2000 +++ linux/drivers/i2o/i2o_config.c Fri Apr 21 16:08:52 2000 @@ -85,11 +85,21 @@ { u32 *msg = (u32 *)m; - if (msg[0] & (1<<13)) + if (msg[0] & MSG_FAIL) { + u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]); + printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n"); - - if (msg[4] >> 24) // RegStatus != SUCCESS - i2o_report_status(KERN_INFO,"i2o_config",msg); + + /* Release the preserved msg frame by resubmitting it as a NOP */ + + preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; + preserved_msg[2] = 0; + i2o_post_message(c, msg[7]); + } + + if (msg[4] >> 24) // ReqStatus != SUCCESS + i2o_report_status(KERN_INFO,"i2o_config", msg); if(m->function == I2O_CMD_UTIL_EVT_REGISTER) { @@ -166,6 +176,9 @@ struct i2o_handler cfg_handler= { i2o_cfg_reply, + NULL, + NULL, + NULL, "Configuration", 0, 0xffffffff // All classes @@ -409,14 +422,14 @@ return -ENOMEM; } - len = i2o_issue_params(i2o_cmd, c, kcmd.tid, - ops, kcmd.oplen, res, 65536); - i2o_unlock_controller(c); + len = i2o_issue_params(i2o_cmd, c, kcmd.tid, + ops, kcmd.oplen, res, 65536); + i2o_unlock_controller(c); kfree(ops); if (len < 0) { kfree(res); - return len; /* -DetailedStatus */ + return -EAGAIN; } put_user(len, kcmd.reslen); @@ -749,7 +762,7 @@ /* Device exists? */ for(d = iop->devices; d; d = d->next) - if(d->lct_data->tid == kdesc.tid) + if(d->lct_data.tid == kdesc.tid) break; if(!d) @@ -903,7 +916,7 @@ #endif { printk(KERN_INFO "I2O configuration manager v 0.04.\n"); - printk(KERN_INFO " (C) Copyright 1999 Red Hat Software"); + printk(KERN_INFO " (C) Copyright 1999 Red Hat Software\n"); if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c --- v2.3.99-pre5/linux/drivers/i2o/i2o_core.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/i2o/i2o_core.c Fri Apr 21 16:08:52 2000 @@ -2,7 +2,7 @@ * Core I2O structure managment * * (C) Copyright 1999 Red Hat Software - * + * * Written by Alan Cox, Building Number Three Ltd * * This program is free software; you can redistribute it and/or @@ -12,12 +12,13 @@ * * A lot of the I2O message side code from this is taken from the * Red Creek RCPCI45 adapter driver by Red Creek Communications - * + * * Fixes by: * Philipp Rumpf * Juha Sievänen * Auvo Häkkinen * Deepak Saxena + * */ #include @@ -31,51 +32,73 @@ #include #include #include +#include #include #include +#include #include +#include +#include +#include +#include #include +#include #include "i2o_lan.h" // #define DRIVERDEBUG -// #define DEBUG_IRQ -#define dprintk(x) +#ifdef DRIVERDEBUG +#define dprintk(s, args...) printk(s, ## args) +#else +#define dprintk(s, args...) +#endif -/* - * Size of the I2O module table - */ - -static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES]; -static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS]; -struct i2o_controller *i2o_controller_chain; +/* OSM table */ +static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES] = {NULL}; + +/* Controller list */ +static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS] = {NULL}; +struct i2o_controller *i2o_controller_chain = NULL; int i2o_num_controllers = 0; + +/* Initiator Context for Core message */ static int core_context = 0; -static int i2o_activate_controller(struct i2o_controller *iop); -static int i2o_online_controller(struct i2o_controller *c); -static int i2o_init_outbound_q(struct i2o_controller *c); +/* Initialization && shutdown functions */ +static void i2o_sys_init(void); +static void i2o_sys_shutdown(void); +static int i2o_clear_controller(struct i2o_controller *); +static int i2o_reboot_event(struct notifier_block *, unsigned long , void *); +static int i2o_online_controller(struct i2o_controller *); +static int i2o_init_outbound_q(struct i2o_controller *); +static int i2o_post_outbound_messages(struct i2o_controller *); +static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32); + +/* Reply handler */ static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *, struct i2o_message *); -static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *); -static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *); -void i2o_dump_message(u32 *msg); - -static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32); -static int i2o_reset_controller(struct i2o_controller *); +/* Various helper functions */ static int i2o_lct_get(struct i2o_controller *); +static int i2o_lct_notify(struct i2o_controller *); static int i2o_hrt_get(struct i2o_controller *); -static void i2o_sys_init(void); -static void i2o_sys_shutdown(void); - static int i2o_build_sys_table(void); static int i2o_systab_send(struct i2o_controller *c); +/* I2O core event handler */ +static int i2o_core_evt(void *); +static int evt_pid; +static int evt_running; + +/* Dynamic LCT update handler */ +static int i2o_dyn_lct(void *); + +void i2o_report_controller_unit(struct i2o_controller *, struct i2o_device *); + /* * I2O System Table. Contains information about * all the IOPs in the system. Used to inform IOPs @@ -126,65 +149,154 @@ static spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED; static void i2o_post_wait_complete(u32, int); -/* Message handler */ +/* OSM descriptor handler */ static struct i2o_handler i2o_core_handler = { (void *)i2o_core_reply, + NULL, + NULL, + NULL, "I2O core layer", - 0 + 0, + I2O_CLASS_EXECUTIVE }; /* - * I2O configuration spinlock. This isnt a big deal for contention - * so we have one only + * Used when queing a reply to be handled later + */ +struct reply_info +{ + struct i2o_controller *iop; + u32 msg[MSG_FRAME_SIZE]; +}; +static struct reply_info evt_reply; +static struct reply_info events[I2O_EVT_Q_LEN]; +static int evt_in = 0; +static int evt_out = 0; +static int evt_q_len = 0; +#define MODINC(x,y) (x = x++ % y) + +/* + * I2O configuration spinlock. This isnt a big deal for contention + * so we have one only */ - static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED; +/* + * Event spinlock. Used to keep event queue sane and from + * handling multiple events simultaneously. + */ +static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED; + +/* + * Semaphore used to syncrhonize event handling thread with + * interrupt handler. + */ +DECLARE_MUTEX(evt_sem); +DECLARE_WAIT_QUEUE_HEAD(evt_wait); + +static struct notifier_block i2o_reboot_notifier = +{ + i2o_reboot_event, + NULL, + 0 +}; + + /* * I2O Core reply handler - * - * Only messages this should see are i2o_post_wait() replies */ void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) { u32 *msg=(u32 *)m; - int status; + u32 status; u32 context = msg[2]; #if 0 i2o_report_status(KERN_INFO, "i2o_core", msg); #endif - + if (msg[0] & (1<<13)) // Fail bit is set - { - printk(KERN_ERR "%s: Failed to process the msg:\n",c->name); - printk(KERN_ERR " Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n", - (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & - 0xFFF); - printk(KERN_ERR " FailureCode = 0x%02X\n Severity = 0x%02X\n" - "LowestVersion = 0x%02X\n HighestVersion = 0x%02X\n", - msg[4] >> 24, (msg[4] >> 16) & 0xFF, - (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); - printk(KERN_ERR " FailingHostUnit = 0x%04X\n FailingIOP = 0x%03X\n", - msg[5] >> 16, msg[5] & 0xFFF); - return; - } + { + u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]); + +// i2o_report_failure(KERN_INFO, c, "i2o_core", msg); + printk(KERN_ERR "%s: Failed to process the msg:\n", c->name); + printk(KERN_ERR " Cmd = 0x%02X, InitiatorTid = %d, TargetTid =% d\n", + (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); + printk(KERN_ERR " FailureCode = 0x%02X\n Severity = 0x%02X\n" + "LowestVersion = 0x%02X\n HighestVersion = 0x%02X\n", + msg[4] >> 24, (msg[4] >> 16) & 0xFF, + (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); + printk(KERN_ERR " FailingHostUnit = 0x%04X\n FailingIOP = 0x%03X\n", + msg[5] >> 16, msg[5] & 0xFFF); + + /* If the failed request needs special treatment, + * it should be done here. */ + + /* Release the preserved msg by resubmitting it as a NOP */ + + preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; + preserved_msg[2] = 0; + i2o_post_message(c, msg[7]); + + /* If reply to i2o_post_wait failed, return causes a timeout */ + return; + } if(msg[2]&0x80000000) // Post wait message { if (msg[4] >> 24) { - i2o_report_status(KERN_WARNING, "i2o_core: post_wait reply", msg); + i2o_report_status(KERN_INFO, "i2o_core: post_wait reply", msg); status = -(msg[4] & 0xFFFF); } else status = I2O_POST_WAIT_OK; i2o_post_wait_complete(context, status); + return; + } + + if(m->function == I2O_CMD_UTIL_EVT_REGISTER) + { + memcpy(events[evt_in].msg, msg, MSG_FRAME_SIZE); + events[evt_in].iop = c; + + spin_lock(&i2o_evt_lock); + MODINC(evt_in, I2O_EVT_Q_LEN); + if(evt_q_len == I2O_EVT_Q_LEN) + MODINC(evt_out, I2O_EVT_Q_LEN); + else + evt_q_len++; + spin_unlock(&i2o_evt_lock); + + up(&evt_sem); + wake_up_interruptible(&evt_wait); + return; + } + + if(m->function == I2O_CMD_LCT_NOTIFY) + { + up(&c->lct_sem); + return; } + + /* + * If this happens, we want to dump the message to the syslog so + * it can be sent back to the card manufacturer by the end user + * to aid in debugging. + * + */ + printk(KERN_WARNING "%s: Unsolicited message reply sent to core!" + "Message dumped to syslog\n", + c->name); + i2o_dump_message(msg); + + return; } /* @@ -218,8 +330,9 @@ /* - * Each I2O controller has a chain of devices on it - these match - * the useful parts of the LCT of the board. + * Each I2O controller has a chain of devices on it. + * Each device has a pointer to it's LCT entry to be used + * for fun purposes. */ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) @@ -245,19 +358,43 @@ int __i2o_delete_device(struct i2o_device *d) { struct i2o_device **p; + int i; p=&(d->controller->devices); /* * Hey we have a driver! + * Check to see if the driver wants us to notify it of + * device deletion. If it doesn't we assume that it + * is unsafe to delete a device with an owner and + * fail. */ - if(d->owner) - return -EBUSY; + { + if(d->owner->dev_del_notify) + { + dprintk(KERN_INFO "Device has owner, notifying\n"); + d->owner->dev_del_notify(d->controller, d); + if(d->owner) + { + printk(KERN_WARNING + "Driver \"%s\" did not release device!\n", d->owner->name); + return -EBUSY; + } + } + else + return -EBUSY; + } /* - * Seek, locate + * Tell any other users who are talking to this device + * that it's going away. We assume that everything works. */ + for(i=0; i < I2O_MAX_MANAGERS; i++) + { + if(d->managers[i] && d->managers[i]->dev_del_notify) + d->managers[i]->dev_del_notify(d->controller, d); + } while(*p!=NULL) { @@ -282,6 +419,10 @@ spin_lock(&i2o_configuration_lock); + /* + * Seek, locate + */ + ret = __i2o_delete_device(d); spin_unlock(&i2o_configuration_lock); @@ -302,12 +443,18 @@ if(i2o_controllers[i]==NULL) { i2o_controllers[i]=c; + c->devices = NULL; c->next=i2o_controller_chain; i2o_controller_chain=c; c->unit = i; - + c->page_frame = NULL; + c->hrt = NULL; + c->lct = NULL; + c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL); + c->status_block = NULL; sprintf(c->name, "i2o/iop%d", i); i2o_num_controllers++; + init_MUTEX_LOCKED(&c->lct_sem); spin_unlock(&i2o_configuration_lock); return 0; } @@ -322,12 +469,21 @@ struct i2o_controller **p; int users; char name[16]; + int stat; + + dprintk(KERN_INFO "Deleting controller iop%d\n", c->unit); + + /* + * Clear event registration as this can cause weird behavior + */ + if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) + i2o_event_register(c, core_context, 0, 0, 0); spin_lock(&i2o_configuration_lock); if((users=atomic_read(&c->users))) { - printk(KERN_INFO "%s busy: %d users for controller.\n", c->name, users); - c->bus_disable(c); + dprintk(KERN_INFO "I2O: %d users for controller iop%d\n", users, + c->name); spin_unlock(&i2o_configuration_lock); return -EBUSY; } @@ -336,20 +492,40 @@ if(__i2o_delete_device(c->devices)<0) { /* Shouldnt happen */ - c->bus_disable(c); + c->bus_disable(c); spin_unlock(&i2o_configuration_lock); return -EBUSY; } } + /* + * If this is shutdown time, the thread's already been killed + */ + if(c->lct_running) { + stat = kill_proc(c->lct_pid, SIGTERM, 1); + if(!stat) { + int count = 10 * 100; + while(c->lct_running && --count) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + + if(!count) + printk(KERN_ERR + "%s: LCT thread still running!\n", + c->name); + } + } + p=&i2o_controller_chain; while(*p) { if(*p==c) { - /* Ask the IOP to switch into RESET state */ - i2o_reset_controller(c); + /* Ask the IOP to switch to HOLD state */ + if (i2o_clear_controller(c) < 0) + printk(KERN_ERR "Unable to clear iop%d\n", c->unit); /* Release IRQ */ c->destructor(c); @@ -365,14 +541,15 @@ kfree(c->lct); if(c->status_block) kfree(c->status_block); + if(c->dlct) + kfree(c->dlct); i2o_controllers[c->unit]=NULL; memcpy(name, c->name, strlen(c->name)+1); kfree(c); - i2o_num_controllers--; + dprintk(KERN_INFO "%s: Deleted from controller chain.\n", name); - dprintk((KERN_INFO "%s: Deleted from controller chain.\n", name)); - + i2o_num_controllers--; return 0; } p=&((*p)->next); @@ -404,105 +581,86 @@ /* - * Claim a device for use as either the primary user or just - * as a management/secondary user + * Claim a device for use by an OSM */ -int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h, u32 type) +int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h) { - /* Device already has a primary user or too many managers */ - if((type == I2O_CLAIM_PRIMARY && d->owner) || - (d->num_managers == I2O_MAX_MANAGERS)) - { - return -EBUSY; - } - - if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, type)) + spin_lock(&i2o_configuration_lock); + if(d->owner) { + printk(KERN_INFO "issue claim called, but dev as owner!"); + spin_unlock(&i2o_configuration_lock); return -EBUSY; } - spin_lock(&i2o_configuration_lock); - if(d->owner) + if(i2o_issue_claim(d->controller,d->lct_data.tid, h->context, 1, + I2O_CLAIM_PRIMARY)) { spin_unlock(&i2o_configuration_lock); return -EBUSY; } - atomic_inc(&d->controller->users); - - if(type == I2O_CLAIM_PRIMARY) - d->owner=h; - else - if (i2o_add_management_user(d, h)) - printk(KERN_WARNING "i2o: Too many managers for TID %d\n", - d->lct_data->tid); - + d->owner=h; spin_unlock(&i2o_configuration_lock); return 0; } -int i2o_release_device(struct i2o_device *d, struct i2o_handler *h, u32 type) +/* + * Release a device that the OS is using + */ +int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) { int err = 0; spin_lock(&i2o_configuration_lock); - - /* Primary user */ - if(type == I2O_CLAIM_PRIMARY) + if(d->owner != h) { - if(d->owner != h) - err = -ENOENT; - else - { - if(i2o_issue_claim(d->controller, d->lct_data->tid, h->context, 0, - type)) - { - err = -ENXIO; - } - else - { - d->owner = NULL; - atomic_dec(&d->controller->users); - } - } - spin_unlock(&i2o_configuration_lock); - return err; - } + return -ENOENT; + } - /* Management or other user */ - if(i2o_remove_management_user(d, h)) - err = -ENOENT; - else + if(i2o_issue_claim(d->controller, d->lct_data.tid, h->context, 0, + I2O_CLAIM_PRIMARY)) { - atomic_dec(&d->controller->users); - - if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 0, - type)) - err = -ENXIO; + err = -ENXIO; } + d->owner = NULL; + spin_unlock(&i2o_configuration_lock); return err; } -int i2o_add_management_user(struct i2o_device *d, struct i2o_handler *h) +/* + * Called by OSMs to let the core know that they want to be + * notified if the given device is deleted from the system. + */ +int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h) { int i; if(d->num_managers == I2O_MAX_MANAGERS) - return 1; + return -ENOSPC; for(i = 0; i < I2O_MAX_MANAGERS; i++) + { if(!d->managers[i]) + { d->managers[i] = h; + break; + } + } d->num_managers++; return 0; } -int i2o_remove_management_user(struct i2o_device *d, struct i2o_handler *h) +/* + * Called by OSMs to let the core know that they no longer + * are interested in the fate of the given device. + */ +int i2o_device_notify_off(struct i2o_device *d, struct i2o_handler *h) { int i; @@ -511,6 +669,7 @@ if(d->managers[i] == h) { d->managers[i] = NULL; + d->num_managers--; return 0; } } @@ -519,6 +678,304 @@ } /* + * Event registration API + */ +int i2o_event_register(struct i2o_controller *c, u32 tid, + u32 init_context, u32 tr_context, u32 evt_mask) +{ + u32 msg[5]; // Not performance critical, so we just + // i2o_post_this it instead of building it + // in IOP memory + + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | tid; + msg[2] = (u32)init_context; + msg[3] = (u32)tr_context; + msg[4] = evt_mask; + + return i2o_post_this(c, msg, sizeof(msg)); +} + +/* + * Event ack API + * + * We just take a pointer to the original UTIL_EVENT_REGISTER reply + * message and change the function code since that's what spec + * describes an EventAck message looking like. + */ +int i2o_event_ack(struct i2o_controller *c, u32 *msg) +{ + struct i2o_message *m = (struct i2o_message *)msg; + + m->function = I2O_CMD_UTIL_EVT_ACK; + + return i2o_post_wait(c, msg, m->size * 4, 2); +} + +/* + * Core event handler. Runs as a separate thread and is woken + * up whenever there is an Executive class event. + */ +static int i2o_core_evt(void *reply_data) +{ + struct reply_info *reply = (struct reply_info *) reply_data; + u32 *msg = reply->msg; + struct i2o_controller *c = NULL; + int flags; + + lock_kernel(); + exit_files(current); + daemonize(); + unlock_kernel(); + + strcpy(current->comm, "i2oevtd"); + evt_running = 1; + + while(1) + { + down_interruptible(&evt_sem); + if(signal_pending(current)) + { + dprintk(KERN_INFO "I2O event thread dead\n"); + evt_running = 0; + return 0; + } + + /* + * Copy the data out of the queue so that we don't have to lock + * around the whole function and just around the qlen update + */ + spin_lock_irqsave(&i2o_evt_lock, flags); + memcpy(reply, &events[evt_out], sizeof(struct reply_info)); + MODINC(evt_out, I2O_EVT_Q_LEN); + evt_q_len--; + spin_unlock_irqrestore(&i2o_evt_lock, flags); + + c = reply->iop; + dprintk(KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4]); + + /* + * We do not attempt to delete/quiesce/etc. the controller if + * some sort of error indidication occurs. We may want to do + * so in the future, but for now we just let the user deal with + * it. One reason for this is that what to do with an error + * or when to send what ærror is not really agreed on, so + * we get errors that may not be fatal but just look like they + * are...so let the user deal with it. + */ + switch(msg[4]) + { + case I2O_EVT_IND_EXEC_RESOURCE_LIMITS: + printk(KERN_ERR "iop%d: Out of resources\n", c->unit); + break; + + case I2O_EVT_IND_EXEC_POWER_FAIL: + printk(KERN_ERR "iop%d: Power failure\n", c->unit); + break; + + case I2O_EVT_IND_EXEC_HW_FAIL: + { + char *fail[] = + { + "Unknown Error", + "Power Lost", + "Code Violation", + "Parity Error", + "Code Execution Exception", + "Watchdog Timer Expired" + }; + + if(msg[5] <= 6) + printk(KERN_ERR "%s: Hardware Failure: %s\n", + c->name, fail[msg[5]]); + else + printk(KERN_ERR "%s: Unknown Hardware Failure\n", c->name); + + break; + } + + /* + * New device created + * - Create a new i2o_device entry + * - Inform all interested drivers about this device's existence + */ + case I2O_EVT_IND_EXEC_NEW_LCT_ENTRY: + { + struct i2o_device *d = (struct i2o_device *) + kmalloc(sizeof(struct i2o_device), GFP_KERNEL); + int i; + + memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry)); + + d->next = NULL; + d->controller = c; + d->flags = 0; + + i2o_report_controller_unit(c, d); + i2o_install_device(c,d); + + for(i = 0; i < MAX_I2O_MODULES; i++) + { + if(i2o_handlers[i] && + i2o_handlers[i]->new_dev_notify && + (i2o_handlers[i]->class&d->lct_data.class_id)) + i2o_handlers[i]->new_dev_notify(c,d); + } + + break; + } + + /* + * LCT entry for a device has been modified, so update it + * internally. + */ + case I2O_EVT_IND_EXEC_MODIFIED_LCT: + { + struct i2o_device *d; + i2o_lct_entry *new_lct = (i2o_lct_entry *)&msg[5]; + + for(d = c->devices; d; d = d->next) + { + if(d->lct_data.tid == new_lct->tid) + { + memcpy(&d->lct_data, new_lct, sizeof(i2o_lct_entry)); + break; + } + } + break; + } + + case I2O_EVT_IND_CONFIGURATION_FLAG: + printk(KERN_WARNING "%s requires user configuration\n", c->name); + break; + + case I2O_EVT_IND_GENERAL_WARNING: + printk(KERN_WARNING "%s: Warning notification received!" + "Check configuration for errors!\n", c->name); + break; + + default: + printk(KERN_WARNING "%s: Unknown event (0x%08x)...check config\n", c->name, msg[4]); + break; + } + } + + return 0; +} + +/* + * Dynamic LCT update. This compares the LCT with the currently + * installed devices to check for device deletions..this needed b/c there + * is no DELETED_LCT_ENTRY EventIndicator for the Executive class so + * we can't just have the event handler do this...annoying + * + * This is a hole in the spec that will hopefully be fixed someday. + */ +static int i2o_dyn_lct(void *foo) +{ + struct i2o_controller *c = (struct i2o_controller *)foo; + struct i2o_device *d = NULL; + struct i2o_device *d1 = NULL; + int i = 0; + int found = 0; + int entries; + void *tmp; + char name[16]; + + lock_kernel(); + exit_files(current); + daemonize(); + unlock_kernel(); + + sprintf(name, "iop%d_lctd", c->unit); + strcpy(current->comm, name); + + c->lct_running = 1; + + while(1) + { + down_interruptible(&c->lct_sem); + if(signal_pending(current)) + { + dprintk(KERN_ERR "%s: LCT thread dead\n", c->name); + c->lct_running = 0; + return 0; + } + + entries = c->dlct->table_size; + entries -= 3; + entries /= 9; + + dprintk(KERN_INFO "I2O: Dynamic LCT Update\n"); + dprintk(KERN_INFO "I2O: Dynamic LCT contains %d entries\n", entries); + + if(!entries) + { + printk(KERN_INFO "iop%d: Empty LCT???\n", c->unit); + continue; + } + + /* + * Loop through all the devices on the IOP looking for their + * LCT data in the LCT. We assume that TIDs are not repeated. + * as that is the only way to really tell. It's been confirmed + * by the IRTOS vendor(s?) that TIDs are not reused until they + * wrap arround(4096), and I doubt a system will up long enough + * to create/delete that many devices. + */ + for(d = c->devices; d; ) + { + found = 0; + d1 = d->next; + + for(i = 0; i < entries; i++) + { + if(d->lct_data.tid == c->dlct->lct_entry[i].tid) + { + found = 1; + break; + } + } + if(!found) + { + dprintk(KERN_INFO "Deleted device!\n"); + i2o_delete_device(d); + } + d = d1; + } + + /* + * Tell LCT to renotify us next time there is a change + */ + i2o_lct_notify(c); + + /* + * Copy new LCT into public LCT + * + * Possible race if someone is reading LCT while we are copying + * over it. If this happens, we'll fix it then. but I doubt that + * the LCT will get updated often enough or will get read by + * a user often enough to worry. + */ + if(c->lct->table_size < c->dlct->table_size) + { + tmp = c->lct; + c->lct = kmalloc(c->dlct->table_size<<2, GFP_KERNEL); + if(!c->lct) + { + printk(KERN_ERR "%s: No memory for LCT!\n", c->name); + c->lct = tmp; + continue; + } + kfree(tmp); + } + memcpy(c->lct, c->dlct, c->dlct->table_size<<2); + } + + return 0; +} + +/* * This is called by the bus specific driver layer when an interrupt * or poll of this card interface is desired. */ @@ -527,41 +984,46 @@ { struct i2o_message *m; u32 mv; + u32 *msg; + int count = 0; -#ifdef DEBUG_IRQ - printk(KERN_INFO "%s: interrupt\n", c->name); -#endif - /* Sometimes we get here, but a message can't be read. Why? */ + /* + * Old 960 steppings had a bug in the I2O unit that caused + * the queue to appear empty when it wasn't. + */ if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF) mv=I2O_REPLY_READ32(c); - while (mv!=0xFFFFFFFF) + while(mv!=0xFFFFFFFF) { struct i2o_handler *i; m=(struct i2o_message *)bus_to_virt(mv); + msg=(u32*)m; + + count++; + /* * Temporary Debugging */ if(m->function==0x15) - printk("UTFR!\n"); - -#ifdef DEBUG_IRQ - i2o_dump_message((u32*)m); -#endif + printk(KERN_ERR "%s: UTFR!\n", c->name); i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)]; - if(i) + if(i && i->reply) i->reply(i,c,m); else { - printk("i2o: Spurious reply to handler %d\n", + printk(KERN_WARNING "I2O: Spurious reply to handler %d\n", m->initiator_context&(MAX_I2O_MODULES-1)); - i2o_dump_message((u32*)m); } i2o_flush_reply(c,mv); mb(); - mv=I2O_REPLY_READ32(c); - } + + /* That 960 bug again... */ + if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF) + mv=I2O_REPLY_READ32(c); + + } } @@ -643,8 +1105,8 @@ { if((jiffies-time)>=5*HZ) { - dprintk((KERN_ERR "%s: Timeout waiting for message frame (%s).\n", - c->name, why)); + dprintk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", + c->name, why); return 0xFFFFFFFF; } schedule(); @@ -667,8 +1129,8 @@ { if(jiffies-time >= timeout*HZ ) { - dprintk((KERN_ERR "%s: timeout waiting for %s reply.\n", - c->name, why)); + dprintk(KERN_ERR "%s: timeout waiting for %s reply.\n", + c->name, why); return 0xFFFFFFFF; } schedule(); @@ -676,37 +1138,60 @@ return m; } - /* * Dump the information block associated with a given unit (TID) */ -void i2o_report_controller_unit(struct i2o_controller *c, int unit) +void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d) { char buf[64]; + char str[22]; + int ret; + int unit = d->lct_data.tid; - if(i2o_query_scalar(c, unit, 0xF100, 3, buf, 16)>=0) + printk(KERN_INFO "Target ID %d.\n", unit); + + if((ret=i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))>=0) { buf[16]=0; - printk(KERN_INFO " Vendor: %s", buf); + printk(KERN_INFO " Vendor: %s\n", buf); } - if(i2o_query_scalar(c, unit, 0xF100, 4, buf, 16)>=0) + if((ret=i2o_query_scalar(c, unit, 0xF100, 4, buf, 16))>=0) { + buf[16]=0; - printk(" Device: %s", buf); + printk(KERN_INFO " Device: %s\n", buf); } #if 0 if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0) { buf[16]=0; - printk("Description: %s", buf); + printk(KERN_INFO " Description: %s\n", buf); } #endif - if(i2o_query_scalar(c, unit, 0xF100, 6, buf, 8)>=0) + if((ret=i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))>=0) { buf[8]=0; - printk(" Rev: %s\n", buf); + printk(KERN_INFO " Rev: %s\n", buf); } + + printk(KERN_INFO " Class: "); + sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id)); + printk("%s\n", str); + + printk(KERN_INFO " Subclass: 0x%04X\n", d->lct_data.sub_class); + printk(KERN_INFO " Flags: "); + + if(d->lct_data.device_flags&(1<<0)) + printk("C"); // ConfigDialog requested + if(d->lct_data.device_flags&(1<<1)) + printk("U"); // Multi-user capable + if(!(d->lct_data.device_flags&(1<<4))) + printk("P"); // Peer service enabled! + if(!(d->lct_data.device_flags&(1<<5))) + printk("M"); // Mgmt service enabled! + printk("\n"); + } @@ -723,20 +1208,21 @@ static int i2o_parse_hrt(struct i2o_controller *c) { #ifdef DRIVERDEBUG - u32 *rows=(u32 *)c->hrt; + u32 *rows=(u32*)c->hrt; u8 *p=(u8 *)c->hrt; u8 *d; int count; int length; int i; int state; - - if(p[3]!=0) { + + if(p[3]!=0) + { printk(KERN_ERR "%s: HRT table for controller is too new a version.\n", c->name); - return -1; + return -1; } - + count=p[0]|(p[1]<<8); length = p[2]; @@ -803,7 +1289,6 @@ printk("\n"); rows+=length; } - #endif return 0; } @@ -818,21 +1303,19 @@ int i; int max; int tid; - u32 *p; struct i2o_device *d; - char str[22]; i2o_lct *lct = c->lct; if (lct == NULL) { - printk(KERN_ERR "%s: LCT is empty???\n",c->name); + printk(KERN_ERR "%s: LCT is empty???\n", c->name); return -1; } - - max = lct->table_size; + + max = lct->table_size; max -= 3; max /= 9; - - printk(KERN_INFO "%s: LCT has %d entries.\n", c->name,max); + + printk(KERN_INFO "%s: LCT has %d entries.\n", c->name, max); if(lct->iop_flags&(1<<0)) printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name); @@ -849,35 +1332,14 @@ d->controller = c; d->next = NULL; - d->lct_data = &lct->lct_entry[i]; + memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); d->flags = 0; - tid = d->lct_data->tid; + tid = d->lct_data.tid; - printk(KERN_INFO "Target ID %d.\n", tid); - - i2o_report_controller_unit(c, tid); + i2o_report_controller_unit(c, d); i2o_install_device(c, d); - - printk(KERN_INFO " Class: "); - - sprintf(str, "%-21s", i2o_get_class_name(d->lct_data->class_id)); - printk("%s", str); - - printk(" Subclass: 0x%04X Flags: ", - d->lct_data->sub_class); - - if(d->lct_data->device_flags&(1<<0)) - printk("C"); // ConfigDialog requested - if(d->lct_data->device_flags&(1<<1)) - printk("M"); // Multi-user capable - if(!(d->lct_data->device_flags&(1<<4))) - printk("P"); // Peer service enabled! - if(!(d->lct_data->device_flags&(1<<5))) - printk("m"); // Mgmt service enabled! - printk("\n"); - p+=9; } return 0; } @@ -892,59 +1354,66 @@ u32 msg[4]; int ret; + i2o_status_get(c); + /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */ if ((c->status_block->iop_state != ADAPTER_STATE_READY) && - (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)) + (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)) { return 0; } - msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; - /* msg[2] filled in i2o_post_wait */ - msg[3]=0; + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; + msg[3] = 0; /* Long timeout needed for quiesce if lots of devices */ - if ((ret = i2o_post_wait(c, msg, sizeof(msg), 120))) - printk(KERN_INFO "%s: Unable to quiesce (status=%#10x).\n", + if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) + printk(KERN_INFO "%s: Unable to quiesce (status=%#10x).\n", c->name, ret); else - dprintk((KERN_INFO "%s: Quiesced.\n", c->name)); + dprintk(KERN_INFO "%s: Quiesced.\n", c->name); i2o_status_get(c); // Reread the Status Block - return ret; + return ret; + } -/* +/* * Enable IOP. Allows the IOP to resume external operations. */ int i2o_enable_controller(struct i2o_controller *c) { u32 msg[4]; int ret; + + i2o_status_get(c); + /* Enable only allowed on READY state */ + if(c->status_block->iop_state != ADAPTER_STATE_READY) + return -EINVAL; + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID; - /* msg[2] filled in i2o_post_wait */ - /* How long of a timeout do we need? */ + /* How long of a timeout do we need? */ if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) - printk(KERN_ERR "%s: Could not enable (status=%#10x).\n", + printk(KERN_ERR "%s: Could not enable (status=%#10x).\n", c->name, ret); else - dprintk((KERN_INFO "%s: Enabled.\n", c->name)); + dprintk(KERN_INFO "%s: Enabled.\n", c->name); i2o_status_get(c); return ret; } -/* - * Clear an IOP to HOLD state, ie. terminate external operations, clear all +/* + * Clear an IOP to HOLD state, ie. terminate external operations, clear all * input queues and prepare for a system restart. IOP's internal operation * continues normally and the outbound queue is alive. * IOP is not expected to rebuild its LCT. @@ -962,14 +1431,13 @@ msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID; - /* msg[2] filled in i2o_post_wait */ msg[3]=0; if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30))) - printk(KERN_INFO "%s: Unable to clear (status=%#10x).\n", + printk(KERN_INFO "%s: Unable to clear (status=%#10x).\n", c->name, ret); else - dprintk((KERN_INFO "%s: Cleared.\n",c->name)); + dprintk(KERN_INFO "%s: Cleared.\n",c->name); i2o_status_get(c); @@ -977,21 +1445,21 @@ for (iop = i2o_controller_chain; iop; iop = iop->next) if (iop != c) - i2o_enable_controller(iop); + i2o_enable_controller(iop); return ret; } -/* - * Reset the IOP into INIT state and wait until IOP gets into RESET state. - * Terminate all external operations, clear IOP's inbound and outbound - * queues, terminate all DDMs, and reload the IOP's operating environment +/* + * Reset the IOP into INIT state and wait until IOP gets into RESET state. + * Terminate all external operations, clear IOP's inbound and outbound + * queues, terminate all DDMs, and reload the IOP's operating environment * and all local DDMs. IOP rebuilds its LCT. */ static int i2o_reset_controller(struct i2o_controller *c) { - struct i2o_controller *iop; + struct i2o_controller *iop; u32 m; u8 *status; u32 *msg; @@ -1002,19 +1470,19 @@ for (iop = i2o_controller_chain; iop; iop = iop->next) i2o_quiesce_controller(iop); + /* Get a message */ m=i2o_wait_message(c, "AdapterReset"); if(m==0xFFFFFFFF) return -ETIMEDOUT; msg=(u32 *)(c->mem_offset+m); - - status = kmalloc(4,GFP_KERNEL); - if (status==NULL) { - printk(KERN_ERR "%s: IOP reset failed - no free memory.\n", - c->name); + + status=(void *)kmalloc(4, GFP_KERNEL); + if(status==NULL) { + printk(KERN_ERR "IOP reset failed - no free memory.\n"); return -ENOMEM; } - memset(status,0,4); - + memset(status, 0, 4); + msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; msg[2]=core_context; @@ -1028,11 +1496,11 @@ /* Wait for a reply */ time=jiffies; - while (status[0]==0) + while(status[0]==0) { - if((jiffies-time)>=5*HZ) + if((jiffies-time)>=20*HZ) { - printk(KERN_ERR "%s: IOP reset timeout.\n", c->name); + printk(KERN_ERR "IOP reset timeout.\n"); kfree(status); return -ETIMEDOUT; } @@ -1040,26 +1508,27 @@ barrier(); } - if (status[0]==0x01) - { + if (status[0]==0x01) + { /* * Once the reset is sent, the IOP goes into the INIT state * which is indeterminate. We need to wait until the IOP * has rebooted before we can let the system talk to * it. We read the inbound Free_List until a message is - * available. If we can't read one in the given amount of + * available. If we can't read one in the given ammount of * time, we assume the IOP could not reboot properly. */ + dprintk(KERN_INFO "Reset succeeded...waiting for reboot\n"); + time = jiffies; m = I2O_POST_READ32(c); while(m == 0XFFFFFFFF) { if((jiffies-time) >= 30*HZ) { - printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", + printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", c->name); - kfree(status); return -ETIMEDOUT; } schedule(); @@ -1069,7 +1538,7 @@ i2o_flush_reply(c,m); - dprintk((KERN_INFO "%s: Reset completed.\n", c->name)); + dprintk(KERN_INFO "%s: Reset completed.\n", c->name); } /* If IopReset was rejected or didn't perform reset, try IopClear */ @@ -1077,22 +1546,24 @@ i2o_status_get(c); if (status[0] == 0x02 || c->status_block->iop_state != ADAPTER_STATE_RESET) { - printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name); + printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name); i2o_clear_controller(c); - } /* Enable other IOPs */ for (iop = i2o_controller_chain; iop; iop = iop->next) if (iop != c) - i2o_enable_controller(iop); + i2o_enable_controller(iop); kfree(status); return 0; } +/* + * Get the status block for the IOP + */ int i2o_status_get(struct i2o_controller *c) { long time; @@ -1100,23 +1571,25 @@ u32 *msg; u8 *status_block; - if (c->status_block == NULL) { + if (c->status_block == NULL) + { c->status_block = (i2o_status_block *) - kmalloc(sizeof(i2o_status_block),GFP_KERNEL); + kmalloc(sizeof(i2o_status_block),GFP_KERNEL); if (c->status_block == NULL) { - printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", c->name); + printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", + c->name); return -ENOMEM; } } status_block = (u8*)c->status_block; memset(c->status_block,0,sizeof(i2o_status_block)); - + m=i2o_wait_message(c, "StatusGet"); if(m==0xFFFFFFFF) return -ETIMEDOUT; - + msg=(u32 *)(c->mem_offset+m); msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; @@ -1126,13 +1599,13 @@ msg[4]=0; msg[5]=0; msg[6]=virt_to_phys(c->status_block); - msg[7]=0; /* 64bit host FIXME */ + msg[7]=0; /* 64bit host FIXME */ msg[8]=sizeof(i2o_status_block); /* always 88 bytes */ i2o_post_message(c,m); /* Wait for a reply */ - + time=jiffies; while(status_block[87]!=0xFF) { @@ -1144,43 +1617,47 @@ schedule(); barrier(); } - + /* Ok the reply has arrived. Fill in the important stuff */ - c->inbound_size = c->status_block->inbound_frame_size *4; + c->inbound_size = (status_block[12]|(status_block[13]<<8))*4; #ifdef DRIVERDEBUG printk(KERN_INFO "%s: State = ", c->name); switch (c->status_block->iop_state) { - case 0x01: - printk("INIT\n"); + case 0x01: + printk("INIT\n"); break; - case 0x02: - printk("RESET\n"); + case 0x02: + printk("RESET\n"); break; - case 0x04: - printk("HOLD\n"); + case 0x04: + printk("HOLD\n"); break; - case 0x05: - printk("READY\n"); + case 0x05: + printk("READY\n"); break; - case 0x08: - printk("OPERATIONAL\n"); + case 0x08: + printk("OPERATIONAL\n"); break; - case 0x10: - printk("FAILED\n"); + case 0x10: + printk("FAILED\n"); break; - case 0x11: - printk("FAULTED\n"); + case 0x11: + printk("FAULTED\n"); break; - default: + default: printk("%x (unknown !!)\n",c->status_block->iop_state); - } -#endif +} +#endif return 0; } - +/* + * Get the Hardware Resource Table for the device. + * The HRT contains information about possible hidden devices + * but is mostly useless to us + */ int i2o_hrt_get(struct i2o_controller *c) { u32 msg[6]; @@ -1199,7 +1676,6 @@ msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; - /* msg[2] filled in i2o_post_wait */ msg[3]= 0; msg[4]= (0xD0000000 | size); /* Simple transaction */ msg[5]= virt_to_phys(c->hrt); /* Dump it here */ @@ -1222,51 +1698,49 @@ return 0; } +/* + * Send the I2O System Table to the specified IOP + * + * The system table contains information about all the IOPs in the + * system. It is build and then sent to each IOP so that IOPs can + * establish connections between each other. + * + */ static int i2o_systab_send(struct i2o_controller *iop) { - u32 msg[12]; - u32 privmem[2]; - u32 privio[2]; - int ret; - - /* See i2o_status_block */ -#if 0 - iop->status->current_mem_base; - iop->status->current_mem_size; - iop->status->current_io_base; - iop->status->current_io_size; -#endif + u32 msg[12]; + u32 privmem[2]; + u32 privio[2]; + int ret; -/* FIXME */ - privmem[0]=iop->priv_mem; /* Private memory space base address */ - privmem[1]=iop->priv_mem_size; - privio[0]=iop->priv_io; /* Private I/O address */ - privio[1]=iop->priv_io_size; + privmem[0] = iop->status_block->current_mem_base; + privmem[1] = iop->status_block->current_mem_size; + privio[0] = iop->status_block->current_io_base; + privio[1] = iop->status_block->current_io_size; msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; - msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; - /* msg[2] filled in i2o_post_wait */ + msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; msg[3] = 0; - msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */ - msg[5] = 0; /* Segment 0 */ + msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */ + msg[5] = 0; /* Segment 0 */ - /* - * Provide three SGL-elements: - * System table (SysTab), Private memory space declaration and - * Private i/o space declaration - */ - msg[6] = 0x54000000 | sys_tbl_len; - msg[7] = virt_to_phys(sys_tbl); - msg[8] = 0x54000000 | 0; - msg[9] = virt_to_phys(privmem); - msg[10] = 0xD4000000 | 0; - msg[11] = virt_to_phys(privio); + /* + * Provide three SGL-elements: + * System table (SysTab), Private memory space declaration and + * Private i/o space declaration + */ + msg[6] = 0x54000000 | sys_tbl_len; + msg[7] = virt_to_phys(sys_tbl); + msg[8] = 0x54000000 | 0; + msg[9] = virt_to_phys(privmem); + msg[10] = 0xD4000000 | 0; + msg[11] = virt_to_phys(privio); if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120))) printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n", iop->name, ret); else - dprintk((KERN_INFO "%s: SysTab set.\n", iop->name)); + dprintk(KERN_INFO "%s: SysTab set.\n", iop->name); return ret; @@ -1281,10 +1755,11 @@ printk(KERN_INFO "Activating I2O controllers\n"); printk(KERN_INFO "This may take a few minutes if there are many devices\n"); - + /* In INIT state, Activate IOPs */ - for (iop = i2o_controller_chain; iop; iop = niop) { + dprintk(KERN_INFO "Calling i2o_activate_controller for %s\n", + iop->name); niop = iop->next; i2o_activate_controller(iop); } @@ -1299,6 +1774,7 @@ * If build_sys_table fails, we kill everything and bail * as we can't init the IOPs w/o a system table */ + dprintk(KERN_INFO "calling i2o_build_sys_table\n"); if (i2o_build_sys_table() < 0) { i2o_sys_shutdown(); return; @@ -1307,11 +1783,30 @@ /* If IOP don't get online, we need to rebuild the System table */ for (iop = i2o_controller_chain; iop; iop = niop) { niop = iop->next; + dprintk(KERN_INFO "Calling i2o_online_controller for %s\n", iop->name); if (i2o_online_controller(iop) < 0) goto rebuild_sys_tab; } /* Active IOPs now in OPERATIONAL state */ + + /* + * Register for status updates from all IOPs + */ + for(iop = i2o_controller_chain; iop; iop=iop->next) { + + /* Create a kernel thread to deal with dynamic LCT updates */ + iop->lct_pid = kernel_thread(i2o_dyn_lct, iop, CLONE_SIGHAND); + + /* Update change ind on DLCT */ + iop->dlct->change_ind = iop->lct->change_ind; + + /* Start dynamic LCT updates */ + i2o_lct_notify(iop); + + /* Register for all events from IRTOS */ + i2o_event_register(iop, core_context, 0, 0, 0xFFFFFFFF); + } } /* @@ -1335,14 +1830,14 @@ */ int i2o_activate_controller(struct i2o_controller *iop) { - /* In INIT state, Wait Inbound Q to initilaize (in i2o_status_get) */ + /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ /* In READY state, Get status */ if (i2o_status_get(iop) < 0) { - printk("Unable to obtain status of IOP, attempting a reset.\n"); + printk(KERN_INFO "Unable to obtain status of IOP, attempting a reset.\n"); i2o_reset_controller(iop); if (i2o_status_get(iop) < 0) { - printk("IOP not responding.\n"); + printk(KERN_ERR "%s: IOP not responding.\n", iop->name); i2o_delete_controller(iop); return -1; } @@ -1354,13 +1849,18 @@ return -1; } -// if (iop->status_block->iop_state == ADAPTER_STATE_HOLD || if (iop->status_block->iop_state == ADAPTER_STATE_READY || iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || + iop->status_block->iop_state == ADAPTER_STATE_HOLD || iop->status_block->iop_state == ADAPTER_STATE_FAILED) { - dprintk((KERN_INFO "%s: already running...trying to reset\n", - iop->name)); + u32 m[MSG_FRAME_SIZE]; + dprintk(KERN_INFO "%s: already running...trying to reset\n", + iop->name); + + i2o_init_outbound_q(iop); + I2O_REPLY_WRITE32(iop,virt_to_phys(m)); + i2o_reset_controller(iop); if (i2o_status_get(iop) < 0 || @@ -1377,6 +1877,9 @@ return -1; } + if (i2o_post_outbound_messages(iop)) + return -1; + /* In HOLD state */ if (i2o_hrt_get(iop) < 0) { @@ -1387,6 +1890,7 @@ return 0; } + /* * Clear and (re)initialize IOP's outbound queue */ @@ -1396,8 +1900,8 @@ u32 m; u32 *msg; u32 time; - int i; + dprintk(KERN_INFO "%s: Initializing Outbound Queue\n", c->name); m=i2o_wait_message(c, "OutboundInit"); if(m==0xFFFFFFFF) return -ETIMEDOUT; @@ -1410,66 +1914,72 @@ return -ENOMEM; } memset(status, 0, 4); - - msg[0]= EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6; + + + msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6; msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID; msg[2]= core_context; - msg[3]= 0x0106; /* Transaction context */ - msg[4]= 4096; /* Host page frame size */ + msg[3]= 0x0106; /* Transaction context */ + msg[4]= 4096; /* Host page frame size */ /* Frame size is in words. Pick 128, its what everyone elses uses and - other sizes break some adapters. */ - msg[5]= (MSG_FRAME_SIZE>>2)<<16|0x80; /* Outbound msg frame size and Initcode */ - msg[6]= 0xD0000004; /* Simple SG LE, EOB */ + other sizes break some adapters. */ + msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */ + msg[6]= 0xD0000004; /* Simple SG LE, EOB */ msg[7]= virt_to_bus(status); i2o_post_message(c,m); - barrier(); + barrier(); time=jiffies; while(status[0]<0x02) { - if((jiffies-time)>=5*HZ) + if((jiffies-time)>=30*HZ) { if(status[0]==0x00) printk(KERN_ERR "%s: Ignored queue initialize request.\n", c->name); - else + else printk(KERN_ERR "%s: Outbound queue initialize timeout.\n", c->name); kfree(status); return -ETIMEDOUT; - } + } schedule(); barrier(); - } + } if(status[0] != I2O_CMD_OUTBOUND_INIT_COMPLETE) { - printk(KERN_ERR "%s: Outbound queue initialize rejected (%d).\n", - c->name, status[0]); + printk(KERN_ERR "%s: IOP outbound initialise failed.\n", c->name); kfree(status); - return -EINVAL; + return -ETIMEDOUT; } + + return 0; +} + +int i2o_post_outbound_messages(struct i2o_controller *c) +{ + int i; + u32 m; /* Alloc space for IOP's outbound queue message frames */ c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL); if(c->page_frame==NULL) { printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n", c->name); - kfree(status); return -ENOMEM; - } + } m=virt_to_phys(c->page_frame); - + /* Post frames */ for(i=0; i< NMBR_MSG_FRAMES; i++) { - I2O_REPLY_WRITE32(c,m); - mb(); + I2O_REPLY_WRITE32(c,m); + mb(); m += MSG_FRAME_SIZE; } - kfree(status); return 0; } @@ -1520,11 +2030,31 @@ return 0; } +/* + * Like above, but used for async notification. The main + * difference is that we keep track of the CurrentChangeIndiicator + * so that we only get updates when it actually changes. + * + */ +int i2o_lct_notify(struct i2o_controller *c) +{ + u32 msg[8]; + + msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; + msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = core_context; + msg[3] = 0xDEADBEEF; + msg[4] = 0xFFFFFFFF; /* All devices */ + msg[5] = c->dlct->change_ind+1; /* Next change */ + msg[6] = 0xD0000000|8192; + msg[7] = virt_to_bus(c->dlct); + return i2o_post_this(c, msg, sizeof(msg)); +} + /* * Bring a controller online into OPERATIONAL state. */ - int i2o_online_controller(struct i2o_controller *iop) { if (i2o_systab_send(iop) < 0) { @@ -1534,6 +2064,7 @@ /* In READY state */ + dprintk(KERN_INFO "Attempting to enable iop%d\n", iop->unit); if (i2o_enable_controller(iop) < 0) { i2o_delete_controller(iop); return -1; @@ -1541,6 +2072,7 @@ /* In OPERATIONAL state */ + dprintk(KERN_INFO "Attempting to get/parse lct iop%d\n", iop->unit); if (i2o_lct_get(iop) < 0){ i2o_delete_controller(iop); return -1; @@ -1549,9 +2081,18 @@ return 0; } +/* + * Build system table + * + * The system table contains information about all the IOPs in the + * system (duh) and is used by the Executives on the IOPs to establish + * peer2peer connections. We're not supporting peer2peer at the moment, + * but this will be needed down the road for things like lan2lan forwarding. + */ static int i2o_build_sys_table(void) { struct i2o_controller *iop = NULL; + struct i2o_controller *niop = NULL; int count = 0; sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs @@ -1563,7 +2104,7 @@ sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL); if(!sys_tbl) { - printk(KERN_CRIT "SysTab Set failed. Out of memory.\n"); + printk(KERN_CRIT "SysTab Set failed. Out of memory.\n"); return -ENOMEM; } memset((void*)sys_tbl, 0, sys_tbl_len); @@ -1572,12 +2113,23 @@ sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */ sys_tbl->change_ind = sys_tbl_ind++; - for(iop = i2o_controller_chain; iop; iop = iop->next) + for(iop = i2o_controller_chain; iop; iop = niop) { - // Get updated Status Block so we have the latest information - if (i2o_status_get(iop)) { + niop = iop->next; + + /* + * Get updated IOP state so we have the latest information + * + * We should delete the controller at this point if it + * doesn't respond since if it's not on the system table + * it is techninically not part of the I2O subsyßtem... + */ + if(i2o_status_get(iop)) { + printk(KERN_ERR "%s: Deleting b/c could not get status while" + "attempting to build system table", iop->name); + i2o_delete_controller(iop); sys_tbl->num_entries--; - continue; // try next one + continue; // try the next one } sys_tbl->iops[count].org_id = iop->status_block->org_id; @@ -1603,10 +2155,10 @@ #ifdef DRIVERDEBUG { - u32 *table = (u32*)sys_tbl; + u32 *table; + table = (u32*)sys_tbl; for(count = 0; count < (sys_tbl_len >>2); count++) - printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", - count, table[count]); + printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]); } #endif @@ -1641,18 +2193,19 @@ if(m==0xFFFFFFFF) { printk(KERN_ERR "%s: Timeout waiting for message frame!\n", - c->name); + c->name); return -ETIMEDOUT; } - msg = (u32 *)(c->mem_offset + m); - memcpy_toio(msg, data, len); + memcpy_toio(msg, data, len); i2o_post_message(c,m); return 0; } /* - * Post a message and wait for a response flag to be set. + * This core API allows an OSM to post a message and then be told whether + * or not the system received a successful reply. It is useful when + * the OSM does not want to know the exact 3 */ int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) { @@ -1677,15 +2230,28 @@ spin_unlock_irqrestore(&post_wait_lock, flags); wait_data->wq = &wq_i2o_post; - wait_data->status = -EAGAIN; - - msg[2]=0x80000000|(u32)core_context|((u32)wait_data->id<<16); + wait_data->status = -ETIMEDOUT; + msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16); + if ((status = i2o_post_this(c, msg, len))==0) { interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout); status = wait_data->status; - } + } + +#ifdef DRIVERDEBUG + if(status == -ETIMEDOUT) + printk(KERN_INFO "POST WAIT TIMEOUT\n"); +#endif + /* + * Remove the entry from the queue. + * Since i2o_post_wait() may have been called again by + * a different thread while we were waiting for this + * instance to complete, we're not guaranteed that + * this entry is at the head of the queue anymore, so + * we need to search for it, find it, and delete it. + */ p2 = NULL; spin_lock_irqsave(&post_wait_lock, flags); for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) { @@ -1694,6 +2260,7 @@ p2->next = p1->next; else post_wait_queue = p1->next; + break; } } @@ -1710,7 +2277,7 @@ */ static void i2o_post_wait_complete(u32 context, int status) { - struct i2o_post_wait_data *p1; + struct i2o_post_wait_data *p1 = NULL; /* * We need to search through the post_wait @@ -1728,60 +2295,21 @@ for(p1 = post_wait_queue; p1; p1 = p1->next) { if(p1->id == ((context >> 16) & 0x7fff)) { p1->status = status; - spin_unlock(&post_wait_lock); wake_up_interruptible(p1->wq); + spin_unlock(&post_wait_lock); return; } } spin_unlock(&post_wait_lock); - printk(KERN_DEBUG "i2o: i2o_post_wait reply after timeout!"); -} - -/* - * Send UTIL_EVENT messages - */ - -int i2o_event_register(struct i2o_controller *c, int tid, int context, - u32 evt_mask) -{ - u32 msg[5]; - - msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - msg[1] = I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | tid; - msg[2] = context; - msg[3] = 0; - msg[4] = evt_mask; - - if (i2o_post_this(c, msg, sizeof(msg)) < 0) - return -ETIMEDOUT; - - return 0; -} - -int i2o_event_ack(struct i2o_controller *c, int tid, int context, - u32 evt_indicator, void *evt_data, int evt_data_len) -{ - u32 msg[c->inbound_size]; - - msg[0] = I2O_MESSAGE_SIZE(5 + evt_data_len / 4) | SGL_OFFSET_5; - msg[1] = I2O_CMD_UTIL_EVT_ACK << 24 | HOST_TID << 12 | tid; - msg[2] = context; - msg[3] = 0; - msg[4] = evt_indicator; - memcpy(msg+5, evt_data, evt_data_len); - - if (i2o_post_this(c, msg, sizeof(msg)) < 0) - return -ETIMEDOUT; - - return 0; + printk(KERN_DEBUG "i2o_post_wait reply after timeout!\n"); } /* * Issue UTIL_CLAIM or UTIL_RELEASE messages */ - -static int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, u32 type) +static int i2o_issue_claim(struct i2o_controller *c, int tid, int context, + int onoff, u32 type) { u32 msg[5]; @@ -1791,53 +2319,71 @@ else msg[1] = I2O_CMD_UTIL_RELEASE << 24 | HOST_TID << 12 | tid; - /* msg[2] filled in i2o_post_wait */ msg[3] = 0; msg[4] = type; - - return i2o_post_wait(c, msg, sizeof(msg), 2); + + return i2o_post_wait(c, msg, sizeof(msg), 30); } /* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET * * This function can be used for all UtilParamsGet/Set operations. - * The OperationBlock is given in opblk-buffer, - * and results are returned in resblk-buffer. - * Note that the minimum sized resblk is 8 bytes and contains + * The OperationList is given in oplist-buffer, + * and results are returned in reslist-buffer. + * Note that the minimum sized reslist is 8 bytes and contains * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. */ int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, - void *opblk, int oplen, void *resblk, int reslen) + void *oplist, int oplen, void *reslist, int reslen) { u32 msg[9]; - u32 *res = (u32 *)resblk; + u8 *res = (u8 *)reslist; + u32 *res32 = (u32*)reslist; + u32 *restmp = (u32*)reslist; + int len = 0; + int i = 0; int wait_status; msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5; msg[1] = cmd << 24 | HOST_TID << 12 | tid; - /* msg[2] filled in i2o_post_wait */ msg[3] = 0; msg[4] = 0; - msg[5] = 0x54000000 | oplen; /* OperationBlock */ - msg[6] = virt_to_bus(opblk); - msg[7] = 0xD0000000 | reslen; /* ResultBlock */ - msg[8] = virt_to_bus(resblk); - - if ((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 20))) - return wait_status; /* -DetailedStatus */ - - if (res[1]&0x00FF0000) /* BlockStatus != SUCCESS */ - { - printk(KERN_WARNING "%s: %s - Error:\n ErrorInfoSize = 0x%02x, " - "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", - iop->name, - (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" - : "PARAMS_GET", - res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF); - return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ + msg[5] = 0x54000000 | oplen; /* OperationList */ + msg[6] = virt_to_bus(oplist); + msg[7] = 0xD0000000 | reslen; /* ResultList */ + msg[8] = virt_to_bus(reslist); + + if((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10))) + return wait_status; /* -DetailedStatus */ + + /* + * Calculate number of bytes of Result LIST + * We need to loop through each Result BLOCK and grab the length + */ + restmp = res32 + 1; + len = 1; + for(i = 0; i < (res32[0]&0X0000FFFF); i++) + { + if(restmp[0]&0x00FF0000) /* BlockStatus != SUCCESS */ + { + printk(KERN_WARNING "%s - Error:\n ErrorInfoSize = 0x%02x, " + "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", + (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" + : "PARAMS_GET", + res32[1]>>24, (res32[1]>>16)&0xFF, res32[1]&0xFFFF); + + /* + * If this is the only request,than we return an error + */ + if((res32[0]&0x0000FFFF) == 1) + return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ + } + + len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */ + restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ } - return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ + return (len << 2); /* bytes used by result list */ } /* @@ -1852,15 +2398,15 @@ if (field == -1) /* whole group */ opblk[4] = -1; - + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, opblk, sizeof(opblk), resblk, sizeof(resblk)); - + if (size < 0) return size; memcpy(buf, resblk+8, buflen); /* cut off header */ - return buflen; + return buflen < size ? buflen : size; } /* @@ -1904,22 +2450,17 @@ } /* - * if oper == I2O_PARAMS_TABLE_GET: - * Get all table group fields from all rows or - * get specific table group fields from all rows. - * - * if fieldcount == -1 we query all fields from all rows - * ibuf is NULL and ibuflen is 0 - * else we query specific fields from all rows + * if oper == I2O_PARAMS_TABLE_GET, get from all rows + * if fieldcount == -1 return all fields + * ibuf and ibuflen are unused (use NULL, 0) + * else return specific fields * ibuf contains fieldindexes * - * if oper == I2O_PARAMS_LIST_GET: - * Get all table group fields from specified rows or - * get specific table group fields from specified rows. - * - * if fieldcount == -1 we query all fields from specified rows + * if oper == I2O_PARAMS_LIST_GET, gte form specific rows + * if fieldcount == -1 return all fields * ibuf contains rowcount, keyvalues - * else we query specific fields from specified rows + * else return specific fields + * fieldcount is # of fieldindexes * ibuf contains fieldindexes, rowcount, keyvalues * * You could also use directly function i2o_issue_params(). @@ -1955,7 +2496,6 @@ /* * Clear table group, i.e. delete all rows. */ - int i2o_clear_table(struct i2o_controller *iop, int tid, int group) { u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group }; @@ -1973,7 +2513,6 @@ * else just specific fields are given, rest use defaults * buf contains fieldindexes, rowcount, keyvalues */ - int i2o_row_add_table(struct i2o_controller *iop, int tid, int group, int fieldcount, void *buf, int buflen) { @@ -2005,7 +2544,6 @@ /* * Delete rows from a table group. */ - int i2o_row_delete_table(struct i2o_controller *iop, int tid, int group, int keycount, void *keys, int keyslen) { @@ -2034,6 +2572,9 @@ return size; } +/* + * Used for error reporting/debugging purposes + */ void i2o_report_common_status(u8 req_status) { /* the following reply status strings are common to all classes */ @@ -2061,6 +2602,9 @@ return; } +/* + * Used for error reporting/debugging purposes + */ static void i2o_report_common_dsc(u16 detailed_status) { /* The following detailed statuscodes are valid @@ -2108,6 +2652,9 @@ return; } +/* + * Used for error reporting/debugging purposes + */ static void i2o_report_lan_dsc(u16 detailed_status) { static char *LAN_DSC[] = { // Lan detailed status code strings @@ -2140,6 +2687,9 @@ return; } +/* + * Used for error reporting/debugging purposes + */ static void i2o_report_util_cmd(u8 cmd) { switch (cmd) { @@ -2192,7 +2742,9 @@ return; } - +/* + * Used for error reporting/debugging purposes + */ static void i2o_report_exec_cmd(u8 cmd) { switch (cmd) { @@ -2302,6 +2854,9 @@ return; } +/* + * Used for error reporting/debugging purposes + */ static void i2o_report_lan_cmd(u8 cmd) { switch (cmd) { @@ -2327,38 +2882,45 @@ return; } -/* TODO: Add support for other classes */ +/* + * Used for error reporting/debugging purposes + */ void i2o_report_status(const char *severity, const char *module, u32 *msg) { u8 cmd = (msg[1]>>24)&0xFF; u8 req_status = (msg[4]>>24)&0xFF; u16 detailed_status = msg[4]&0xFFFF; + struct i2o_handler *h = i2o_handlers[msg[2] & (MAX_I2O_MODULES-1)]; printk("%s%s: ", severity, module); - if (cmd < 0x1F) { // Utility Class - i2o_report_util_cmd(cmd); - i2o_report_common_status(req_status); - i2o_report_common_dsc(detailed_status); - return; - } + switch (h->class) { + case I2O_CLASS_EXECUTIVE: + if (cmd < 0x1F) { // Utility cmd + i2o_report_util_cmd(cmd); + i2o_report_common_status(req_status); + i2o_report_common_dsc(detailed_status); + } + if (cmd >= 0xA0 && cmd <= 0xEF) { // Executive cmd + i2o_report_exec_cmd(cmd); + i2o_report_common_status(req_status); + i2o_report_common_dsc(detailed_status); + } + break; - if (cmd >= 0x30 && cmd <= 0x3F) { // LAN class - i2o_report_lan_cmd(cmd); - i2o_report_common_status(req_status); - i2o_report_lan_dsc(detailed_status); - return; - } - - if (cmd >= 0xA0 && cmd <= 0xEF) { // Executive class - i2o_report_exec_cmd(cmd); - i2o_report_common_status(req_status); - i2o_report_common_dsc(detailed_status); - return; + case I2O_CLASS_LAN: + i2o_report_lan_cmd(cmd); + i2o_report_common_status(req_status); + i2o_report_lan_dsc(detailed_status); + break; +/* + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + break; +*/ + default: + printk(KERN_INFO "%02x, %02x / %04x.\n", + cmd, req_status, detailed_status); } - - printk("%02x, %02x / %04x.\n", cmd, req_status, detailed_status); - return; } /* Used to dump a message to syslog during debugging */ @@ -2366,7 +2928,6 @@ { #ifdef DRIVERDEBUG int i; - printk(KERN_INFO "Dumping I2O message size %d @ %p\n", msg[0]>>16&0xffff, msg); for(i = 0; i < ((msg[0]>>16)&0xffff); i++) @@ -2374,53 +2935,102 @@ #endif } -#ifdef MODULE +/* + * I2O reboot/shutdown notification. + * + * - Call each OSM's reboot notifier (if one exists) + * - Quiesce each IOP in the system + * + * Each IOP has to be quiesced before we can ensure that the system + * can be properly shutdown as a transaction that has already been + * acknowledged still needs to be placed in permanent store on the IOP. + * The SysQuiesce causes the IOP to force all HDMs to complete their + * transactions before returning, so only at that point is it safe + * + */ +static int i2o_reboot_event(struct notifier_block *n, unsigned long code, void +*p) +{ + int i = 0; + struct i2o_controller *c = NULL; -EXPORT_SYMBOL(i2o_install_handler); -EXPORT_SYMBOL(i2o_remove_handler); + if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF) + return NOTIFY_DONE; -EXPORT_SYMBOL(i2o_install_controller); -EXPORT_SYMBOL(i2o_delete_controller); -EXPORT_SYMBOL(i2o_unlock_controller); -EXPORT_SYMBOL(i2o_find_controller); + printk(KERN_INFO "Shutting down I2O system.\n"); + printk(KERN_INFO + " This could take a few minutes if there are many devices attached\n"); + + for(i = 0; i < MAX_I2O_MODULES; i++) + { + if(i2o_handlers[i] && i2o_handlers[i]->reboot_notify) + i2o_handlers[i]->reboot_notify(); + } + + for(c = i2o_controller_chain; c; c = c->next) + { + if(i2o_quiesce_controller(c)) + { + printk(KERN_WARNING "i2o: Could not quiesce %s." " + Verify setup on next system power up.\n", c->name); + } + } + + printk(KERN_INFO "I2O system down.\n"); + return NOTIFY_DONE; +} + + +#ifdef MODULE + +EXPORT_SYMBOL(i2o_controller_chain); EXPORT_SYMBOL(i2o_num_controllers); +EXPORT_SYMBOL(i2o_find_controller); +EXPORT_SYMBOL(i2o_unlock_controller); +EXPORT_SYMBOL(i2o_status_get); -EXPORT_SYMBOL(i2o_event_register); -EXPORT_SYMBOL(i2o_event_ack); +EXPORT_SYMBOL(i2o_install_handler); +EXPORT_SYMBOL(i2o_remove_handler); EXPORT_SYMBOL(i2o_claim_device); EXPORT_SYMBOL(i2o_release_device); -EXPORT_SYMBOL(i2o_run_queue); -EXPORT_SYMBOL(i2o_activate_controller); -EXPORT_SYMBOL(i2o_get_class_name); -EXPORT_SYMBOL(i2o_status_get); +EXPORT_SYMBOL(i2o_device_notify_on); +EXPORT_SYMBOL(i2o_device_notify_off); + +EXPORT_SYMBOL(i2o_post_this); +EXPORT_SYMBOL(i2o_post_wait); EXPORT_SYMBOL(i2o_query_scalar); EXPORT_SYMBOL(i2o_set_scalar); EXPORT_SYMBOL(i2o_query_table); EXPORT_SYMBOL(i2o_clear_table); EXPORT_SYMBOL(i2o_row_add_table); - -EXPORT_SYMBOL(i2o_post_this); -EXPORT_SYMBOL(i2o_post_wait); +EXPORT_SYMBOL(i2o_row_delete_table); EXPORT_SYMBOL(i2o_issue_params); +EXPORT_SYMBOL(i2o_event_register); +EXPORT_SYMBOL(i2o_event_ack); + EXPORT_SYMBOL(i2o_report_status); +EXPORT_SYMBOL(i2o_dump_message); +EXPORT_SYMBOL(i2o_get_class_name); MODULE_AUTHOR("Red Hat Software"); MODULE_DESCRIPTION("I2O Core"); + int init_module(void) { - printk(KERN_INFO "I2O Core - (c) Copyright 1999 Red Hat Software.\n"); + printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n"); if (i2o_install_handler(&i2o_core_handler) < 0) { printk(KERN_ERR - "i2o: Unable to install core handler.\nI2O stack not loaded!"); + "i2o_core: Unable to install core handler.\nI2O stack not loaded!"); return 0; } core_context = i2o_core_handler.context; + /* * Attach core to I2O PCI transport (and others as they are developed) */ @@ -2429,22 +3039,61 @@ printk(KERN_INFO "i2o: No PCI I2O controllers found\n"); #endif + /* + * Initialize event handling thread + */ + init_MUTEX_LOCKED(&evt_sem); + evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND); + if(evt_pid < 0) + { + printk(KERN_ERR "I2O: Could not create event handler kernel thread\n"); + i2o_remove_handler(&i2o_core_handler); + return 0; + } + else + printk(KERN_INFO "event thread created as pid %d\n", evt_pid); + if(i2o_num_controllers) i2o_sys_init(); + register_reboot_notifier(&i2o_reboot_notifier); + return 0; } void cleanup_module(void) { + int stat; + + unregister_reboot_notifier(&i2o_reboot_notifier); + if(i2o_num_controllers) i2o_sys_shutdown(); + /* + * If this is shutdown time, the thread has already been killed + */ + if(evt_running) { + stat = kill_proc(evt_pid, SIGTERM, 1); + if(!stat) { + int count = 10 * 100; + while(evt_running && count) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + + if(!count) + printk(KERN_ERR "i2o: Event thread still running!\n"); + } + } + #ifdef CONFIG_I2O_PCI_MODULE i2o_pci_core_detach(); #endif i2o_remove_handler(&i2o_core_handler); + + unregister_reboot_notifier(&i2o_reboot_notifier); } #else @@ -2468,12 +3117,29 @@ core_context = i2o_core_handler.context; + /* + * Initialize event handling thread + * We may not find any controllers, but still want this as + * down the road we may have hot pluggable controllers that + * need to be dealt with. + */ + init_MUTEX_LOCKED(&evt_sem); + if((evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND)) < 0) + { + printk(KERN_ERR "I2O: Could not create event handler kernel thread\n"); + i2o_remove_handler(&i2o_core_handler); + return 0; + } + + #ifdef CONFIG_I2O_PCI i2o_pci_init(); #endif if(i2o_num_controllers) i2o_sys_init(); + + register_reboot_notifier(&i2o_reboot_notifier); i2o_config_init(); #ifdef CONFIG_I2O_BLOCK diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c --- v2.3.99-pre5/linux/drivers/i2o/i2o_lan.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/i2o/i2o_lan.c Wed Apr 12 09:38:53 2000 @@ -1,10 +1,10 @@ /* - * linux/drivers/i2o/i2o_lan.c + * drivers/i2o/i2o_lan.c * - * I2O LAN CLASS OSM January 7th 1999 + * I2O LAN CLASS OSM April 3rd 2000 * - * (C) Copyright 1999 University of Helsinki, - * Department of Computer Science + * (C) Copyright 1999, 2000 University of Helsinki, + * Department of Computer Science * * This code is still under development / test. * @@ -14,7 +14,8 @@ * 2 of the License, or (at your option) any later version. * * Authors: Auvo Häkkinen - * Juha Sievänen + * Fixes: Juha Sievänen + * Taneli Vähäkangas * Deepak Saxena * * Tested: in FDDI environment (using SysKonnect's DDM) @@ -31,10 +32,12 @@ #include #include #include +#include +#include + #include #include #include -#include #include #include #include @@ -52,46 +55,62 @@ #define dprintk(s, args...) #endif -/* Module params */ - -static u32 bucketpost = I2O_BUCKET_COUNT; -static u32 bucketthresh = I2O_BUCKET_THRESH; -static u32 rx_copybreak = 200; +/* The following module parameters are used as default values + * for per interface values located in the net_device private area. + * Private values are changed via /proc filesystem. + */ +static u32 max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT; +static u32 bucket_thresh = I2O_LAN_BUCKET_THRESH; +static u32 rx_copybreak = I2O_LAN_RX_COPYBREAK; +static tx_batch_mode = I2O_LAN_TX_BATCH_MODE; +static i2o_event_mask = I2O_LAN_EVENT_MASK; #define MAX_LAN_CARDS 16 static struct net_device *i2o_landevs[MAX_LAN_CARDS+1]; -static int unit = -1; /* device unit number */ +static int unit = -1; /* device unit number */ -struct i2o_lan_local { - u8 unit; - struct i2o_device *i2o_dev; - struct fddi_statistics stats; /* see also struct net_device_stats */ - unsigned short (*type_trans)(struct sk_buff *, struct net_device *); - u32 bucket_count; /* nbr of buckets sent to DDM */ - u32 tx_count; /* packets in one TX message frame */ - u32 tx_max_out; /* DDM's Tx queue len */ - u32 tx_out; /* outstanding TXes */ - u32 sgl_max; /* max SGLs in one message frame */ - u32 m; /* IOP address of msg frame */ - - struct tq_struct i2o_batch_send_task; - struct sk_buff **i2o_fbl; /* Free bucket list (to reuse skbs) */ - int i2o_fbl_tail; +extern rwlock_t dev_mc_lock; - spinlock_t lock; -}; - -static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, - struct i2o_message *m); -static void i2o_lan_event_reply(struct net_device *dev, u32 *msg); +static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); +static void i2o_lan_send_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); static int i2o_lan_receive_post(struct net_device *dev); -static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg); +static void i2o_lan_receive_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m); static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg); +static int i2o_lan_reset(struct net_device *dev); +static void i2o_lan_handle_event(struct net_device *dev, u32 *msg); + +/* Structures to register handlers for the incoming replies. */ + +static struct i2o_handler i2o_lan_send_handler = { + i2o_lan_send_post_reply, // For send replies + NULL, + NULL, + NULL, + "I2O Lan OSM send", + -1, + I2O_CLASS_LAN +}; +static int lan_send_context; + +static struct i2o_handler i2o_lan_receive_handler = { + i2o_lan_receive_post_reply, // For receive replies + NULL, + NULL, + NULL, + "I2O Lan OSM receive", + -1, + I2O_CLASS_LAN +}; +static int lan_receive_context; + static struct i2o_handler i2o_lan_handler = { - i2o_lan_reply, + i2o_lan_reply, // For other replies + NULL, + NULL, + NULL, "I2O Lan OSM", - 0, // context + -1, I2O_CLASS_LAN }; static int lan_context; @@ -100,245 +119,264 @@ 0, 0, (void (*)(void *))i2o_lan_receive_post, (void *) 0 }; +/* Functions to handle message failures and transaction errors: +==============================================================*/ + /* - * i2o_lan_reply(): The only callback function to handle incoming messages. + * i2o_lan_handle_failure(): Fail bit has been set since IOP's message + * layer cannot deliver the request to the target, or the target cannot + * process the request. */ -static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, - struct i2o_message *m) +static void i2o_lan_handle_failure(struct net_device *dev, u32 *msg) { - u32 *msg = (u32 *)m; - u8 unit = (u8)(msg[2]>>16); // InitiatorContext - struct net_device *dev = i2o_landevs[unit]; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; - if (msg[0] & (1<<13)) { // Fail bit is set - printk(KERN_ERR "%s: IOP failed to process the msg:\n",dev->name); - printk(KERN_ERR " Cmd = 0x%02X, InitiatorTid = %d, TargetTid = %d\n", - (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); - printk(KERN_ERR " FailureCode = 0x%02X\n Severity = 0x%02X\n " - "LowestVersion = 0x%02X\n HighestVersion = 0x%02X\n", - msg[4] >> 24, (msg[4] >> 16) & 0xFF, - (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); - printk(KERN_ERR " FailingHostUnit = 0x%04X\n FailingIOP = 0x%03X\n", - msg[5] >> 16, msg[5] & 0xFFF); - return; - } + u32 *preserved_msg = (u32*)(iop->mem_offset + msg[7]); + // FIXME on 64-bit host + u32 *sgl_elem = &preserved_msg[4]; + struct sk_buff *skb = NULL; + u8 le_flag; + +// To be added to i2o_core.c +// i2o_report_failure(KERN_INFO, iop, dev->name, msg); + + /* If PacketSend failed, free sk_buffs reserved by upper layers */ + + if (msg[1] >> 24 == LAN_PACKET_SEND) { + do { + skb = (struct sk_buff *)(sgl_elem[1]); + dev_kfree_skb_irq(skb); + + atomic_dec(&priv->tx_out); + + le_flag = *sgl_elem >> 31; + sgl_elem +=3; + } while (le_flag == 0); /* Last element flag not set */ -#ifndef DRIVERDEBUG - if (msg[4] >> 24) /* ReqStatus != SUCCESS */ -#endif - i2o_report_status(KERN_INFO, dev->name, msg); - - switch (msg[1] >> 24) { - case LAN_RECEIVE_POST: - { - if (netif_running(dev)) { - if (!(msg[4]>>24)) { - i2o_lan_receive_post_reply(dev,msg); - break; - } + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } - // Something VERY wrong if this is happening - printk( KERN_WARNING "%s: rejected bucket post.\n", dev->name); - } + /* If ReceivePost failed, free sk_buffs we have reserved */ - // Shutting down, we are getting unused buckets back - i2o_lan_release_buckets(dev,msg); - - break; + if (msg[1] >> 24 == LAN_RECEIVE_POST) { + do { + skb = (struct sk_buff *)(sgl_elem[1]); + dev_kfree_skb_irq(skb); + + atomic_dec(&priv->buckets_out); + + le_flag = *sgl_elem >> 31; + sgl_elem +=3; + } while (le_flag == 0); /* Last element flag not set */ } - case LAN_PACKET_SEND: - case LAN_SDU_SEND: - { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - u8 trl_count = msg[3] & 0x000000FF; + /* Release the preserved msg frame by resubmitting it as a NOP */ - while (trl_count) { - // The HDM has handled the outgoing packet - dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]); - dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n", - dev->name,trl_count); - priv->tx_out--; - trl_count--; - } + preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; + preserved_msg[2] = 0; + i2o_post_message(iop, msg[7]); +} +/* + * i2o_lan_handle_transaction_error(): IOP or DDM has rejected the request + * for general cause (format error, bad function code, insufficient resources, + * etc.). We get one transaction_error for each failed transaction. + */ +static void i2o_lan_handle_transaction_error(struct net_device *dev, u32 *msg) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct sk_buff *skb; + +// To be added to i2o_core.c +// i2o_report_transaction_error(KERN_INFO, dev->name, msg); + + /* If PacketSend was rejected, free sk_buff reserved by upper layers */ + + if (msg[1] >> 24 == LAN_PACKET_SEND) { + skb = (struct sk_buff *)(msg[3]); // TransactionContext + dev_kfree_skb_irq(skb); + atomic_dec(&priv->tx_out); if (netif_queue_stopped(dev)) netif_wake_queue(dev); - - break; - } - - case LAN_RESET: /* default reply without payload */ - case LAN_SUSPEND: - break; + } - case I2O_CMD_UTIL_EVT_REGISTER: - case I2O_CMD_UTIL_EVT_ACK: - i2o_lan_event_reply(dev, msg); - break; + /* If ReceivePost was rejected, free sk_buff we have reserved */ - default: - printk(KERN_ERR "%s: No handler for the reply.\n", dev->name); - i2o_report_status(KERN_INFO, dev->name, msg); + if (msg[1] >> 24 == LAN_RECEIVE_POST) { + skb = (struct sk_buff *)(msg[3]); + dev_kfree_skb_irq(skb); + atomic_dec(&priv->buckets_out); } } /* - * i2o_lan_event_reply(): Handle events. + * i2o_lan_handle_status(): Common parts of handling a not succeeded request + * (status != SUCCESS). */ -static void i2o_lan_event_reply(struct net_device *dev, u32 *msg) +static int i2o_lan_handle_status(struct net_device *dev, u32 *msg) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - struct i2o_reply { - u8 version_offset; - u8 msg_flags; - u16 msg_size; - u32 tid:12; - u32 initiator:12; - u32 function:8; - u32 initiator_context; - u32 transaction_context; - u32 evt_indicator; - u32 evt_data[(iop->inbound_size - 20) / 4]; /* max */ - } *evt = (struct i2o_reply *)msg; - - int evt_data_len = (evt->msg_size - 5) * 4; /* real */ - - if (evt->function == I2O_CMD_UTIL_EVT_REGISTER) { - printk(KERN_INFO "%s: I2O event - ", dev->name); - - switch (evt->evt_indicator) { - case I2O_EVT_IND_STATE_CHANGE: - printk("State chance 0x%08X.\n", - evt->evt_data[0]); - break; - case I2O_EVT_IND_GENERAL_WARNING: - printk("General warning 0x%02X.\n", - evt->evt_data[0]); - break; - case I2O_EVT_IND_CONFIGURATION_FLAG: - printk("Configuration requested.\n"); - break; - case I2O_EVT_IND_LOCK_RELEASE: - printk("Lock released.\n"); - break; - case I2O_EVT_IND_CAPABILITY_CHANGE: - printk("Capability change 0x%02X.\n", - evt->evt_data[0]); - break; - case I2O_EVT_IND_DEVICE_RESET: - printk("Device reset.\n"); - break; - case I2O_EVT_IND_EVT_MASK_MODIFIED: - printk("Event mask modified, 0x%08X.\n", - evt->evt_data[0]); - break; - case I2O_EVT_IND_FIELD_MODIFIED: { - u16 *work16 = (u16 *)evt->evt_data; - printk("Group 0x%04X, field %d changed.\n", - work16[0], work16[1]); - break; - } - case I2O_EVT_IND_VENDOR_EVT: { - int i; - printk("Vendor event:\n"); - for (i = 0; i < evt_data_len / 4; i++) - printk(" 0x%08X\n", evt->evt_data[i]); - break; - } - case I2O_EVT_IND_DEVICE_STATE: - printk("Device state changed 0x%08X.\n", - evt->evt_data[0]); - break; - case I2O_LAN_EVT_LINK_DOWN: - printk("Link to the physical device is lost.\n"); - break; - case I2O_LAN_EVT_LINK_UP: - printk("Link to the physical device is (re)established.\n"); - break; - case I2O_LAN_EVT_MEDIA_CHANGE: - printk("Media change.\n"); - break; - default: - printk("Event Indicator = 0x%08X.\n", - evt->evt_indicator); - } - - /* - * EventAck necessary only for events that cause the device - * to syncronize with the user - * - *if (i2o_event_ack(iop, i2o_dev->lct_data->tid, - * priv->unit << 16 | lan_context, - * evt->evt_indicator, - * evt->evt_data, evt_data_len) < 0) - * printk("%s: Event Acknowledge timeout.\n", dev->name); - */ - } + /* Fail bit set? */ + + if (msg[0] & MSG_FAIL) { + i2o_lan_handle_failure(dev, msg); + return -1; + } + + /* Message rejected for general cause? */ + + if ((msg[4]>>24) == I2O_REPLY_STATUS_TRANSACTION_ERROR) { + i2o_lan_handle_transaction_error(dev, msg); + return -1; + } - /* else evt->function == I2O_CMD_UTIL_EVT_ACK) */ - /* Do we need to do something here too? */ + /* Else have to handle it in the callback function */ + + return 0; } +/* Callback functions called from the interrupt routine: +=======================================================*/ + /* - * i2o_lan_release_buckets(): Handle unused buckets. + * i2o_lan_send_post_reply(): Callback function to handle PostSend replies. */ -static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg) +static void i2o_lan_send_post_reply(struct i2o_handler *h, + struct i2o_controller *iop, struct i2o_message *m) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - u8 trl_count = (u8)(msg[3] & 0x000000FF); - u32 *pskb = &msg[6]; + u32 *msg = (u32 *)m; + u8 unit = (u8)(msg[2]>>16); // InitiatorContext + struct net_device *dev = i2o_landevs[unit]; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + u8 trl_count = msg[3] & 0x000000FF; - while (trl_count--) { - dprintk("%s: Releasing unused sk_buff %p.\n",dev->name, - (struct sk_buff*)(*pskb)); - dev_kfree_skb((struct sk_buff*)(*pskb)); - pskb++; - priv->bucket_count--; +#ifdef DRIVERDEBUG + i2o_report_status(KERN_INFO, dev->name, msg); +#endif + + if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { + if (i2o_lan_handle_status(dev, msg)) + return; + + /* Else we get pending transmit request(s) back */ + } + + /* DDM has handled transmit request(s), free sk_buffs */ + + while (trl_count) { + dev_kfree_skb_irq((struct sk_buff *)msg[4 + trl_count]); + dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n", + dev->name, trl_count); + atomic_dec(&priv->tx_out); + trl_count--; } + + /* If priv->tx_out had reached tx_max_out, the queue was stopped */ + + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); } /* - * i2o_lan_receive_post_reply(): Process incoming packets. + * i2o_lan_receive_post_reply(): Callback function to process incoming packets. */ -static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg) +static void i2o_lan_receive_post_reply(struct i2o_handler *h, + struct i2o_controller *iop, struct i2o_message *m) { + u32 *msg = (u32 *)m; + u8 unit = (u8)(msg[2]>>16); // InitiatorContext + struct net_device *dev = i2o_landevs[unit]; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6]; struct i2o_packet_info *packet; u8 trl_count = msg[3] & 0x000000FF; struct sk_buff *skb, *old_skb; + unsigned long flags = 0; + +#ifdef DRIVERDEBUG + i2o_report_status(KERN_INFO, dev->name, msg); +#endif + + if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { + if (i2o_lan_handle_status(dev, msg)) + return; + + /* Getting unused buckets back? */ + + if (msg[4] & I2O_LAN_DSC_CANCELED || + msg[4] & I2O_LAN_DSC_RECEIVE_ABORTED) { + i2o_lan_release_buckets(dev, msg); + return; + } + + /* Which DetailedStatusCodes need special treatment? */ + } + + /* Else we are receiving incoming post. */ while (trl_count--) { - skb = (struct sk_buff *)bucket->context; - packet = (struct i2o_packet_info *)bucket->packet_info; - priv->bucket_count--; + skb = (struct sk_buff *)bucket->context; + packet = (struct i2o_packet_info *)bucket->packet_info; + atomic_dec(&priv->buckets_out); +#if 0 +/* Is this enough? If we get erroneous bucket, we can't assume that skb could + * be reused, can we? + */ + + /* Should we optimise these ifs away from the fast path? -taneli */ + if (packet->flags & 0x0f) { + + if (packet->flags & 0x01) + printk(KERN_WARNING "%s: packet with errors.\n", dev->name); + if (packet->flags & 0x0c) + /* This actually means that the hw is b0rken, since we + have asked it to not send fragmented packets. */ + printk(KERN_DEBUG "%s: multi-bucket packets not supported!\n", dev->name); + bucket++; + if (skb) + dev_kfree_skb_irq(skb); + continue; + } - if (packet->len < rx_copybreak) { + if (packet->status & 0xff) { + /* Silently discard, unless debugging. */ + dprintk(KERN_DEBUG "%s: toasted packet received.\n", dev->name); + bucket++; + if (skb) + dev_kfree_skb_irq(skb); + continue; + } +#endif + if (packet->len < priv->rx_copybreak) { old_skb = skb; - skb = (struct sk_buff *)dev_alloc_skb(packet->len+2); + skb = (struct sk_buff *)dev_alloc_skb(packet->len+2); if (skb == NULL) { - printk("%s: Can't allocate skb.\n", dev->name); - return -ENOMEM; - } - skb_reserve(skb,2); - memcpy(skb_put(skb,packet->len), old_skb->data, packet->len); + printk(KERN_ERR "%s: Can't allocate skb.\n", dev->name); + return; + } + skb_reserve(skb, 2); + memcpy(skb_put(skb, packet->len), old_skb->data, packet->len); - if (priv->i2o_fbl_tail < I2O_BUCKET_COUNT) - priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb; + spin_lock_irqsave(&priv->fbl_lock, flags); + if (priv->i2o_fbl_tail < I2O_LAN_MAX_BUCKETS_OUT) + priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb; else - dev_kfree_skb(old_skb); + dev_kfree_skb_irq(old_skb); + spin_unlock_irqrestore(&priv->fbl_lock, flags); } else - skb_put(skb,packet->len); - + skb_put(skb, packet->len); + skb->dev = dev; skb->protocol = priv->type_trans(skb, dev); netif_rx(skb); + dev->last_rx = jiffies; dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered " - "to upper level.\n",dev->name,packet->len); + "to upper level.\n", dev->name, packet->len); bucket++; // to next Packet Descriptor Block } @@ -346,19 +384,193 @@ #ifdef DRIVERDEBUG if (msg[5] == 0) printk(KERN_INFO "%s: DDM out of buckets (priv->count = %d)!\n", - dev->name, priv->bucket_count); + dev->name, atomic_read(&priv->buckets_out)); #endif - if (priv->bucket_count <= bucketpost - bucketthresh) { - i2o_post_buckets_task.data = (void *)dev; - queue_task(&i2o_post_buckets_task, &tq_immediate); - mark_bh(IMMEDIATE_BH); - /* Note: the task is queued only once */ + /* If DDM has already consumed bucket_tresh buckets, post new ones */ + + if (atomic_read(&priv->buckets_out) <= priv->max_buckets_out - priv->bucket_thresh) { + i2o_post_buckets_task.data = (void *)dev; + queue_task(&i2o_post_buckets_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + + return; +} + +/* + * i2o_lan_reply(): Callback function to handle other incoming messages + * except SendPost and ReceivePost. + */ +static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, + struct i2o_message *m) +{ + u32 *msg = (u32 *)m; + u8 unit = (u8)(msg[2]>>16); // InitiatorContext + struct net_device *dev = i2o_landevs[unit]; + +#ifdef DRIVERDEBUG + i2o_report_status(KERN_INFO, dev->name, msg); +#endif + + if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { + if (i2o_lan_handle_status(dev, msg)) + return; + + /* This should NOT be reached */ + } + + switch (msg[1] >> 24) { + case LAN_RESET: + case LAN_SUSPEND: + /* default reply without payload */ + break; + case I2O_CMD_UTIL_EVT_REGISTER: + case I2O_CMD_UTIL_EVT_ACK: + i2o_lan_handle_event(dev, msg); + break; + default: + printk(KERN_ERR "%s: No handler for the reply.\n", + dev->name); + i2o_report_status(KERN_INFO, dev->name, msg); + } +} + +/* Functions used by the above callback functions: +=================================================*/ +/* + * i2o_lan_release_buckets(): Free unused buckets (sk_buffs). + */ +static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + u8 trl_elem_size = (u8)(msg[3]>>8 & 0x000000FF); + u8 trl_count = (u8)(msg[3] & 0x000000FF); + u32 *pskb = &msg[6]; + + while (trl_count--) { + dprintk(KERN_DEBUG "%s: Releasing unused sk_buff %p (trl_count=%d).\n", + dev->name, (struct sk_buff*)(*pskb),trl_count+1); + dev_kfree_skb_irq((struct sk_buff *)(*pskb)); + pskb += 1 + trl_elem_size; + atomic_dec(&priv->buckets_out); } - - return 0; } +/* + * i2o_lan_event_reply(): Handle events. + */ +static void i2o_lan_handle_event(struct net_device *dev, u32 *msg) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + struct i2o_reply { + u8 version_offset; + u8 msg_flags; + u16 msg_size; + u32 tid:12; + u32 initiator:12; + u32 function:8; + u32 initiator_context; + u32 transaction_context; + u32 evt_indicator; + u32 data[(iop->inbound_size - 20) / 4]; /* max */ + } *evt = (struct i2o_reply *)msg; + int evt_data_len = (evt->msg_size - 5) * 4; /* real */ + + printk(KERN_INFO "%s: I2O event - ", dev->name); + + if (evt->function == I2O_CMD_UTIL_EVT_ACK) { + printk("Event acknowledgement reply.\n"); + return; + } + + /* Else evt->function == I2O_CMD_UTIL_EVT_REGISTER) */ + + switch (evt->evt_indicator) { + case I2O_EVT_IND_STATE_CHANGE: { + struct state_data { + u16 status; + u8 state; + u8 data; + } *evt_data = (struct state_data *)(evt->data[0]); + + printk("State chance 0x%08x.\n", evt->data[0]); + + /* If the DDM is in error state, recovery may be + * possible if status = Transmit or Receive Control + * Unit Inoperable. + */ + if (evt_data->state==0x05 && evt_data->status==0x0003) + i2o_lan_reset(dev); + break; + } + + case I2O_EVT_IND_GENERAL_WARNING: + printk("General warning 0x%04x.\n", evt->data[0]); + break; + + case I2O_EVT_IND_CONFIGURATION_FLAG: + printk("Configuration requested.\n"); + break; + + case I2O_EVT_IND_CAPABILITY_CHANGE: + printk("Capability change 0x%04x.\n", evt->data[0]); + break; + + case I2O_EVT_IND_DEVICE_RESET: + /* Spec 2.0 p. 6-121: + * The event of _DEVICE_RESET should also be responded + */ + printk("Device reset.\n"); + if (i2o_event_ack(iop, msg) < 0) + printk("%s: Event Acknowledge timeout.\n", dev->name); + break; + + case I2O_EVT_IND_EVT_MASK_MODIFIED: + printk("Event mask modified, 0x%08x.\n", evt->data[0]); + break; + + case I2O_EVT_IND_FIELD_MODIFIED: { + u16 *work16 = (u16 *)evt->data; + printk("Group 0x%04x, field %d changed.\n", work16[0], + work16[1]); + break; + } + + case I2O_EVT_IND_VENDOR_EVT: { + int i; + printk("Vendor event:\n"); + for (i = 0; i < evt_data_len / 4; i++) + printk(" 0x%08x\n", evt->data[i]); + break; + } + + case I2O_EVT_IND_DEVICE_STATE: + printk("Device state changed 0x%08x.\n", evt->data[0]); + break; + + case I2O_LAN_EVT_LINK_DOWN: + printk("Link to the physical device is lost.\n"); + break; + + case I2O_LAN_EVT_LINK_UP: + printk("Link to the physical device is (re)established.\n"); + break; + + case I2O_LAN_EVT_MEDIA_CHANGE: + printk("Media change.\n"); + break; + + default: + printk("Event Indicator = 0x%08x.\n", evt->evt_indicator); + } + + /* Note: EventAck necessary only for events that cause the device to + * syncronize with the user. + */ +} /* * i2o_lan_receive_post(): Post buckets to receive packets. @@ -369,93 +581,108 @@ struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; struct sk_buff *skb; - u32 m; u32 *msg; - u32 bucket_len = (dev->mtu + dev->hard_header_len); - u32 total = bucketpost - priv->bucket_count; - u32 bucket_count; - u32 *sgl_elem; - - while (total) { - m = I2O_POST_READ32(iop); - if (m == 0xFFFFFFFF) - return -ETIMEDOUT; - msg = (u32 *)(iop->mem_offset + m); - - bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total; - total -= bucket_count; - priv->bucket_count += bucket_count; + u32 m, *msg; + u32 bucket_len = (dev->mtu + dev->hard_header_len); + u32 total = priv->max_buckets_out - atomic_read(&priv->buckets_out); + u32 bucket_count; + u32 *sgl_elem; + unsigned long flags; + + /* Send (total/bucket_count) separate I2O requests */ + + while (total) { + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) + return -ETIMEDOUT; + msg = (u32 *)(iop->mem_offset + m); + + bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total; + total -= bucket_count; + atomic_add(bucket_count, &priv->buckets_out); - dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n", - dev->name, bucket_count, bucket_len); + dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN DDM.\n", + dev->name, bucket_count, bucket_len); + + /* Fill in the header */ __raw_writel(I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4, msg); - __raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, msg+1); - __raw_writel(priv->unit << 16 | lan_context, msg+2); + __raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1); + __raw_writel(priv->unit << 16 | lan_receive_context, msg+2); __raw_writel(bucket_count, msg+3); - sgl_elem = &msg[4]; + sgl_elem = &msg[4]; + + /* Fill in the payload - contains bucket_count SGL elements */ - while (bucket_count--) { - if (priv->i2o_fbl_tail >= 0) - skb = priv->i2o_fbl[priv->i2o_fbl_tail--]; - else { - skb = dev_alloc_skb(bucket_len + 2); - if (skb == NULL) - return -ENOMEM; - skb_reserve(skb, 2); - } - __raw_writel(0x51000000 | bucket_len, sgl_elem); - __raw_writel((u32)skb, sgl_elem+1); - __raw_writel(virt_to_bus(skb->data), sgl_elem+2); - sgl_elem += 3; - } + while (bucket_count--) { + spin_lock_irqsave(&priv->fbl_lock, flags); + if (priv->i2o_fbl_tail >= 0) + skb = priv->i2o_fbl[priv->i2o_fbl_tail--]; + else { + skb = dev_alloc_skb(bucket_len + 2); + if (skb == NULL) { + spin_unlock_irqrestore(&priv->fbl_lock, flags); + return -ENOMEM; + } + skb_reserve(skb, 2); + } + spin_unlock_irqrestore(&priv->fbl_lock, flags); - /* set LE flag and post buckets */ + __raw_writel(0x51000000 | bucket_len, sgl_elem); + __raw_writel((u32)skb, sgl_elem+1); + __raw_writel(virt_to_bus(skb->data), sgl_elem+2); + sgl_elem += 3; + } + + /* set LE flag and post */ __raw_writel(__raw_readl(sgl_elem-3) | 0x80000000, (sgl_elem-3)); - i2o_post_message(iop,m); - } + i2o_post_message(iop, m); + } - return 0; + return 0; } +/* Functions called from the network stack, and functions called by them: +========================================================================*/ + /* * i2o_lan_reset(): Reset the LAN adapter into the operational state and * restore it to full operation. */ static int i2o_lan_reset(struct net_device *dev) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; + struct i2o_controller *iop = i2o_dev->controller; u32 msg[5]; dprintk(KERN_INFO "%s: LAN RESET MESSAGE.\n", dev->name); msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid; + msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid; msg[2] = priv->unit << 16 | lan_context; // InitiatorContext msg[3] = 0; // TransactionContext - msg[4] = 1 << 16; // return posted buckets + msg[4] = 0; // keep posted buckets if (i2o_post_this(iop, msg, sizeof(msg)) < 0) - return -ETIMEDOUT; + return -ETIMEDOUT; return 0; } /* * i2o_lan_suspend(): Put LAN adapter into a safe, non-active state. - * Reply to any LAN class message with status error_no_data_transfer + * IOP replies to any LAN class message with status error_no_data_transfer * / suspended. */ static int i2o_lan_suspend(struct net_device *dev) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; + struct i2o_controller *iop = i2o_dev->controller; u32 msg[5]; dprintk(KERN_INFO "%s: LAN SUSPEND MESSAGE.\n", dev->name); msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid; + msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid; msg[2] = priv->unit << 16 | lan_context; // InitiatorContext msg[3] = 0; // TransactionContext msg[4] = 1 << 16; // return posted buckets @@ -471,75 +698,91 @@ */ static void i2o_set_batch_mode(struct net_device *dev) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; u32 val; - /* set LAN_BATCH_CONTROL attributes */ + /* Set defaults LAN_BATCH_CONTROL attributes */ + /* May be changed via /proc or Configuration Utility */ - // enable batch mode, toggle automatically - val = 0x00000000; - if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0003, 0, &val, sizeof(val)) <0) + val = 0x00000000; // enable batch mode, toggle automatically + if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0003, 0, &val, sizeof(val)) <0) printk(KERN_WARNING "%s: Unable to enter I2O LAN batch mode.\n", - dev->name); + dev->name); else - dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n",dev->name); + dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n", dev->name); + + /* Set LAN_OPERATION attributes */ + +#ifdef DRIVERDEBUG +/* Added for testing: this will be removed */ + val = 0x00000003; // 1 = UserFlags + if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0004, 1, &val, sizeof(val)) < 0) + printk(KERN_WARNING "%s: Can't enable ErrorReporting & BadPacketHandling.\n", + dev->name); + else + dprintk(KERN_INFO "%s: ErrorReporting enabled, " + "BadPacketHandling enabled.\n", dev->name); +#endif /* DRIVERDEBUG */ /* * When PacketOrphanlimit is same as the maximum packet length, * the packets will never be split into two separate buckets */ - - /* set LAN_OPERATION attributes */ - - val = dev->mtu + dev->hard_header_len; // PacketOrphanLimit - if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0004, 2, &val, sizeof(val)) < 0) + val = dev->mtu + dev->hard_header_len; // 2 = PacketOrphanLimit + if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0004, 2, &val, sizeof(val)) < 0) printk(KERN_WARNING "%s: Unable to set PacketOrphanLimit.\n", - dev->name); + dev->name); else dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d.\n", - dev->name,val); - - return; + dev->name, val); + + return; } +/* Functions called from the network stack: +==========================================*/ + /* * i2o_lan_open(): Open the device to send/receive packets via - * the network device. + * the network device. */ static int i2o_lan_open(struct net_device *dev) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; -#if 0 struct i2o_controller *iop = i2o_dev->controller; - u32 evt_mask = 0xFFC00007; // All generic events, all lan events -#endif - if (i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) { + + MOD_INC_USE_COUNT; + + if (i2o_claim_device(i2o_dev, &i2o_lan_handler)) { printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name); + MOD_DEC_USE_COUNT; return -EAGAIN; } - dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n", - dev->name, i2o_dev->lct_data->tid); -#if 0 - if (i2o_event_register(iop, i2o_dev->lct_data->tid, - priv->unit << 16 | lan_context, evt_mask) < 0) + dprintk(KERN_INFO "%s: I2O LAN device (tid=%d) claimed by LAN OSM.\n", + dev->name, i2o_dev->lct_data.tid); + + if (i2o_event_register(iop, i2o_dev->lct_data.tid, + priv->unit << 16 | lan_context, 0, priv->i2o_event_mask) < 0) printk(KERN_WARNING "%s: Unable to set the event mask.\n", dev->name); -#endif + i2o_lan_reset(dev); - - priv->i2o_fbl = kmalloc(bucketpost * sizeof(struct sk_buff *),GFP_KERNEL); - if (priv->i2o_fbl == NULL) + + priv->i2o_fbl = kmalloc(priv->max_buckets_out * sizeof(struct sk_buff *), + GFP_KERNEL); + if (priv->i2o_fbl == NULL) { + MOD_DEC_USE_COUNT; return -ENOMEM; + } priv->i2o_fbl_tail = -1; - - netif_start_queue(dev); + priv->send_active = 0; i2o_set_batch_mode(dev); i2o_lan_receive_post(dev); - MOD_INC_USE_COUNT; + netif_start_queue(dev); return 0; } @@ -549,22 +792,24 @@ */ static int i2o_lan_close(struct net_device *dev) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; -#if 0 + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; - if (i2o_event_register(iop, i2o_dev->lct_data->tid, - priv->unit << 16 | lan_context, 0) < 0) - printk(KERN_WARNING "%s: Unable to clear the event mask.\n", -#endif dev->name); - netif_stop_queue(dev); + i2o_lan_suspend(dev); - if (i2o_release_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) + if (i2o_event_register(iop, i2o_dev->lct_data.tid, + priv->unit << 16 | lan_context, 0, 0) < 0) + printk(KERN_WARNING "%s: Unable to clear the event mask.\n", + dev->name); + + if (i2o_release_device(i2o_dev, &i2o_lan_handler)) { printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device " - "(tid=%d).\n", dev->name, i2o_dev->lct_data->tid); + "(tid=%d).\n", dev->name, i2o_dev->lct_data.tid); + return -EBUSY; + } while (priv->i2o_fbl_tail >= 0) dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]); @@ -575,28 +820,115 @@ return 0; } -#if 0 /* - * i2o_lan_sdu_send(): Send a packet, MAC header added by the HDM. - * Must be supported by Fibre Channel, optional for Ethernet/802.3, - * Token Ring, FDDI + * i2o_lan_tx_timeout(): Tx timeout handler. */ -static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev) -{ - return -EINVAL; +static void i2o_lan_tx_timeout(struct net_device *dev) +{ + if (!netif_queue_stopped(dev)) + netif_start_queue(dev); } -#endif +#define batching(x, cond) ( (x)->tx_batch_mode==1 || ((x)->tx_batch_mode==2 && (cond)) ) + +/* + * Batch send packets. Both i2o_lan_sdu_send and i2o_lan_packet_send + * use this. I'm still not pleased. If you come up with + * something better, please tell me. -taneli + */ static void i2o_lan_batch_send(struct net_device *dev) -{ +{ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_controller *iop = priv->i2o_dev->controller; + spin_lock_irq(&priv->tx_lock); if (priv->tx_count != 0) { + dev->trans_start = jiffies; i2o_post_message(iop, priv->m); - dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count); + dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count); priv->tx_count = 0; } + spin_unlock_irq(&priv->tx_lock); + + priv->send_active = 0; +} + +/* + * i2o_lan_sdu_send(): Send a packet, MAC header added by the DDM. + * Must be supported by Fibre Channel, optional for Ethernet/802.3, + * Token Ring, FDDI + */ + +/* + * This is a coarse first approximation. Needs testing. Any takers? -taneli + */ +static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + int tickssofar = jiffies - dev->trans_start; + u32 m, *msg; + u32 *sgl_elem; + + spin_lock_irq(&priv->tx_lock); + + priv->tx_count++; + atomic_inc(&priv->tx_out); + + if (priv->tx_count == 1) { + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) { + spin_unlock_irq(&priv->tx_lock); + return 1; + } + msg = (u32 *)(iop->mem_offset + m); + priv->m = m; + + __raw_writel(NINE_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg); + __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1); + __raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext + __raw_writel(1 << 3, msg+3); // TransmitControlWord + + __raw_writel(0xD7000000 | skb->len, msg+4); // MAC hdr included + __raw_writel((u32)skb, msg+5); // TransactionContext + __raw_writel(virt_to_bus(skb->data), msg+6); + __raw_writel((u32)skb->mac.raw, msg+7); + __raw_writel((u32)skb->mac.raw+4, msg+8); + if (batching(priv, !tickssofar) && !priv->send_active) { + priv->send_active = 1; + queue_task(&priv->i2o_batch_send_task, &tq_scheduler); + } + } else { /* Add new SGL element to the previous message frame */ + + msg = (u32 *)(iop->mem_offset + priv->m); + sgl_elem = &msg[priv->tx_count * 5 + 1]; + + __raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 5) | 1<<12 | SGL_OFFSET_4, msg); + __raw_writel(__raw_readl(sgl_elem-5) & 0x7FFFFFFF, sgl_elem-5); /* clear LE flag */ + __raw_writel(0xD5000000 | skb->len, sgl_elem); + __raw_writel((u32)skb, sgl_elem+1); + __raw_writel(virt_to_bus(skb->data), sgl_elem+2); + __raw_writel((u32)(skb->mac.raw), sgl_elem+3); + __raw_writel((u32)(skb->mac.raw)+1, sgl_elem+4); + } + + /* If tx not in batch mode or frame is full, send immediatelly */ + + if (!batching(priv, !tickssofar) || priv->tx_count == priv->sgl_max) { + dev->trans_start = jiffies; + i2o_post_message(iop, priv->m); + dprintk(KERN_DEBUG "%s: %d packets sent.\n", dev->name, priv->tx_count); + priv->tx_count = 0; + } + + /* If DDMs TxMaxPktOut reached, stop queueing layer to send more */ + + if (atomic_read(&priv->tx_out) >= priv->tx_max_out) + netif_stop_queue(dev); + + spin_unlock_irq(&priv->tx_lock); + return 0; } /* @@ -610,37 +942,37 @@ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; + int tickssofar = jiffies - dev->trans_start; u32 m, *msg; u32 *sgl_elem; + spin_lock_irq(&priv->tx_lock); + priv->tx_count++; - priv->tx_out++; + atomic_inc(&priv->tx_out); if (priv->tx_count == 1) { - dprintk("%s: New message frame\n", dev->name); - m = I2O_POST_READ32(iop); if (m == 0xFFFFFFFF) { - dev_kfree_skb(skb); - return -ETIMEDOUT; + spin_unlock_irq(&priv->tx_lock); + return 1; } msg = (u32 *)(iop->mem_offset + m); priv->m = m; __raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg); - __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, msg+1); - __raw_writel(priv->unit << 16 | lan_context, msg+2); // InitiatorContext - __raw_writel(1 << 4, msg+3); // TransmitControlWord + __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data.tid, msg+1); + __raw_writel(priv->unit << 16 | lan_send_context, msg+2); // InitiatorContext + __raw_writel(1 << 3, msg+3); // TransmitControlWord + __raw_writel(0xD5000000 | skb->len, msg+4); // MAC hdr included __raw_writel((u32)skb, msg+5); // TransactionContext __raw_writel(virt_to_bus(skb->data), msg+6); - - queue_task(&priv->i2o_batch_send_task, &tq_scheduler); - + if (batching(priv, !tickssofar) && !priv->send_active) { + priv->send_active = 1; + queue_task(&priv->i2o_batch_send_task, &tq_scheduler); + } } else { /* Add new SGL element to the previous message frame */ - - dprintk("%s: Adding packet %d to msg frame\n", - dev->name, priv->tx_count); msg = (u32 *)(iop->mem_offset + priv->m); sgl_elem = &msg[priv->tx_count * 3 + 1]; @@ -650,19 +982,23 @@ __raw_writel(0xD5000000 | skb->len, sgl_elem); __raw_writel((u32)skb, sgl_elem+1); __raw_writel(virt_to_bus(skb->data), sgl_elem+2); + } - if (priv->tx_count == priv->sgl_max) { /* frame full, send now */ - i2o_post_message(iop, priv->m); - dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count); - priv->tx_count = 0; - } + /* If tx not in batch mode or frame is full, send immediatelly */ + + if (!batching(priv, !tickssofar) || priv->tx_count == priv->sgl_max) { + dev->trans_start = jiffies; + i2o_post_message(iop, priv->m); + dprintk(KERN_DEBUG"%s: %d packets sent.\n", dev->name, priv->tx_count); + priv->tx_count = 0; } - - /* If HDMs TxMaxPktOut reached, stay busy (don't clean tbusy) */ - if (priv->tx_out >= priv->tx_max_out) + /* If DDMs TxMaxPktOut reached, stop queueing layer to send more */ + + if (atomic_read(&priv->tx_out) >= priv->tx_max_out) netif_stop_queue(dev); - + + spin_unlock_irq(&priv->tx_lock); return 0; } @@ -671,65 +1007,64 @@ */ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; u64 val64[16]; u64 supported_group[4] = { 0, 0, 0, 0 }; - if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0100, -1, val64, - sizeof(val64)) < 0) - printk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name); + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0100, -1, val64, + sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_HISTORICAL_STATS.\n", dev->name); else { - dprintk("%s: LAN_HISTORICAL_STATS queried.\n",dev->name); - priv->stats.tx_packets = val64[0]; - priv->stats.tx_bytes = val64[1]; - priv->stats.rx_packets = val64[2]; - priv->stats.rx_bytes = val64[3]; - priv->stats.tx_errors = val64[4]; - priv->stats.rx_errors = val64[5]; + dprintk(KERN_DEBUG "%s: LAN_HISTORICAL_STATS queried.\n", dev->name); + priv->stats.tx_packets = val64[0]; + priv->stats.tx_bytes = val64[1]; + priv->stats.rx_packets = val64[2]; + priv->stats.rx_bytes = val64[3]; + priv->stats.tx_errors = val64[4]; + priv->stats.rx_errors = val64[5]; priv->stats.rx_dropped = val64[6]; } - if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0180, -1, - &supported_group, sizeof(supported_group)) < 0) - printk("%s: Unable to query LAN_SUPPORTED_OPTIONAL_HISTORICAL_STATS.\n",dev->name); + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0180, -1, + &supported_group, sizeof(supported_group)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_OPTIONAL_HISTORICAL_STATS.\n", dev->name); if (supported_group[2]) { - if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0183, -1, - val64, sizeof(val64)) < 0) - printk("%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n",dev->name); + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0183, -1, + val64, sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n", dev->name); else { - dprintk("%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n",dev->name); - priv->stats.multicast = val64[4]; + dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n", dev->name); + priv->stats.multicast = val64[4]; priv->stats.rx_length_errors = val64[10]; priv->stats.rx_crc_errors = val64[0]; } } - if (i2o_dev->lct_data->sub_class == I2O_LAN_ETHERNET) { - u64 supported_stats = 0; - - if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0200, -1, - val64, sizeof(val64)) < 0) - printk("%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n",dev->name); + if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET) { + u64 supported_stats = 0; + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0200, -1, + val64, sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n", dev->name); else { - dprintk("%s: LAN_802_3_HISTORICAL_STATS queried.\n",dev->name); + dprintk(KERN_DEBUG "%s: LAN_802_3_HISTORICAL_STATS queried.\n", dev->name); priv->stats.transmit_collision = val64[1] + val64[2]; - priv->stats.rx_frame_errors = val64[0]; + priv->stats.rx_frame_errors = val64[0]; priv->stats.tx_carrier_errors = val64[6]; } - if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0280, -1, - &supported_stats, sizeof(supported_stats)) < 0) - printk("%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS.\n", dev->name); - - if (supported_stats != 0) { - if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0281, -1, - val64, sizeof(val64)) < 0) - printk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name); + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0280, -1, + &supported_stats, sizeof(supported_stats)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS.\n", dev->name); + + if (supported_stats != 0) { + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0281, -1, + val64, sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n", dev->name); else { - dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name); + dprintk(KERN_DEBUG "%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n", dev->name); if (supported_stats & 0x1) priv->stats.rx_over_errors = val64[0]; if (supported_stats & 0x4) @@ -739,14 +1074,14 @@ } #ifdef CONFIG_TR - if (i2o_dev->lct_data->sub_class == I2O_LAN_TR) { - if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0300, -1, - val64, sizeof(val64)) < 0) - printk("%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n",dev->name); + if (i2o_dev->lct_data.sub_class == I2O_LAN_TR) { + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0300, -1, + val64, sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n", dev->name); else { struct tr_statistics *stats = - (struct tr_statistics *)&priv->stats; - dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name); + (struct tr_statistics *)&priv->stats; + dprintk(KERN_DEBUG "%s: LAN_802_5_HISTORICAL_STATS queried.\n", dev->name); stats->line_errors = val64[0]; stats->internal_errors = val64[7]; @@ -764,25 +1099,29 @@ #endif #ifdef CONFIG_FDDI - if (i2o_dev->lct_data->sub_class == I2O_LAN_FDDI) { - if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0400, -1, - val64, sizeof(val64)) < 0) - printk("%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n",dev->name); + if (i2o_dev->lct_data.sub_class == I2O_LAN_FDDI) { + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0400, -1, + val64, sizeof(val64)) < 0) + printk(KERN_INFO "%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n", dev->name); else { - dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name); + dprintk(KERN_DEBUG "%s: LAN_FDDI_HISTORICAL_STATS queried.\n", dev->name); priv->stats.smt_cf_state = val64[0]; memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN); - memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN); + memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN); priv->stats.mac_error_cts = val64[3]; priv->stats.mac_lost_cts = val64[4]; priv->stats.mac_rmt_state = val64[5]; memcpy(priv->stats.port_lct_fail_cts, &val64[6], 8); - memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8); + memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8); memcpy(priv->stats.port_lem_cts, &val64[8], 8); memcpy(priv->stats.port_pcm_state, &val64[9], 8); } /* FDDI optional stats not yet defined */ - } + } +#endif + +#ifdef CONFIG_NET_FC + /* Fibre Channel Statistics not yet defined in 1.53 nor 2.0 */ #endif return (struct net_device_stats *)&priv->stats; @@ -795,70 +1134,79 @@ static void i2o_lan_set_mc_list(struct net_device *dev) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - u32 filter_mask; - u32 max_size_mc_table; - u32 mc_addr_group[64]; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 filter_mask; + u32 max_size_mc_table; + u32 mc_addr_group[64]; + +// This isn't safe yet. Needs to be async. +return; + +// read_lock_bh(&dev_mc_lock); +// spin_lock(&dev->xmit_lock); +// dev->xmit_lock_owner = smp_processor_id(); - if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0001, -1, - &mc_addr_group, sizeof(mc_addr_group)) < 0 ) { + if (i2o_query_scalar(iop, i2o_dev->lct_data.tid, 0x0001, -1, + &mc_addr_group, sizeof(mc_addr_group)) < 0 ) { printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name); - return; - } - - max_size_mc_table = mc_addr_group[8]; + return; + } - if (dev->flags & IFF_PROMISC) { - filter_mask = 0x00000002; - dprintk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name); - } - - else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > max_size_mc_table) { - filter_mask = 0x00000004; - dprintk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name); - } + max_size_mc_table = mc_addr_group[8]; - else if (dev->mc_count) { - struct dev_mc_list *mc; + if (dev->flags & IFF_PROMISC) { + filter_mask = 0x00000002; + printk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name); + } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > max_size_mc_table) { + filter_mask = 0x00000004; + printk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name); + } else if (dev->mc_count) { + struct dev_mc_list *mc; u8 mc_table[2 + 8 * dev->mc_count]; // RowCount, Addresses u64 *work64 = (u64 *)(mc_table + 2); - filter_mask = 0x00000000; - dprintk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name); + filter_mask = 0x00000000; + printk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name); - /* Fill multicast addr table */ + /* Fill multicast addr table */ memset(mc_table, 0, sizeof(mc_table)); - memcpy(mc_table, &dev->mc_count, 2); - for (mc = dev->mc_list; mc ; mc = mc->next, work64++ ) - memcpy(work64, mc->dmi_addr, mc->dmi_addrlen); - + memcpy(mc_table, &dev->mc_count, 2); + for (mc = dev->mc_list; mc ; mc = mc->next, work64++ ) + memcpy(work64, mc->dmi_addr, mc->dmi_addrlen); + /* Clear old mc table, copy new table to */ - if (i2o_clear_table(iop, i2o_dev->lct_data->tid, 0x0002) < 0) - printk("%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name); + if (i2o_clear_table(iop, i2o_dev->lct_data.tid, 0x0002) < 0) + printk(KERN_INFO "%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n", dev->name); - if ((i2o_row_add_table(iop, i2o_dev->lct_data->tid, 0x0002, -1, - mc_table, sizeof(mc_table))) < 0) - printk("%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name); - } - - else { - filter_mask = 0x00000300; // Broadcast, Multicast disabled - printk(KERN_INFO "%s: Enabling unicast mode...\n",dev->name); - } + if ((i2o_row_add_table(iop, i2o_dev->lct_data.tid, 0x0002, -1, + mc_table, sizeof(mc_table))) < 0) + printk(KERN_INFO "%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n", dev->name); + } else { + filter_mask = 0x00000300; // Broadcast, Multicast disabled + printk(KERN_INFO "%s: Enabling unicast mode...\n", dev->name); + } /* Finally copy new FilterMask to */ - if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0001, 3, - &filter_mask, sizeof(filter_mask)) <0) - printk(KERN_WARNING "%s: Unable to set MAC FilterMask.\n",dev->name); + if (i2o_set_scalar(iop, i2o_dev->lct_data.tid, 0x0001, 3, + &filter_mask, sizeof(filter_mask)) <0) + printk(KERN_WARNING "%s: Unable to set MAC FilterMask.\n", dev->name); + + dev->xmit_lock_owner = -1; + spin_unlock(&dev->xmit_lock); +// read_unlock_bh(&dev_mc_lock); - return; + return; } +static struct tq_struct i2o_lan_set_mc_list_task = { + 0, 0, (void (*)(void *))i2o_lan_set_mc_list, (void *) 0 +}; + /* * i2o_lan_set_multicast_list(): * Queue routine i2o_lan_set_mc_list() to be called later. @@ -867,17 +1215,12 @@ static void i2o_lan_set_multicast_list(struct net_device *dev) { - struct tq_struct *task; - - task = (struct tq_struct *)kmalloc(sizeof(struct tq_struct), GFP_KERNEL); - if (task == NULL) - return; - - task->next = NULL; - task->sync = 0; - task->routine = (void *)i2o_lan_set_mc_list; - task->data = (void *)dev; - queue_task(task, &tq_scheduler); + if (!in_interrupt()) { + i2o_lan_set_mc_list_task.data = (void *)dev; + queue_task(&i2o_lan_set_mc_list_task, &tq_scheduler); + } else { + i2o_lan_set_mc_list(dev); + } } /* @@ -885,13 +1228,24 @@ */ static int i2o_lan_change_mtu(struct net_device *dev, int new_mtu) { - if ((new_mtu < 68) || (new_mtu > 9000)) + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + u32 max_pkt_size; + + if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid, + 0x0000, 6, &max_pkt_size, 4) < 0) + return -EFAULT; + + if (new_mtu < 68 || max_pkt_size < new_mtu) return -EINVAL; - + dev->mtu = new_mtu; return 0; } +/* Functions to initialize I2O LAN OSM: +======================================*/ + /* * i2o_lan_register_device(): Register LAN class device to kernel. */ @@ -904,9 +1258,9 @@ unsigned short (*type_trans)(struct sk_buff *, struct net_device *); void (*unregister_dev)(struct net_device *dev); - switch (i2o_dev->lct_data->sub_class) { + switch (i2o_dev->lct_data.sub_class) { case I2O_LAN_ETHERNET: - dev = init_etherdev(NULL, sizeof(struct i2o_lan_local)); + dev = init_etherdev(NULL, sizeof(struct i2o_lan_local)); if (dev == NULL) return NULL; type_trans = eth_type_trans; @@ -916,6 +1270,7 @@ #ifdef CONFIG_ANYLAN case I2O_LAN_100VG: printk(KERN_ERR "i2o_lan: 100base VG not yet supported.\n"); + return NULL; break; #endif @@ -925,7 +1280,7 @@ if (dev==NULL) return NULL; type_trans = tr_type_trans; - unregister_dev = unregister_trdev; + unregister_dev = unregister_trdev; break; #endif @@ -933,92 +1288,122 @@ case I2O_LAN_FDDI: { int size = sizeof(struct net_device) + sizeof(struct i2o_lan_local) - + sizeof("fddi%d "); + + sizeof("fddi%d "); - dev = (struct net_device *) kmalloc(size, GFP_KERNEL); - memset((char *)dev, 0, size); - dev->priv = (void *)(dev + 1); - dev->name = (char *)(dev + 1) + sizeof(struct i2o_lan_local); + dev = (struct net_device *) kmalloc(size, GFP_KERNEL); + if (dev == NULL) + return NULL; + memset((char *)dev, 0, size); + dev->priv = (void *)(dev + 1); + dev->name = (char *)(dev + 1) + sizeof(struct i2o_lan_local); - if (dev_alloc_name(dev,"fddi%d") < 0) { + if (dev_alloc_name(dev, "fddi%d") < 0) { printk(KERN_WARNING "i2o_lan: Too many FDDI devices.\n"); kfree(dev); return NULL; } type_trans = fddi_type_trans; unregister_dev = (void *)unregister_netdevice; - + fddi_setup(dev); register_netdev(dev); - } + } break; #endif -#ifdef CONFIG_FIBRE_CHANNEL +#ifdef CONFIG_NET_FC case I2O_LAN_FIBRE_CHANNEL: - printk(KERN_INFO "i2o_lan: Fibre Channel not yet supported.\n"); - break; + dev = init_fcdev(NULL, sizeof(struct i2o_lan_local)); + if (dev == NULL) + return NULL; + type_trans = NULL; +/* FIXME: Move fc_type_trans() from drivers/net/fc/iph5526.c to net/802/fc.c + * and export it in include/linux/fcdevice.h + * type_trans = fc_type_trans; + */ + unregister_dev = (void *)unregister_fcdev; + break; #endif case I2O_LAN_UNKNOWN: default: - printk(KERN_ERR "i2o_lan: LAN type 0x%08X not supported.\n", - i2o_dev->lct_data->sub_class); + printk(KERN_ERR "i2o_lan: LAN type 0x%04x not supported.\n", + i2o_dev->lct_data.sub_class); return NULL; } priv = (struct i2o_lan_local *)dev->priv; priv->i2o_dev = i2o_dev; priv->type_trans = type_trans; - priv->bucket_count = 0; priv->sgl_max = (i2o_dev->controller->inbound_size - 16) / 12; + atomic_set(&priv->buckets_out, 0); + + /* Set default values for user configurable parameters */ + /* Private values are changed via /proc file system */ + + priv->max_buckets_out = max_buckets_out; + priv->bucket_thresh = bucket_thresh; + priv->rx_copybreak = rx_copybreak; + priv->tx_batch_mode = tx_batch_mode; + priv->i2o_event_mask = i2o_event_mask; + + priv->tx_lock = SPIN_LOCK_UNLOCKED; + priv->fbl_lock = SPIN_LOCK_UNLOCKED; unit++; i2o_landevs[unit] = dev; priv->unit = unit; - if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid, + if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid, 0x0001, 0, &hw_addr, sizeof(hw_addr)) < 0) { - printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name); + printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name); unit--; unregister_dev(dev); kfree(dev); - return NULL; + return NULL; } - dprintk("%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->name,hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], - hw_addr[4], hw_addr[5]); + dprintk(KERN_DEBUG "%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + dev->name, hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], + hw_addr[4], hw_addr[5]); dev->addr_len = 6; memcpy(dev->dev_addr, hw_addr, 6); - if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid, - 0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0) - { - printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name); - unit--; - unregister_dev(dev); - kfree(dev); - return NULL; - } - dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out); - priv->tx_max_out = tx_max_out; - priv->tx_out = 0; - priv->tx_count = 0; - priv->lock = SPIN_LOCK_UNLOCKED; + if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data.tid, + 0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0) { + printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name); + unit--; + unregister_dev(dev); + kfree(dev); + return NULL; + } + dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out); + priv->tx_max_out = tx_max_out; + atomic_set(&priv->tx_out, 0); + priv->tx_count = 0; priv->i2o_batch_send_task.next = NULL; priv->i2o_batch_send_task.sync = 0; priv->i2o_batch_send_task.routine = (void *)i2o_lan_batch_send; priv->i2o_batch_send_task.data = (void *)dev; - dev->open = i2o_lan_open; - dev->stop = i2o_lan_close; - dev->hard_start_xmit = i2o_lan_packet_send; - dev->get_stats = i2o_lan_get_stats; + dev->open = i2o_lan_open; + dev->stop = i2o_lan_close; + dev->get_stats = i2o_lan_get_stats; dev->set_multicast_list = i2o_lan_set_multicast_list; - dev->change_mtu = i2o_lan_change_mtu; + dev->tx_timeout = i2o_lan_tx_timeout; + dev->watchdog_timeo = I2O_LAN_TX_TIMEOUT; + +#ifdef CONFIG_NET_FC + if (i2o_dev->lct_data.sub_class == I2O_LAN_FIBRE_CHANNEL) + dev->hard_start_xmit = i2o_lan_sdu_send; + else +#endif + dev->hard_start_xmit = i2o_lan_packet_send; + + if (i2o_dev->lct_data.sub_class == I2O_LAN_ETHERNET) + dev->change_mtu = i2o_lan_change_mtu; return dev; } @@ -1032,19 +1417,35 @@ struct net_device *dev; int i; - printk(KERN_INFO "Linux I2O LAN OSM (c) 1999 University of Helsinki.\n"); + printk(KERN_INFO "I2O LAN OSM (c) 1999 University of Helsinki.\n"); + + /* Module params used as global defaults for private values */ + + if (max_buckets_out > I2O_LAN_MAX_BUCKETS_OUT) + max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT; + if (bucket_thresh > max_buckets_out) + bucket_thresh = max_buckets_out; + + /* Install handlers for incoming replies */ + + if (i2o_install_handler(&i2o_lan_send_handler) < 0) { + printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n"); + return -EINVAL; + } + lan_send_context = i2o_lan_send_handler.context; - if (bucketpost > I2O_BUCKET_COUNT) - bucketpost = I2O_BUCKET_COUNT; - if (bucketthresh > bucketpost) - bucketthresh = bucketpost; + if (i2o_install_handler(&i2o_lan_receive_handler) < 0) { + printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n"); + return -EINVAL; + } + lan_receive_context = i2o_lan_receive_handler.context; if (i2o_install_handler(&i2o_lan_handler) < 0) { printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n"); return -EINVAL; } lan_context = i2o_lan_handler.context; - + for(i=0; i <= MAX_LAN_CARDS; i++) i2o_landevs[i] = NULL; @@ -1052,15 +1453,16 @@ struct i2o_controller *iop = i2o_find_controller(i); struct i2o_device *i2o_dev; - if (iop==NULL) continue; + if (iop==NULL) + continue; for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) { - if (i2o_dev->lct_data->class_id != I2O_CLASS_LAN) + if (i2o_dev->lct_data.class_id != I2O_CLASS_LAN) continue; /* Make sure device not already claimed by an ISM */ - if (i2o_dev->lct_data->user_tid != 0xFFF) + if (i2o_dev->lct_data.user_tid != 0xFFF) continue; if (unit == MAX_LAN_CARDS) { @@ -1071,14 +1473,16 @@ dev = i2o_lan_register_device(i2o_dev); if (dev == NULL) { - printk(KERN_ERR "i2o_lan: Unable to register I2O LAN device.\n"); - continue; // try next one + printk(KERN_ERR "i2o_lan: Unable to register I2O LAN device 0x%04x.\n", + i2o_dev->lct_data.sub_class); + continue; } - printk(KERN_INFO "%s: I2O LAN device registered, tid = %d," - " subclass = 0x%08X, unit = %d.\n", - dev->name, i2o_dev->lct_data->tid, i2o_dev->lct_data->sub_class, - ((struct i2o_lan_local *)dev->priv)->unit); + printk(KERN_INFO "%s: I2O LAN device registered, " + "subclass = 0x%04x, unit = %d, tid = %d.\n", + dev->name, i2o_dev->lct_data.sub_class, + ((struct i2o_lan_local *)dev->priv)->unit, + i2o_dev->lct_data.tid); } i2o_unlock_controller(iop); @@ -1097,45 +1501,55 @@ for (i = 0; i <= unit; i++) { struct net_device *dev = i2o_landevs[i]; - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; - switch (i2o_dev->lct_data->sub_class) { + switch (i2o_dev->lct_data.sub_class) { case I2O_LAN_ETHERNET: unregister_netdev(dev); - kfree(dev); break; #ifdef CONFIG_FDDI case I2O_LAN_FDDI: unregister_netdevice(dev); - kfree(dev); break; #endif #ifdef CONFIG_TR case I2O_LAN_TR: unregister_trdev(dev); - kfree(dev); + break; +#endif +#ifdef CONFIG_NET_FC + case I2O_LAN_FIBRE_CHANNEL: + unregister_fcdev(dev); break; #endif default: - printk(KERN_WARNING "i2o_lan: Spurious I2O LAN subclass 0x%08X.\n", - i2o_dev->lct_data->sub_class); + printk(KERN_WARNING "%s: Spurious I2O LAN subclass 0x%08x.\n", + dev->name, i2o_dev->lct_data.sub_class); } dprintk(KERN_INFO "%s: I2O LAN device unregistered.\n", dev->name); + kfree(dev); } i2o_remove_handler(&i2o_lan_handler); + i2o_remove_handler(&i2o_lan_send_handler); + i2o_remove_handler(&i2o_lan_receive_handler); } EXPORT_NO_SYMBOLS; -MODULE_AUTHOR("Univ of Helsinki, CS Department"); +MODULE_AUTHOR("University of Helsinki, Department of Computer Science"); MODULE_DESCRIPTION("I2O Lan OSM"); -MODULE_PARM(bucketpost, "i"); // Total number of buckets to post -MODULE_PARM(bucketthresh, "i"); // Bucket post threshold -MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(max_buckets_out, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i"); +MODULE_PARM_DESC(max_buckets_out, "Total number of buckets to post (1-)"); +MODULE_PARM(bucket_thresh, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i"); +MODULE_PARM_DESC(bucket_thresh, "Bucket post threshold (1-)"); +MODULE_PARM(rx_copybreak, "1-" "i"); +MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy only small frames (1-)"); +MODULE_PARM(tx_batch_mode, "0-1" "i"); +MODULE_PARM_DESC(tx_batch_mode, "0=Use immediate mode send, 1=Use batch mode send"); #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_lan.h linux/drivers/i2o/i2o_lan.h --- v2.3.99-pre5/linux/drivers/i2o/i2o_lan.h Tue Jan 11 22:31:40 2000 +++ linux/drivers/i2o/i2o_lan.h Wed Apr 12 09:38:53 2000 @@ -1,24 +1,29 @@ /* - * i2o_lan.h LAN Class specific definitions + * i2o_lan.h I2O LAN Class definitions * - * I2O LAN CLASS OSM Prototyping, May 17th 1999 + * I2O LAN CLASS OSM April 3rd 2000 * - * (C) Copyright 1999 University of Helsinki, - * Department of Computer Science + * (C) Copyright 1999, 2000 University of Helsinki, + * Department of Computer Science * * This code is still under development / test. * - * Author: Auvo Häkkinen - * Juha Sievänen + * Author: Auvo Häkkinen + * Juha Sievänen + * Taneli Vähäkangas */ #ifndef _I2O_LAN_H #define _I2O_LAN_H -/* Tunable parameters first */ +/* Default values for tunable parameters first */ -#define I2O_BUCKET_COUNT 256 -#define I2O_BUCKET_THRESH 18 /* 9 buckets in one message */ +#define I2O_LAN_MAX_BUCKETS_OUT 256 +#define I2O_LAN_BUCKET_THRESH 18 /* 9 buckets in one message */ +#define I2O_LAN_RX_COPYBREAK 200 +#define I2O_LAN_TX_TIMEOUT (1*HZ) +#define I2O_LAN_TX_BATCH_MODE 1 /* 1=on, 0=off */ +#define I2O_LAN_EVENT_MASK 0 /* 0=None, 0xFFC00002=All */ /* LAN types */ #define I2O_LAN_ETHERNET 0x0030 @@ -114,5 +119,38 @@ #define I2O_LAN_EVT_LINK_DOWN 0x01 #define I2O_LAN_EVT_LINK_UP 0x02 #define I2O_LAN_EVT_MEDIA_CHANGE 0x04 - + +#include +#include + +struct i2o_lan_local { + u8 unit; + struct i2o_device *i2o_dev; + struct fddi_statistics stats; /* see also struct net_device_stats */ + unsigned short (*type_trans)(struct sk_buff *, struct net_device *); + atomic_t buckets_out; /* nbr of unused buckets on DDM */ + atomic_t tx_out; /* outstanding TXes */ + u8 tx_count; /* packets in one TX message frame */ + u16 tx_max_out; /* DDM's Tx queue len */ + u8 sgl_max; /* max SGLs in one message frame */ + u32 m; /* IOP address of msg frame */ + + struct tq_struct i2o_batch_send_task; + int send_active; + struct sk_buff **i2o_fbl; /* Free bucket list (to reuse skbs) */ + int i2o_fbl_tail; + spinlock_t fbl_lock; + + spinlock_t tx_lock; + + /* LAN OSM configurable parameters are here: */ + + u16 max_buckets_out; /* max nbr of buckets to send to DDM */ + u16 bucket_thresh; /* send more when this many used */ + u16 rx_copybreak; + + u8 tx_batch_mode; /* Set when using batch mode sends */ + u32 i2o_event_mask; /* To turn on interesting event flags */ +}; + #endif /* _I2O_LAN_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c --- v2.3.99-pre5/linux/drivers/i2o/i2o_pci.c Thu Jan 6 12:57:47 2000 +++ linux/drivers/i2o/i2o_pci.c Wed Apr 12 09:38:53 2000 @@ -53,8 +53,10 @@ iounmap(((u8 *)c->post_port)-0x40); #ifdef CONFIG_MTRR - if(c->bus.pci.mtrr_reg > 0) - mtrr_del(c->bus.pci.mtrr_reg, 0, 0); + if(c->bus.pci.mtrr_reg0 > 0) + mtrr_del(c->bus.pci.mtrr_reg0, 0, 0); + if(c->bus.pci.mtrr_reg1 > 0) + mtrr_del(c->bus.pci.mtrr_reg1, 0, 0); #endif } @@ -176,8 +178,22 @@ * Enable Write Combining MTRR for IOP's memory region */ #ifdef CONFIG_MTRR - c->bus.pci.mtrr_reg = - mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1); + c->bus.pci.mtrr_reg0 = + mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1); +/* +* If it is an INTEL i960 I/O processor then set the first 64K to Uncacheable +* since the region contains the Messaging unit which shouldn't be cached. +*/ + c->bus.pci.mtrr_reg1 = -1; + if(dev->vendor == PCI_VENDOR_ID_INTEL) + { + printk(KERN_INFO "i2o_pci: MTRR workaround for Intel i960 processor\n"); + c->bus.pci.mtrr_reg1 = + mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1); + if(c->bus.pci.mtrr_reg1< 0) + printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n"); + } + #endif I2O_IRQ_WRITE32(c,0xFFFFFFFF); @@ -230,7 +246,8 @@ printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n"); - pci_for_each_dev(dev) { + pci_for_each_dev(dev) + { if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O) continue; if((dev->class&0xFF)>1) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c --- v2.3.99-pre5/linux/drivers/i2o/i2o_proc.c Tue Jan 11 22:31:40 2000 +++ linux/drivers/i2o/i2o_proc.c Wed Apr 12 09:38:53 2000 @@ -29,7 +29,7 @@ /* * TODO List * - * - Add support for any version 2.0 spec changes once 2.0 IRTOS + * - Add support for any version 2.0 spec changes once 2.0 IRTOS is * is available to test with * - Clean up code to use official structure definitions */ @@ -64,6 +64,8 @@ write_proc_t *write_proc; /* write func */ } i2o_proc_entry; +// #define DRIVERDEBUG + static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *); @@ -97,8 +99,12 @@ struct proc_dir_entry * ); static void i2o_proc_remove_controller(struct i2o_controller *, struct proc_dir_entry * ); +static void i2o_proc_add_device(struct i2o_device *, struct proc_dir_entry *); +static void i2o_proc_remove_device(struct i2o_device *); static int create_i2o_procfs(void); static int destroy_i2o_procfs(void); +static void i2o_proc_new_dev(struct i2o_controller *, struct i2o_device *); +static void i2o_proc_dev_del(struct i2o_controller *, struct i2o_device *); static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *, void *); @@ -130,6 +136,20 @@ static struct proc_dir_entry *i2o_proc_dir_root; /* + * I2O OSM descriptor + */ +static struct i2o_handler i2o_proc_handler = +{ + NULL, + i2o_proc_new_dev, + i2o_proc_dev_del, + NULL, + "I2O procfs Layer", + 0, + 0xffffffff // All classes +}; + +/* * IOP specific entries...write field just in case someone * ever wants one. */ @@ -240,6 +260,7 @@ {NULL, 0, NULL, NULL} }; + static char *chtostr(u8 *chars, int n) { char tmp[256]; @@ -412,6 +433,9 @@ if(lct->boot_tid) len += sprintf(buf+len, "Boot Device @ ID %d\n", lct->boot_tid); + len += + sprintf(buf+len, "Current Change Indicator: %#10x\n", lct->change_ind); + for(i = 0; i < entries; i++) { len += sprintf(buf+len, "Entry %d\n", i); @@ -1024,7 +1048,7 @@ len = 0; token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data->tid, 0xF000, -1, NULL, 0, + d->controller, d->lct_data.tid, 0xF000, -1, NULL, 0, &result, sizeof(result)); if (token < 0) { @@ -1088,7 +1112,7 @@ len = 0; token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data->tid, + d->controller, d->lct_data.tid, 0xF001, -1, NULL, 0, &result, sizeof(result)); @@ -1137,7 +1161,7 @@ len = 0; token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data->tid, + d->controller, d->lct_data.tid, 0xF002, -1, NULL, 0, &result, sizeof(result)); @@ -1196,7 +1220,7 @@ len = 0; token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data->tid, + d->controller, d->lct_data.tid, 0xF003, -1, NULL, 0, &result, sizeof(result)); @@ -1255,7 +1279,7 @@ len = 0; token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data->tid, + d->controller, d->lct_data.tid, 0xF000, -1, NULL, 0, &result, sizeof(result)); @@ -1310,7 +1334,7 @@ len = 0; token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data->tid, + d->controller, d->lct_data.tid, 0xF006, -1, NULL, 0, &result, sizeof(result)); @@ -1352,7 +1376,7 @@ len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0xF100, -1, &work32, sizeof(work32)); @@ -1421,7 +1445,7 @@ len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0xF101, -1, &result, sizeof(result)); @@ -1464,7 +1488,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0xF102, -1, &result, sizeof(result)); @@ -1497,7 +1521,7 @@ len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0xF103, -1, &work32, sizeof(work32)); @@ -1573,7 +1597,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0xF200, -1, &result, sizeof(result)); @@ -2020,7 +2044,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0000, -1, &work32, 56*4); if (token < 0) { len += i2o_report_query_status(buf+len, token, "0x0000 LAN Device Info"); @@ -2142,7 +2166,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0001, -1, &work32, 48*4); if (token < 0) { len += i2o_report_query_status(buf+len, token,"0x0001 LAN MAC Address"); @@ -2240,7 +2264,7 @@ len = 0; token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data->tid, 0x0002, -1, + d->controller, d->lct_data.tid, 0x0002, -1, NULL, 0, &result, sizeof(result)); if (token < 0) { @@ -2275,7 +2299,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0003, -1, &work32, 9*4); if (token < 0) { len += i2o_report_query_status(buf+len, token,"0x0003 LAN Batch Control"); @@ -2316,7 +2340,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0004, -1, &work32, 20); if (token < 0) { len += i2o_report_query_status(buf+len, token,"0x0004 LAN Operation"); @@ -2389,7 +2413,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0005, -1, &result, sizeof(result)); if (token < 0) { len += i2o_report_query_status(buf+len, token, "0x0005 LAN Media Operation"); @@ -2471,7 +2495,7 @@ len = 0; token = i2o_query_table(I2O_PARAMS_TABLE_GET, - d->controller, d->lct_data->tid, + d->controller, d->lct_data.tid, 0x0006, -1, NULL, 0, &result, sizeof(result)); if (token < 0) { @@ -2506,7 +2530,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0007, -1, &work32, 8*4); if (token < 0) { len += i2o_report_query_status(buf+len, token,"0x0007 LAN Transmit Info"); @@ -2558,7 +2582,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0008, -1, &work32, 8*4); if (token < 0) { len += i2o_report_query_status(buf+len, token,"0x0008 LAN Receive Info"); @@ -2675,7 +2699,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0100, -1, &stats, sizeof(stats)); if (token < 0) { len += i2o_report_query_status(buf+len, token,"0x100 LAN Statistics"); @@ -2705,7 +2729,7 @@ /* Optional statistics follows */ /* Get 0x0180 to see which optional groups/fields are supported */ - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0180, -1, &supp_groups, sizeof(supp_groups)); if (token < 0) { @@ -2716,7 +2740,7 @@ if (supp_groups[1]) /* 0x0182 */ { - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0182, -1, &tx_stats, sizeof(tx_stats)); if (token < 0) { @@ -2749,7 +2773,7 @@ if (supp_groups[2]) /* 0x0183 */ { - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0183, -1, &rx_stats, sizeof(rx_stats)); if (token < 0) { len += i2o_report_query_status(buf+len, token,"0x183 LAN Optional Rx Historical Stats"); @@ -2785,7 +2809,7 @@ if (supp_groups[3]) /* 0x0184 */ { - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0184, -1, &chksum_stats, sizeof(chksum_stats)); if (token < 0) { @@ -2864,7 +2888,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0200, -1, &stats, sizeof(stats)); if (token < 0) { @@ -2893,7 +2917,7 @@ /* Optional Ethernet statistics follows */ /* Get 0x0280 to see which optional fields are supported */ - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0280, -1, &supp_fields, sizeof(supp_fields)); if (token < 0) { @@ -2904,7 +2928,7 @@ if (supp_fields) /* 0x0281 */ { - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0281, -1, &stats, sizeof(stats)); if (token < 0) { @@ -2959,7 +2983,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0300, -1, &work64, sizeof(work64)); if (token < 0) { @@ -3053,7 +3077,7 @@ spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_scalar(d->controller, d->lct_data->tid, + token = i2o_query_scalar(d->controller, d->lct_data.tid, 0x0400, -1, &work64, sizeof(work64)); if (token < 0) { @@ -3135,78 +3159,117 @@ for(dev = pctrl->devices; dev; dev = dev->next) { - sprintf(buff, "%0#5x", dev->lct_data->tid); + sprintf(buff, "%0#5x", dev->lct_data.tid); dir1 = proc_mkdir(buff, dir); dev->proc_entry = dir1; if(!dir1) printk(KERN_INFO "i2o_proc: Could not allocate proc dir\n"); - - i2o_proc_create_entries(dev, generic_dev_entries, dir1); - switch(dev->lct_data->class_id) - { + i2o_proc_add_device(dev, dir1); + } + + return 0; +} + +void i2o_proc_new_dev(struct i2o_controller *c, struct i2o_device *d) +{ + char buff[10]; + +#ifdef DRIVERDEBUG + printk(KERN_INFO "Adding new device to /proc/i2o/iop%d\n", c->unit); +#endif + sprintf(buff, "%0#5x", d->lct_data.tid); + + d->proc_entry = proc_mkdir(buff, c->proc_entry); + + if(!d->proc_entry) + { + printk(KERN_WARNING "i2o: Could not allocate procdir!\n"); + return; + } + + i2o_proc_add_device(d, d->proc_entry); +} + +void i2o_proc_add_device(struct i2o_device *dev, struct proc_dir_entry *dir) +{ + i2o_proc_create_entries(dev, generic_dev_entries, dir); + + /* Inform core that we want updates about this device's status */ + i2o_device_notify_on(dev, &i2o_proc_handler); + switch(dev->lct_data.class_id) + { case I2O_CLASS_SCSI_PERIPHERAL: case I2O_CLASS_RANDOM_BLOCK_STORAGE: - i2o_proc_create_entries(dev, rbs_dev_entries, dir1); + i2o_proc_create_entries(dev, rbs_dev_entries, dir); break; case I2O_CLASS_LAN: - i2o_proc_create_entries(dev, lan_entries, dir1); - switch(dev->lct_data->sub_class) + i2o_proc_create_entries(dev, lan_entries, dir); + switch(dev->lct_data.sub_class) { - case I2O_LAN_ETHERNET: - i2o_proc_create_entries(dev, lan_eth_entries, - dir1); - break; - case I2O_LAN_FDDI: - i2o_proc_create_entries(dev, lan_fddi_entries, - dir1); - break; - case I2O_LAN_TR: - i2o_proc_create_entries(dev, lan_tr_entries, - dir1); - break; - default: - break; + case I2O_LAN_ETHERNET: + i2o_proc_create_entries(dev, lan_eth_entries, dir); + break; + case I2O_LAN_FDDI: + i2o_proc_create_entries(dev, lan_fddi_entries, dir); + break; + case I2O_LAN_TR: + i2o_proc_create_entries(dev, lan_tr_entries, dir); + break; + default: + break; } break; default: break; - } } - - return 0; } static void i2o_proc_remove_controller(struct i2o_controller *pctrl, struct proc_dir_entry *parent) { char buff[10]; - char dev_id[10]; - struct proc_dir_entry *de; struct i2o_device *dev; /* Remove unused device entries */ for(dev=pctrl->devices; dev; dev=dev->next) + i2o_proc_remove_device(dev); + + if(!pctrl->proc_entry->count) { - de=dev->proc_entry; - sprintf(dev_id, "%0#5x", dev->lct_data->tid); + sprintf(buff, "iop%d", pctrl->unit); - /* Would it be safe to remove _files_ even if they are in use? */ - if((de) && (!de->count)) - { - i2o_proc_remove_entries(generic_dev_entries, de); + i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry); - switch(dev->lct_data->class_id) - { + remove_proc_entry(buff, parent); + pctrl->proc_entry = NULL; + } +} + +void i2o_proc_remove_device(struct i2o_device *dev) +{ + struct proc_dir_entry *de=dev->proc_entry; + char dev_id[10]; + + sprintf(dev_id, "%0#5x", dev->lct_data.tid); + + i2o_device_notify_off(dev, &i2o_proc_handler); + /* Would it be safe to remove _files_ even if they are in use? */ + if((de) && (!de->count)) + { + i2o_proc_remove_entries(generic_dev_entries, de); + switch(dev->lct_data.class_id) + { case I2O_CLASS_SCSI_PERIPHERAL: case I2O_CLASS_RANDOM_BLOCK_STORAGE: i2o_proc_remove_entries(rbs_dev_entries, de); break; case I2O_CLASS_LAN: + { i2o_proc_remove_entries(lan_entries, de); - switch(dev->lct_data->sub_class) + switch(dev->lct_data.sub_class) { case I2O_LAN_ETHERNET: i2o_proc_remove_entries(lan_eth_entries, de); @@ -3219,19 +3282,19 @@ break; } } - remove_proc_entry(dev_id, parent); + remove_proc_entry(dev_id, dev->controller->proc_entry); } } +} + +void i2o_proc_dev_del(struct i2o_controller *c, struct i2o_device *d) +{ +#ifdef DRIVERDEBUG + printk(KERN_INFO, "Deleting device %d from iop%d\n", + d->lct_data.tid, c->unit); +#endif - if(!pctrl->proc_entry->count) - { - sprintf(buff, "iop%d", pctrl->unit); - - i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry); - - remove_proc_entry(buff, parent); - pctrl->proc_entry = NULL; - } + i2o_proc_remove_device(d); } static int create_i2o_procfs(void) @@ -3278,13 +3341,19 @@ return 0; } - + #ifdef MODULE #define i2o_proc_init init_module #endif int __init i2o_proc_init(void) { + if (i2o_install_handler(&i2o_proc_handler) < 0) + { + printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n"); + return 0; + } + if(create_i2o_procfs()) return -EBUSY; @@ -3293,12 +3362,12 @@ #ifdef MODULE - MODULE_AUTHOR("Deepak Saxena"); MODULE_DESCRIPTION("I2O procfs Handler"); void cleanup_module(void) { destroy_i2o_procfs(); + i2o_remove_handler(&i2o_proc_handler); } #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c --- v2.3.99-pre5/linux/drivers/i2o/i2o_scsi.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/i2o/i2o_scsi.c Wed Apr 12 09:38:53 2000 @@ -288,6 +288,9 @@ struct i2o_handler i2o_scsi_handler= { i2o_scsi_reply, + NULL, + NULL, + NULL, "I2O SCSI OSM", 0, I2O_CLASS_SCSI_PERIPHERAL @@ -297,12 +300,12 @@ { u8 reply[8]; - if(i2o_query_scalar(c, d->lct_data->tid, 0, 3, reply, 4)<0) + if(i2o_query_scalar(c, d->lct_data.tid, 0, 3, reply, 4)<0) return -1; *target=reply[0]; - if(i2o_query_scalar(c, d->lct_data->tid, 0, 4, reply, 8)<0) + if(i2o_query_scalar(c, d->lct_data.tid, 0, 4, reply, 8)<0) return -1; *lun=reply[1]; @@ -319,7 +322,7 @@ int target; h->controller=c; - h->bus_task=d->lct_data->tid; + h->bus_task=d->lct_data.tid; for(target=0;target<16;target++) for(lun=0;lun<8;lun++) @@ -328,33 +331,33 @@ for(unit=c->devices;unit!=NULL;unit=unit->next) { dprintk(("Class %03X, parent %d, want %d.\n", - unit->lct_data->class_id, unit->lct_data->parent_tid, d->lct_data->tid)); + unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid)); /* Only look at scsi and fc devices */ - if ( (unit->lct_data->class_id != I2O_CLASS_SCSI_PERIPHERAL) - && (unit->lct_data->class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL) + if ( (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL) + && (unit->lct_data.class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL) ) continue; /* On our bus ? */ - dprintk(("Found a disk (%d).\n", unit->lct_data->tid)); - if ((unit->lct_data->parent_tid == d->lct_data->tid) - || (unit->lct_data->parent_tid == d->lct_data->parent_tid) + dprintk(("Found a disk (%d).\n", unit->lct_data.tid)); + if ((unit->lct_data.parent_tid == d->lct_data.tid) + || (unit->lct_data.parent_tid == d->lct_data.parent_tid) ) { u16 limit; dprintk(("Its ours.\n")); if(i2o_find_lun(c, unit, &target, &lun)==-1) { - printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data->tid); + printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid); continue; } dprintk(("Found disk %d %d.\n", target, lun)); - h->task[target][lun]=unit->lct_data->tid; + h->task[target][lun]=unit->lct_data.tid; h->tagclock[target][lun]=jiffies; /* Get the max fragments/request */ - i2o_query_scalar(c, d->lct_data->tid, 0xF103, 3, &limit, 2); + i2o_query_scalar(c, d->lct_data.tid, 0xF103, 3, &limit, 2); /* sanity */ if ( limit == 0 ) @@ -428,8 +431,8 @@ /* * bus_adapter, SCSI (obsolete), or FibreChannel busses only */ - if( (d->lct_data->class_id!=I2O_CLASS_BUS_ADAPTER_PORT) // bus_adapter -// && (d->lct_data->class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT) // FC_PORT + if( (d->lct_data.class_id!=I2O_CLASS_BUS_ADAPTER_PORT) // bus_adapter +// && (d->lct_data.class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT) // FC_PORT ) continue; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/Config.in linux/drivers/ide/Config.in --- v2.3.99-pre5/linux/drivers/ide/Config.in Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/Config.in Mon Apr 24 18:59:07 2000 @@ -16,7 +16,7 @@ dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE - dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE + dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI comment 'IDE chipset support/bugfixes' if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then @@ -35,8 +35,8 @@ define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL $CONFIG_EXPERIMENTAL dep_bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL dep_bool ' Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP - dep_bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 $CONFIG_BLK_DEV_IDEDMA_PCI - dep_mbool ' AEC6210 Tuning support (WIP)' CONFIG_AEC6210_TUNING $CONFIG_BLK_DEV_AEC6210 $CONFIG_IDEDMA_PCI_WIP + dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI + dep_mbool ' AEC62XX Tuning support (WIP)' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX $CONFIG_IDEDMA_PCI_WIP dep_bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 dep_bool ' AMD Viper support' CONFIG_BLK_DEV_AMD7409 $CONFIG_BLK_DEV_IDEDMA_PCI @@ -62,6 +62,7 @@ dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI + dep_mbool ' VIA82CXXX Tuning support (WIP)' CONFIG_VIA82CXXX_TUNING $CONFIG_BLK_DEV_VIA82CXXX $CONFIG_IDEDMA_PCI_WIP fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 @@ -122,7 +123,7 @@ fi if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ - "$CONFIG_BLK_DEV_AEC6210" = "y" -o \ + "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \ "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \ "$CONFIG_BLK_DEV_AMD7409" = "y" -o \ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ @@ -136,7 +137,8 @@ "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ - "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then + "$CONFIG_BLK_DEV_SL82C105" = "y" -o \ + "$CONFIG_BLK_DEV_VIA82CXXX" = "y" ]; then define_bool CONFIG_BLK_DEV_IDE_MODES y else define_bool CONFIG_BLK_DEV_IDE_MODES n diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/Makefile linux/drivers/ide/Makefile --- v2.3.99-pre5/linux/drivers/ide/Makefile Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/Makefile Thu Apr 13 22:54:26 2000 @@ -25,8 +25,8 @@ LX_OBJS := MX_OBJS := -ifeq ($(CONFIG_BLK_DEV_AEC6210),y) -IDE_OBJS += aec6210.o +ifeq ($(CONFIG_BLK_DEV_AEC62XX),y) +IDE_OBJS += aec62xx.o endif ifeq ($(CONFIG_BLK_DEV_ALI14XX),y) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/aec6210.c linux/drivers/ide/aec6210.c --- v2.3.99-pre5/linux/drivers/ide/aec6210.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/aec6210.c Wed Dec 31 16:00:00 1969 @@ -1,376 +0,0 @@ -/* - * linux/drivers/ide/aec6210.c Version 0.06 Mar. 18, 2000 - * - * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) - * May be copied or modified under the terms of the GNU General Public License - * - * pio 0 :: 40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02 - * pio 1 :: 40: 0a 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02 - * pio 2 :: 40: 08 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02 - * pio 3 :: 40: 03 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 - * pio 4 :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 - * dma 0 :: 40: 0a 07 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 - * dma 1 :: 40: 02 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 - * dma 2 :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 - * 50: ff ff ff ff 00 06 04 00 00 00 00 00 00 00 00 00 - * - * udma 0 :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 - * 50: ff ff ff ff 01 06 04 00 00 00 00 00 00 00 00 00 - * - * udma 1 :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 - * 50: ff ff ff ff 01 06 04 00 00 00 00 00 00 00 00 00 - * - * udma 2 :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 - * 50: ff ff ff ff 02 06 04 00 00 00 00 00 00 00 00 00 - * - * auto :: 40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02 - * 50: ff ff ff ff 02 06 04 00 00 00 00 00 00 00 00 00 - * - * auto :: 40: 01 04 01 04 01 04 01 04 02 05 a6 cf 00 02 00 02 - * 50: ff ff ff ff aa 06 04 00 00 00 00 00 00 00 00 00 - * - * NO-Devices - * 40: 00 00 00 00 00 00 00 00 02 05 a6 00 00 02 00 02 - * 50: ff ff ff ff 00 06 00 00 00 00 00 00 00 00 00 00 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "ide_modes.h" - -#define ACARD_DEBUG_DRIVE_INFO 0 - -#undef DISPLAY_AEC6210_TIMINGS - -#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) -#include -#include - -static int aec6210_get_info(char *, char **, off_t, int); -extern int (*aec6210_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); -static struct pci_dev *bmide_dev; - -static int aec6210_get_info (char *buffer, char **addr, off_t offset, int count) -{ - char *p = buffer; - - u32 bibma = bmide_dev->resource[4].start; - u8 c0 = 0, c1 = 0; - - p += sprintf(p, "\n AEC6210 Chipset.\n"); - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb_p((unsigned short)bibma + 0x02); - c1 = inb_p((unsigned short)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\n"); - p += sprintf(p, "DMA\n"); - p += sprintf(p, "PIO\n"); - return p-buffer;/* => must be less than 4k! */ -} -#endif /* defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) */ - -byte aec6210_proc = 0; - -#ifdef CONFIG_AEC6210_TUNING - -struct chipset_bus_clock_list_entry { - byte xfer_speed; - unsigned short chipset_settings; - byte ultra_settings; -}; - -struct chipset_bus_clock_list_entry aec6210_base [] = { - { XFER_UDMA_2, 0x0401, 0x02 }, - { XFER_UDMA_1, 0x0401, 0x01 }, - { XFER_UDMA_0, 0x0401, 0x01 }, - - { XFER_MW_DMA_2, 0x0401, 0x00 }, - { XFER_MW_DMA_1, 0x0402, 0x00 }, - { XFER_MW_DMA_0, 0x070a, 0x00 }, - - { XFER_PIO_4, 0x0401, 0x00 }, - { XFER_PIO_3, 0x0403, 0x00 }, - { XFER_PIO_2, 0x0708, 0x00 }, - { XFER_PIO_1, 0x070a, 0x00 }, - { XFER_PIO_0, 0x0700, 0x00 }, - { 0, 0x0000, 0x00 } -}; - -extern char *ide_xfer_verbose (byte xfer_rate); - -/* - * TO DO: active tuning and correction of cards without a bios. - */ - -static unsigned short pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) -{ - for ( ; chipset_table->xfer_speed ; chipset_table++) - if (chipset_table->xfer_speed == speed) { - return chipset_table->chipset_settings; - } - return 0x0000; -} - -static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table) -{ - for ( ; chipset_table->xfer_speed ; chipset_table++) - if (chipset_table->xfer_speed == speed) { - return chipset_table->ultra_settings; - } - return 0x00; -} - -static int aec6210_tune_chipset (ide_drive_t *drive, byte speed) -{ - ide_hwif_t *hwif = HWIF(drive); - - int err; - byte drive_pci; - unsigned short drive_conf = 0x0000; - byte ultra = 0x00, ultra_conf = 0x00; - byte tmp1 = 0x00, tmp2 = 0x00; - - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - - switch(drive_number) { - case 0: drive_pci = 0x40; break; - case 1: drive_pci = 0x42; break; - case 2: drive_pci = 0x44; break; - case 3: drive_pci = 0x46; break; - default: return -1; - } - - pci_read_config_word(HWIF(drive)->pci_dev, drive_pci, &drive_conf); - drive_conf = pci_bus_clock_list(speed, aec6210_base); - pci_write_config_word(HWIF(drive)->pci_dev, drive_pci, drive_conf); - - pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, &ultra); - tmp1 = ((0x00 << (2*drive_number)) | (ultra & ~(3 << (2*drive_number)))); - ultra_conf = pci_bus_clock_list_ultra(speed, aec6210_base); - tmp2 = ((ultra_conf << (2*drive_number)) | (tmp1 & ~(3 << (2*drive_number)))); - pci_write_config_byte(HWIF(drive)->pci_dev, 0x54, tmp2); - - err = ide_config_drive_speed(drive, speed); - -#if ACARD_DEBUG_DRIVE_INFO - printk("%s: %s drive%d 0x04%x 0x02%x 0x02%x 0x02%x 0x02%x\n", - drive->name, ide_xfer_verbose(speed), drive_number, - drive_conf, ultra, tmp1, ultra_conf, tmp2); -#endif /* ACARD_DEBUG_DRIVE_INFO */ - - return(err); -} - -#ifdef CONFIG_BLK_DEV_IDEDMA -static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) -{ - struct hd_driveid *id = drive->id; - byte speed = -1; - - if (drive->media != ide_disk) - return ((int) ide_dma_off_quietly); - - if (((id->dma_ultra & 0x0010) || - (id->dma_ultra & 0x0008) || - (id->dma_ultra & 0x0004)) && (ultra)) { - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && (ultra)) { - speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && (ultra)) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; - } else { - return ((int) ide_dma_off_quietly); - } - (void) aec6210_tune_chipset(drive, speed); - - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); -} -#endif /* CONFIG_BLK_DEV_IDEDMA */ - -static void aec6210_tune_drive (ide_drive_t *drive, byte pio) -{ - byte speed; - - switch(pio) { - case 5: - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); - case 4: - speed = XFER_PIO_4; break; - case 3: - speed = XFER_PIO_3; break; - case 2: - speed = XFER_PIO_2; break; - case 1: - speed = XFER_PIO_1; break; - default: - speed = XFER_PIO_0; break; - } - (void) aec6210_tune_chipset(drive, speed); -} - -#ifdef CONFIG_BLK_DEV_IDEDMA -static int config_drive_xfer_rate (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - ide_dma_action_t dma_func = ide_dma_on; - - if (id && (id->capability & 1) && HWIF(drive)->autodma) { - /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive)) { - dma_func = ide_dma_off; - goto fast_ata_pio; - } - dma_func = ide_dma_off_quietly; - if (id->field_valid & 4) { - if (id->dma_ultra & 0x001F) { - /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, 1); - if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) - goto try_dma_modes; - } - } else if (id->field_valid & 2) { -try_dma_modes: - if ((id->dma_mword & 0x0007) || - (id->dma_1word & 0x0007)) { - /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, 0); - if (dma_func != ide_dma_on) - goto no_dma_set; - } - } else if (ide_dmaproc(ide_dma_good_drive, drive)) { - if (id->eide_dma_time > 150) { - goto no_dma_set; - } - /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, 0); - if (dma_func != ide_dma_on) - goto no_dma_set; - } else { - goto fast_ata_pio; - } - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - dma_func = ide_dma_off_quietly; -no_dma_set: - aec6210_tune_drive(drive, 5); - } - return HWIF(drive)->dmaproc(dma_func, drive); -} - -/* - * aec6210_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. - */ -int aec6210_dmaproc (ide_dma_action_t func, ide_drive_t *drive) -{ - switch (func) { - case ide_dma_check: - return config_drive_xfer_rate(drive); - default: - break; - } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ -} -#endif /* CONFIG_BLK_DEV_IDEDMA */ -#endif /* CONFIG_AEC6210_TUNING */ - -unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) -{ - if (dev->resource[PCI_ROM_RESOURCE].start) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); - } - -#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) - aec6210_proc = 1; - bmide_dev = dev; - aec6210_display_info = &aec6210_get_info; -#endif /* DISPLAY_AEC6210_TIMINGS && CONFIG_PROC_FS */ - - return dev->irq; -} - -void __init ide_init_aec6210 (ide_hwif_t *hwif) -{ -#ifdef CONFIG_AEC6210_TUNING - hwif->tuneproc = &aec6210_tune_drive; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - -#ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_base) - hwif->dmaproc = &aec6210_dmaproc; -#endif /* CONFIG_BLK_DEV_IDEDMA */ -#endif /* CONFIG_AEC6210_TUNING */ -} - -void __init ide_dmacapable_aec6210 (ide_hwif_t *hwif, unsigned long dmabase) -{ - byte dma_new = 0; - byte dma_old = inb(dmabase+2); - byte reg54h = 0; - byte masterdma = hwif->channel ? 0x30 : 0x03; - byte slavedma = hwif->channel ? 0xc0 : 0x0c; - unsigned long flags; - - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ - - dma_new = dma_old; - - pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); - - if (reg54h & masterdma) dma_new |= 0x20; - if (reg54h & slavedma) dma_new |= 0x40; - if (dma_new != dma_old) outb(dma_new, dmabase+2); - - __restore_flags(flags); /* local CPU only */ - - ide_setup_dma(hwif, dmabase, 8); -} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/aec62xx.c linux/drivers/ide/aec62xx.c --- v2.3.99-pre5/linux/drivers/ide/aec62xx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/ide/aec62xx.c Thu Apr 13 22:54:26 2000 @@ -0,0 +1,553 @@ +/* + * linux/drivers/ide/aec62xx.c Version 0.08 Mar. 28, 2000 + * + * Copyright (C) 2000 Andre Hedrick (andre@suse.com) + * May be copied or modified under the terms of the GNU General Public License + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "ide_modes.h" + +#define DISPLAY_AEC62XX_TIMINGS + +#ifndef HIGH_4 +#define HIGH_4(H) ((H)=(H>>4)) +#endif +#ifndef LOW_4 +#define LOW_4(L) ((L)=(L-((L>>4)<<4))) +#endif +#ifndef SPLIT_BYTE +#define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) +#endif +#ifndef MAKE_WORD +#define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB)) +#endif + + +#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int aec62xx_get_info(char *, char **, off_t, int); +extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + u8 art = 0, uart = 0; + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_ARTOP_ATP850UF: + p += sprintf(p, "\n AEC6210 Chipset.\n"); + break; + case PCI_DEVICE_ID_ARTOP_ATP860: + p += sprintf(p, "\n AEC6260 No Bios Chipset.\n"); + break; + case PCI_DEVICE_ID_ARTOP_ATP860R: + p += sprintf(p, "\n AEC6260 Chipset.\n"); + break; + default: + p += sprintf(p, "\n AEC62?? Chipset.\n"); + break; + } + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + (void) pci_read_config_byte(bmide_dev, 0x4a, &art); + p += sprintf(p, " %sabled %sabled\n", + (art&0x02)?" en":"dis",(art&0x04)?" en":"dis"); + 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 "); + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_ARTOP_ATP850UF: + (void) pci_read_config_byte(bmide_dev, 0x54, &art); + p += sprintf(p, "DMA Mode: %s(%s) %s(%s) %s(%s) %s(%s)\n", + (c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO", + (art&0x02)?"2":(art&0x01)?"1":"0", + (c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO", + (art&0x08)?"2":(art&0x04)?"1":"0", + (c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO", + (art&0x20)?"2":(art&0x10)?"1":"0", + (c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO", + (art&0x80)?"2":(art&0x40)?"1":"0"); + (void) pci_read_config_byte(bmide_dev, 0x40, &art); + p += sprintf(p, "Active: 0x%02x", art); + (void) pci_read_config_byte(bmide_dev, 0x42, &art); + p += sprintf(p, " 0x%02x", art); + (void) pci_read_config_byte(bmide_dev, 0x44, &art); + p += sprintf(p, " 0x%02x", art); + (void) pci_read_config_byte(bmide_dev, 0x46, &art); + p += sprintf(p, " 0x%02x\n", art); + (void) pci_read_config_byte(bmide_dev, 0x41, &art); + p += sprintf(p, "Recovery: 0x%02x", art); + (void) pci_read_config_byte(bmide_dev, 0x43, &art); + p += sprintf(p, " 0x%02x", art); + (void) pci_read_config_byte(bmide_dev, 0x45, &art); + p += sprintf(p, " 0x%02x", art); + (void) pci_read_config_byte(bmide_dev, 0x47, &art); + p += sprintf(p, " 0x%02x\n", art); + break; + case PCI_DEVICE_ID_ARTOP_ATP860: + case PCI_DEVICE_ID_ARTOP_ATP860R: + (void) pci_read_config_byte(bmide_dev, 0x44, &art); + p += sprintf(p, "DMA Mode: %s(%s) %s(%s)", + (c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO", + ((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?", + (c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO", + ((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?"); + (void) pci_read_config_byte(bmide_dev, 0x45, &art); + p += sprintf(p, " %s(%s) %s(%s)\n", + (c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO", + ((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?", + (c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO", + ((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?"); + (void) pci_read_config_byte(bmide_dev, 0x40, &art); + p += sprintf(p, "Active: 0x%02x", HIGH_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x41, &art); + p += sprintf(p, " 0x%02x", HIGH_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x42, &art); + p += sprintf(p, " 0x%02x", HIGH_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x43, &art); + p += sprintf(p, " 0x%02x\n", HIGH_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x40, &art); + p += sprintf(p, "Recovery: 0x%02x", LOW_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x41, &art); + p += sprintf(p, " 0x%02x", LOW_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x42, &art); + p += sprintf(p, " 0x%02x", LOW_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x43, &art); + p += sprintf(p, " 0x%02x\n", LOW_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x49, &uart); + p += sprintf(p, "reg49h = 0x%02x ", uart); + (void) pci_read_config_byte(bmide_dev, 0x4a, &uart); + p += sprintf(p, "reg4ah = 0x%02x\n", uart); + break; + default: + break; + } + + return p-buffer;/* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte aec62xx_proc = 0; + +#ifdef CONFIG_AEC62XX_TUNING + +struct chipset_bus_clock_list_entry { + byte xfer_speed; + + byte chipset_settings_34; + byte ultra_settings_34; + + byte chipset_settings_33; + byte ultra_settings_33; +}; + +struct chipset_bus_clock_list_entry aec62xx_base [] = { + { XFER_UDMA_4, 0x41, 0x04, 0x31, 0x05 }, + { XFER_UDMA_3, 0x41, 0x03, 0x31, 0x04 }, + { XFER_UDMA_2, 0x41, 0x02, 0x31, 0x03 }, + { XFER_UDMA_1, 0x41, 0x01, 0x31, 0x02 }, + { XFER_UDMA_0, 0x41, 0x01, 0x31, 0x01 }, + + { XFER_MW_DMA_2, 0x41, 0x00, 0x31, 0x00 }, + { XFER_MW_DMA_1, 0x42, 0x00, 0x31, 0x00 }, + { XFER_MW_DMA_0, 0x7a, 0x00, 0x0a, 0x00 }, + + { XFER_PIO_4, 0x41, 0x00, 0x31, 0x00 }, + { XFER_PIO_3, 0x43, 0x00, 0x33, 0x00 }, + { XFER_PIO_2, 0x78, 0x00, 0x08, 0x00 }, + { XFER_PIO_1, 0x7a, 0x00, 0x0a, 0x00 }, + { XFER_PIO_0, 0x70, 0x00, 0x00, 0x00 }, + { 0, 0x00, 0x00, 0x00, 0x00 } +}; + +extern char *ide_xfer_verbose (byte xfer_rate); + +/* + * TO DO: active tuning and correction of cards without a bios. + */ + +static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) +{ + for ( ; chipset_table->xfer_speed ; chipset_table++) + if (chipset_table->xfer_speed == speed) { + return ((byte) ((1) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34)); + } + return 0x00; +} + +static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table) +{ + for ( ; chipset_table->xfer_speed ; chipset_table++) + if (chipset_table->xfer_speed == speed) { + return ((byte) ((1) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34)); + } + return 0x00; +} + +static int aec6210_tune_chipset (ide_drive_t *drive, byte speed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + byte unit = (drive->select.b.unit & 0x01); + int drive_number = ((hwif->channel ? 2 : 0) + unit); + int err = 0; + unsigned short d_conf = 0x0000; + byte ultra = 0x00; + byte ultra_conf = 0x00; + byte tmp0 = 0x00; + byte tmp1 = 0x00; + byte tmp2 = 0x00; + unsigned long flags; + + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ + + pci_read_config_word(dev, 0x40|(2*drive_number), &d_conf); + tmp0 = pci_bus_clock_list(speed, aec62xx_base); + SPLIT_BYTE(tmp0,tmp1,tmp2); + MAKE_WORD(d_conf,tmp1,tmp2); + pci_write_config_word(dev, 0x40|(2*drive_number), d_conf); + + tmp1 = 0x00; + tmp2 = 0x00; + pci_read_config_byte(dev, 0x54, &ultra); + tmp1 = ((0x00 << (2*drive_number)) | (ultra & ~(3 << (2*drive_number)))); + ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base); + tmp2 = ((ultra_conf << (2*drive_number)) | (tmp1 & ~(3 << (2*drive_number)))); + pci_write_config_byte(dev, 0x54, tmp2); + + __restore_flags(flags); /* local CPU only */ + + err = ide_config_drive_speed(drive, speed); + return(err); +} + +static int aec6260_tune_chipset (ide_drive_t *drive, byte speed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + byte unit = (drive->select.b.unit & 0x01); + int drive_number = ((hwif->channel ? 2 : 0) + unit); + byte ultra_pci = hwif->channel ? 0x45 : 0x44; + int err = 0; + byte drive_conf = 0x00; + byte ultra_conf = 0x00; + byte ultra = 0x00; + byte tmp1 = 0x00; + byte tmp2 = 0x00; + + unsigned long flags; + + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ + + pci_read_config_byte(dev, 0x40|drive_number, &drive_conf); + drive_conf = pci_bus_clock_list(speed, aec62xx_base); + pci_write_config_byte(dev, 0x40|drive_number, drive_conf); + + pci_read_config_byte(dev, ultra_pci, &ultra); + tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit)))); + ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base); + tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit)))); + pci_write_config_byte(dev, ultra_pci, tmp2); + __restore_flags(flags); /* local CPU only */ + + err = ide_config_drive_speed(drive, speed); + return(err); +} + +#ifdef CONFIG_BLK_DEV_IDEDMA +static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + byte unit = (drive->select.b.unit & 0x01); + unsigned long dma_base = hwif->dma_base; + byte speed = -1; + + if (drive->media != ide_disk) + return ((int) ide_dma_off_quietly); + + if (((id->dma_ultra & 0x0010) || + (id->dma_ultra & 0x0008) || + (id->dma_ultra & 0x0004)) && (ultra)) { + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (ultra)) { + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (ultra)) { + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); + (void) aec6210_tune_chipset(drive, speed); + + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + byte unit = (drive->select.b.unit & 0x01); + unsigned long dma_base = hwif->dma_base; + byte speed = -1; + byte ultra66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; + + if (drive->media != ide_disk) + return ((int) ide_dma_off_quietly); + + if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) { + speed = XFER_UDMA_4; + } else if ((id->dma_ultra & 0x0008) && (ultra) && (ultra66)) { + speed = XFER_UDMA_3; + } else if ((id->dma_ultra & 0x0004) && (ultra)) { + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (ultra)) { + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (ultra)) { + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); + (void) aec6260_tune_chipset(drive, speed); + + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) +{ + switch(HWIF(drive)->pci_dev->device) { + case PCI_DEVICE_ID_ARTOP_ATP850UF: + return config_aec6210_chipset_for_dma(drive, ultra); + case PCI_DEVICE_ID_ARTOP_ATP860: + case PCI_DEVICE_ID_ARTOP_ATP860R: + return config_aec6260_chipset_for_dma(drive, ultra); + default: + return ((int) ide_dma_off_quietly); + } +} + +#endif /* CONFIG_BLK_DEV_IDEDMA */ + +static void aec62xx_tune_drive (ide_drive_t *drive, byte pio) +{ + byte speed; + byte new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + + switch(pio) { + case 5: speed = new_pio; break; + case 4: speed = XFER_PIO_4; break; + case 3: speed = XFER_PIO_3; break; + case 2: speed = XFER_PIO_2; break; + case 1: speed = XFER_PIO_1; break; + default: speed = XFER_PIO_0; break; + } + + switch(HWIF(drive)->pci_dev->device) { + case PCI_DEVICE_ID_ARTOP_ATP850UF: + (void) aec6210_tune_chipset(drive, speed); + case PCI_DEVICE_ID_ARTOP_ATP860: + case PCI_DEVICE_ID_ARTOP_ATP860R: + (void) aec6260_tune_chipset(drive, speed); + default: + break; + } +} + +#ifdef CONFIG_BLK_DEV_IDEDMA +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_on; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; + } + dma_func = ide_dma_off_quietly; + if (id->field_valid & 4) { + if (id->dma_ultra & 0x001F) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive, 1); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive, 0); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive, 0); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + aec62xx_tune_drive(drive, 5); + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + +/* + * aec62xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + */ +int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return config_drive_xfer_rate(drive); + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} +#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* CONFIG_AEC62XX_TUNING */ + +unsigned int __init pci_init_aec62xx (struct pci_dev *dev, const char *name) +{ + if (dev->resource[PCI_ROM_RESOURCE].start) { + pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); + } + +#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS) + if (!aec62xx_proc) { + aec62xx_proc = 1; + bmide_dev = dev; + aec62xx_display_info = &aec62xx_get_info; + } +#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */ + + return dev->irq; +} + +unsigned int __init ata66_aec62xx (ide_hwif_t *hwif) +{ + byte mask = hwif->channel ? 0x02 : 0x01; + byte ata66 = 0; + + pci_read_config_byte(hwif->pci_dev, 0x49, &ata66); +#if 1 + printk("AEC6260: reg49h=0x%02x ATA-%s Cable Port%d\n", ata66, (ata66 & mask) ? "33" : "66", hwif->channel); +#endif + return ((ata66 & mask) ? 0 : 1); +} + +void __init ide_init_aec62xx (ide_hwif_t *hwif) +{ +#ifdef CONFIG_AEC62XX_TUNING + hwif->tuneproc = &aec62xx_tune_drive; + +#ifdef CONFIG_BLK_DEV_IDEDMA + if (hwif->dma_base) + hwif->dmaproc = &aec62xx_dmaproc; +#else /* !CONFIG_BLK_DEV_IDEDMA */ + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* CONFIG_AEC62XX_TUNING */ +} + +void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase) +{ +#ifdef CONFIG_AEC62XX_TUNING + unsigned long flags; + byte reg54h = 0; + + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ + + pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); + pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F)); + + __restore_flags(flags); /* local CPU only */ +#endif /* CONFIG_AEC62XX_TUNING */ + ide_setup_dma(hwif, dmabase, 8); +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ali14xx.c linux/drivers/ide/ali14xx.c --- v2.3.99-pre5/linux/drivers/ide/ali14xx.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ali14xx.c Thu Apr 13 22:54:26 2000 @@ -48,6 +48,7 @@ #include #include #include +#include #include @@ -118,7 +119,7 @@ byte param1, param2, param3, param4; unsigned long flags; ide_pio_data_t d; - int bus_speed = ide_system_bus_speed(); + int bus_speed = system_bus_clock(); pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/alim15x3.c linux/drivers/ide/alim15x3.c --- v2.3.99-pre5/linux/drivers/ide/alim15x3.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/alim15x3.c Thu Apr 13 22:54:26 2000 @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -249,7 +250,7 @@ int s_time, a_time, c_time; byte s_clc, a_clc, r_clc; unsigned long flags; - int bus_speed = ide_system_bus_speed(); + int bus_speed = system_bus_clock(); int port = hwif->index ? 0x5c : 0x58; int portFIFO = hwif->channel ? 0x55 : 0x54; byte cd_dma_fifo = 0; @@ -409,14 +410,14 @@ static byte ali15x3_can_ultra (ide_drive_t *drive) { -#ifdef CONFIG_WDC_ALI15X3 +#ifndef CONFIG_WDC_ALI15X3 struct hd_driveid *id = drive->id; #endif /* CONFIG_WDC_ALI15X3 */ if (m5229_revision <= 0x20) { return 0; } else if ((m5229_revision < 0xC2) && -#ifdef CONFIG_WDC_ALI15X3 +#ifndef CONFIG_WDC_ALI15X3 ((chip_is_1543c_e && strstr(id->model, "WDC ")) || (drive->media!=ide_disk))) { #else /* CONFIG_WDC_ALI15X3 */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/amd7409.c linux/drivers/ide/amd7409.c --- v2.3.99-pre5/linux/drivers/ide/amd7409.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/amd7409.c Thu Apr 13 22:54:26 2000 @@ -17,6 +17,7 @@ #include #include +#include #include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/buddha.c linux/drivers/ide/buddha.c --- v2.3.99-pre5/linux/drivers/ide/buddha.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/buddha.c Thu Apr 13 22:54:26 2000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/cmd640.c linux/drivers/ide/cmd640.c --- v2.3.99-pre5/linux/drivers/ide/cmd640.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/cmd640.c Thu Apr 13 22:54:26 2000 @@ -111,6 +111,7 @@ #include #include #include +#include #include @@ -595,7 +596,7 @@ { int setup_time, active_time, recovery_time, clock_time; byte setup_count, active_count, recovery_count, recovery_count2, cycle_count; - int bus_speed = ide_system_bus_speed(); + int bus_speed = system_bus_clock(); if (pio_mode > 5) pio_mode = 5; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/cmd64x.c linux/drivers/ide/cmd64x.c --- v2.3.99-pre5/linux/drivers/ide/cmd64x.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/cmd64x.c Thu Apr 13 22:54:26 2000 @@ -19,8 +19,10 @@ #include #include #include +#include #include + #include "ide_modes.h" #ifndef SPLIT_BYTE @@ -271,7 +273,7 @@ int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time; byte recovery_count2, cycle_count; int setup_count, active_count, recovery_count; - int bus_speed = ide_system_bus_speed(); + int bus_speed = system_bus_clock(); /*byte b;*/ ide_pio_data_t d; @@ -645,6 +647,9 @@ #endif (void) pci_write_config_byte(dev, DRWTIM23, 0x3f); (void) pci_write_config_byte(dev, DRWTIM3, 0x3f); +#ifdef CONFIG_PPC + (void) pci_write_config_byte(dev, UDIDETCR0, 0xf0); +#endif /* CONFIG_PPC */ #if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) if (!cmd64x_proc) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/cy82c693.c linux/drivers/ide/cy82c693.c --- v2.3.99-pre5/linux/drivers/ide/cy82c693.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/cy82c693.c Thu Apr 13 22:54:26 2000 @@ -49,6 +49,7 @@ #include #include #include +#include #include @@ -140,9 +141,8 @@ static void compute_clocks (byte pio, pio_clocks_t *p_pclk) { int clk1, clk2; - int bus_speed; + int bus_speed = system_bus_clock(); /* get speed of PCI bus */ - bus_speed = ide_system_bus_speed(); /* get speed of PCI bus */ /* we don't check against CY82C693's min and max speed, * so you can play with the idebus=xx parameter */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/dtc2278.c linux/drivers/ide/dtc2278.c --- v2.3.99-pre5/linux/drivers/ide/dtc2278.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/dtc2278.c Thu Apr 13 22:54:26 2000 @@ -15,6 +15,7 @@ #include #include #include +#include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/falconide.c linux/drivers/ide/falconide.c --- v2.3.99-pre5/linux/drivers/ide/falconide.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/falconide.c Thu Apr 13 22:54:26 2000 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/gayle.c linux/drivers/ide/gayle.c --- v2.3.99-pre5/linux/drivers/ide/gayle.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/gayle.c Thu Apr 13 22:54:26 2000 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ht6560b.c linux/drivers/ide/ht6560b.c --- v2.3.99-pre5/linux/drivers/ide/ht6560b.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ht6560b.c Thu Apr 13 22:54:26 2000 @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -203,9 +204,10 @@ static byte ht_pio2timings(ide_drive_t *drive, byte pio) { - int bus_speed, active_time, recovery_time; + int active_time, recovery_time; int active_cycles, recovery_cycles; ide_pio_data_t d; + int bus_speed = system_bus_clock(); if (pio) { pio = ide_get_best_pio_mode(drive, pio, 5, &d); @@ -215,7 +217,6 @@ * actual cycle time for recovery and activity * according system bus speed. */ - bus_speed = ide_system_bus_speed(); active_time = ide_pio_timings[pio].active_time; recovery_time = d.cycle_time - active_time diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/icside.c linux/drivers/ide/icside.c --- v2.3.99-pre5/linux/drivers/ide/icside.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/icside.c Thu Apr 13 22:54:26 2000 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c --- v2.3.99-pre5/linux/drivers/ide/ide-cd.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ide-cd.c Tue Apr 25 17:46:33 2000 @@ -3,7 +3,7 @@ * * Copyright (C) 1994, 1995, 1996 scott snyder * Copyright (C) 1996-1998 Erik Andersen - * Copyright (C) 1998, 1999 Jens Axboe + * Copyright (C) 1998-2000 Jens Axboe * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. @@ -16,8 +16,8 @@ * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI * (SFF-8020i rev 2.6) standards. These documents can be obtained by * anonymous ftp from: - * ftp://fission.dt.wdc.com/pub/standards/SFF/specs/INF-8020.PDF - * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r01.pdf + * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps + * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf * * Drives that deviate from these standards will be accomodated as much * as possible via compile time or command-line options. Since I only have @@ -272,10 +272,19 @@ * - Fixed a problem with WPI CDS-32X drive - it * failed the capabilities * + * 4.57 Apr 7, 2000 - Fixed sense reporting. + * - Fixed possible oops in ide_cdrom_get_last_session() + * - Fix locking mania and make ide_cdrom_reset relock + * - Stop spewing errors to log when magicdev polls with + * TEST_UNIT_READY on some drives. + * - Various fixes from Tobias Ringstrom: + * tray if it was locked prior to the reset. + * - cdrom_read_capacity returns one frame too little. + * - Fix real capacity reporting. * *************************************************************************/ -#define IDECD_VERSION "4.56" +#define IDECD_VERSION "4.57" #include #include @@ -314,11 +323,12 @@ static -void cdrom_analyze_sense_data (ide_drive_t *drive, struct request_sense *reqbuf, - struct packet_command *failed_command) +void cdrom_analyze_sense_data(ide_drive_t *drive, + struct packet_command *failed_command, + struct request_sense *sense) { - if (reqbuf->sense_key == NOT_READY || - reqbuf->sense_key == UNIT_ATTENTION) { + if (sense->sense_key == NOT_READY || + sense->sense_key == UNIT_ATTENTION) { /* Make good and sure we've seen this potential media change. Some drives (i.e. Creative) fail to present the correct sense key in the error register. */ @@ -330,13 +340,14 @@ uses this command to poll the drive, and we don't want to fill the syslog with useless errors. */ if (failed_command && - failed_command->c[0] == GPCMD_READ_SUBCHANNEL) + (failed_command->c[0] == GPCMD_READ_SUBCHANNEL || + failed_command->c[0] == GPCMD_TEST_UNIT_READY)) return; } - if (reqbuf->error_code == 0x70 && reqbuf->sense_key == 0x02 - && ((reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) || - (reqbuf->asc == 0x04 && reqbuf->ascq == 0x01))) + if (sense->error_code == 0x70 && sense->sense_key == 0x02 + && ((sense->asc == 0x3a && sense->ascq == 0x00) || + (sense->asc == 0x04 && sense->ascq == 0x01))) { /* * Suppress the following errors: @@ -353,30 +364,32 @@ char buf[80]; printk ("ATAPI device %s:\n", drive->name); - if (reqbuf->error_code==0x70) + if (sense->error_code==0x70) printk(" Error: "); - else if (reqbuf->error_code==0x71) + else if (sense->error_code==0x71) printk(" Deferred Error: "); + else if (sense->error_code == 0x7f) + printk(" Vendor-specific Error: "); else printk(" Unknown Error Type: "); - if ( reqbuf->sense_key < ARY_LEN (sense_key_texts)) - s = sense_key_texts[reqbuf->sense_key]; + if (sense->sense_key < ARY_LEN(sense_key_texts)) + s = sense_key_texts[sense->sense_key]; else s = "bad sense key!"; - printk ("%s -- (Sense key=0x%02x)\n", s, reqbuf->sense_key); + printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key); - if (reqbuf->asc == 0x40) { - sprintf (buf, "Diagnostic failure on component 0x%02x", - reqbuf->ascq); + if (sense->asc == 0x40) { + sprintf(buf, "Diagnostic failure on component 0x%02x", + sense->ascq); s = buf; } else { - int lo=0, mid, hi=ARY_LEN (sense_data_texts); - unsigned long key = (reqbuf->sense_key << 16); - key |= (reqbuf->asc << 8); - if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) ) - key |= reqbuf->ascq; + int lo = 0, mid, hi = ARY_LEN(sense_data_texts); + unsigned long key = (sense->sense_key << 16); + key |= (sense->asc << 8); + if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd)) + key |= sense->ascq; s = NULL; while (hi > lo) { @@ -394,14 +407,14 @@ } if (s == NULL) { - if (reqbuf->asc > 0x80) + if (sense->asc > 0x80) s = "(vendor-specific error)"; else s = "(reserved error code)"; } - printk (" %s -- (asc=0x%02x, ascq=0x%02x)\n", - s, reqbuf->asc, reqbuf->ascq); + printk(" %s -- (asc=0x%02x, ascq=0x%02x)\n", + s, sense->asc, sense->ascq); if (failed_command != NULL) { @@ -431,21 +444,21 @@ * In the case of NOT_READY, if SKSV is set the drive can * give us nice ETA readings. */ - if (reqbuf->sense_key == NOT_READY && (reqbuf->sks[0] & 0x80)) { - int progress = (reqbuf->sks[1] << 8 | reqbuf->sks[2]) * 100; + if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) { + int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100; printk(" Command is %02d%% complete\n", progress / 0xffff); } - if (reqbuf->sense_key == ILLEGAL_REQUEST && - (reqbuf->sks[0] & 0x80) != 0) { - printk (" Error in %s byte %d", - (reqbuf->sks[0] & 0x40) != 0 ? + if (sense->sense_key == ILLEGAL_REQUEST && + (sense->sks[0] & 0x80) != 0) { + printk(" Error in %s byte %d", + (sense->sks[0] & 0x40) != 0 ? "command packet" : "command data", - (reqbuf->sks[1] << 8) + reqbuf->sks[2]); + (sense->sks[1] << 8) + sense->sks[2]); - if ((reqbuf->sks[0] & 0x40) != 0) - printk (" bit %d", reqbuf->sks[0] & 0x07); + if ((sense->sks[0] & 0x40) != 0) + printk (" bit %d", sense->sks[0] & 0x07); printk ("\n"); } @@ -456,45 +469,43 @@ /* Suppress printing unit attention and `in progress of becoming ready' errors when we're not being verbose. */ - if (reqbuf->sense_key == UNIT_ATTENTION || - (reqbuf->sense_key == NOT_READY && (reqbuf->asc == 4 || - reqbuf->asc == 0x3a))) + if (sense->sense_key == UNIT_ATTENTION || + (sense->sense_key == NOT_READY && (sense->asc == 4 || + sense->asc == 0x3a))) return; - printk ("%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", + printk("%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", drive->name, - reqbuf->error_code, reqbuf->sense_key, - reqbuf->asc, reqbuf->ascq); + sense->error_code, sense->sense_key, + sense->asc, sense->ascq); #endif /* not VERBOSE_IDE_CD_ERRORS */ } -static void cdrom_queue_request_sense (ide_drive_t *drive, - struct semaphore *sem, - struct packet_command *failed_command) +static void cdrom_queue_request_sense(ide_drive_t *drive, + struct semaphore *sem, + struct request_sense *sense, + struct packet_command *failed_command) { struct cdrom_info *info = drive->driver_data; struct request *rq; - struct packet_command *pc; + struct packet_command *pc = &info->request_sense_pc; - /* Make up a new request to retrieve sense information. */ - pc = &info->request_sense_pc; - memset(pc, 0, sizeof (*pc)); + if (sense == NULL) + sense = &info->sense_data; + memset(pc, 0, sizeof(struct packet_command)); pc->c[0] = GPCMD_REQUEST_SENSE; - - /* just get the first 18 bytes of the sense info, there might not - * be more available */ pc->c[4] = pc->buflen = 18; - pc->buffer = (char *)&info->sense_data; - pc->sense_data = (struct request_sense *)failed_command; + pc->buffer = (char *) sense; + pc->sense = (struct request_sense *) failed_command; /* stuff the sense request in front of our current request */ rq = &info->request_sense_request; - ide_init_drive_cmd (rq); + ide_init_drive_cmd(rq); rq->cmd = REQUEST_SENSE_COMMAND; - rq->buffer = (char *)pc; + rq->buffer = (char *) pc; rq->sem = sem; - (void) ide_do_drive_cmd (drive, rq, ide_preempt); + (void) ide_do_drive_cmd(drive, rq, ide_preempt); } @@ -503,11 +514,10 @@ struct request *rq = HWGROUP(drive)->rq; if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) { - struct packet_command *pc = (struct packet_command *) - rq->buffer; - cdrom_analyze_sense_data (drive, - (struct request_sense *) (pc->buffer - pc->c[4]), - (struct packet_command *) pc->sense_data); + struct packet_command *pc = (struct packet_command *)rq->buffer; + cdrom_analyze_sense_data(drive, + (struct packet_command *) pc->sense, + (struct request_sense *) (pc->buffer - pc->c[4])); } if (rq->cmd == READ && !rq->current_nr_sectors) uptodate = 1; @@ -523,7 +533,7 @@ { struct request *rq = HWGROUP(drive)->rq; int stat, cmd, err, sense_key; - struct packet_command *pc = (struct packet_command *) rq->buffer; + struct packet_command *pc; /* Check for errors. */ stat = GET_STAT(); @@ -547,6 +557,7 @@ from the drive (probably while trying to recover from a former error). Just give up. */ + pc = (struct packet_command *) rq->buffer; pc->stat = 1; cdrom_end_request (1, drive); *startstop = ide_error (drive, "request sense failure", stat); @@ -556,6 +567,7 @@ /* All other functions, except for READ. */ struct semaphore *sem = NULL; + pc = (struct packet_command *) rq->buffer; /* Check for tray open. */ if (sense_key == NOT_READY) { @@ -589,7 +601,8 @@ cdrom_end_request (1, drive); if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, sem, pc); + cdrom_queue_request_sense(drive, sem, pc->sense, + pc); } else { /* Handle errors from READ requests. */ @@ -628,7 +641,7 @@ /* If we got a CHECK_CONDITION status, queue a request sense command. */ if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, NULL, NULL); + cdrom_queue_request_sense(drive, NULL, NULL, NULL); } } @@ -1062,11 +1075,11 @@ pc.c[0] = GPCMD_READ_10; pc.c[7] = (nframes >> 8); pc.c[8] = (nframes & 0xff); - put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); + put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); /* Send the command to the drive and return. */ - return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), - &cdrom_read_intr); + return cdrom_transfer_packet_command(drive, pc.c, sizeof(pc.c), + &cdrom_read_intr); } @@ -1178,7 +1191,8 @@ */ /* Forward declarations. */ -static int cdrom_lockdoor(ide_drive_t *drive, int lockflag); +static int cdrom_lockdoor(ide_drive_t *drive, int lockflag, + struct request_sense *sense); /* Interrupt routine for packet command completion. */ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive) @@ -1186,11 +1200,8 @@ int ireason, len, stat, thislen; struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; - struct cdrom_info *info = drive->driver_data; ide_startstop_t startstop; - pc->sense_data = &info->sense_data; - /* Check for errors. */ if (cdrom_decode_status (&startstop, drive, 0, &stat)) return startstop; @@ -1320,8 +1331,12 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc) { - int retries = 10; + struct request_sense sense; struct request req; + int retries = 10; + + if (pc->sense == NULL) + pc->sense = &sense; /* Start of retry loop. */ do { @@ -1337,7 +1352,7 @@ /* The request failed. Retry if it was due to a unit attention status (usually means media was changed). */ - struct request_sense *reqbuf = pc->sense_data; + struct request_sense *reqbuf = pc->sense; if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change (drive); @@ -1358,24 +1373,7 @@ } while (pc->stat != 0 && retries >= 0); /* Return an error if the command failed. */ - if (pc->stat) - return -EIO; - - /* The command succeeded. If it was anything other than - a request sense, eject, or door lock command, - and we think that the door is presently unlocked, lock it - again. (The door was probably unlocked via an explicit - CDROMEJECT ioctl.) */ - if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && - (pc->c[0] != GPCMD_TEST_UNIT_READY && - pc->c[0] != GPCMD_REQUEST_SENSE && - pc->c[0] != GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL && - pc->c[0] != GPCMD_START_STOP_UNIT && - pc->c[0] != GPCMD_MODE_SENSE_10 && - pc->c[0] != GPCMD_MODE_SELECT_10)) { - (void) cdrom_lockdoor (drive, 1); - } - return 0; + return pc->stat ? -EIO : 0; } /**************************************************************************** @@ -1483,13 +1481,14 @@ return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; } -static int cdrom_check_status (ide_drive_t *drive) +static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense) { struct packet_command pc; struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; memset(&pc, 0, sizeof(pc)); + pc.sense = sense; pc.c[0] = GPCMD_TEST_UNIT_READY; @@ -1506,24 +1505,26 @@ /* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */ static int -cdrom_lockdoor(ide_drive_t *drive, int lockflag) +cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense) { - struct request_sense *sense; + struct request_sense my_sense; struct packet_command pc; int stat; + if (sense == NULL) + sense = &my_sense; + /* If the drive cannot lock the door, just pretend. */ - if (CDROM_CONFIG_FLAGS (drive)->no_doorlock) + if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) { stat = 0; - else { + } else { memset(&pc, 0, sizeof(pc)); + pc.sense = sense; pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; pc.c[4] = (lockflag != 0); stat = cdrom_queue_packet_command (drive, &pc); } - sense = pc.sense_data; - /* If we got an illegal field error, the drive probably cannot lock the door. */ if (stat != 0 && @@ -1548,7 +1549,8 @@ /* Eject the disk if EJECTFLAG is 0. If EJECTFLAG is 1, try to reload the disk. */ -static int cdrom_eject(ide_drive_t *drive, int ejectflag) +static int cdrom_eject(ide_drive_t *drive, int ejectflag, + struct request_sense *sense) { struct packet_command pc; @@ -1560,13 +1562,15 @@ return 0; memset(&pc, 0, sizeof (pc)); + pc.sense = sense; pc.c[0] = GPCMD_START_STOP_UNIT; pc.c[4] = 0x02 + (ejectflag != 0); return cdrom_queue_packet_command (drive, &pc); } -static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity) +static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity, + struct request_sense *sense) { struct { __u32 lba; @@ -1576,7 +1580,8 @@ int stat; struct packet_command pc; - memset(&pc, 0, sizeof (pc)); + memset(&pc, 0, sizeof(pc)); + pc.sense = sense; pc.c[0] = GPCMD_READ_CDVD_CAPACITY; pc.buffer = (char *)&capbuf; @@ -1584,17 +1589,19 @@ stat = cdrom_queue_packet_command(drive, &pc); if (stat == 0) - *capacity = be32_to_cpu(capbuf.lba); + *capacity = 1 + be32_to_cpu(capbuf.lba); return stat; } static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag, - int format, char *buf, int buflen) + int format, char *buf, int buflen, + struct request_sense *sense) { struct packet_command pc; memset(&pc, 0, sizeof(pc)); + pc.sense = sense; pc.buffer = buf; pc.buflen = buflen; @@ -1612,12 +1619,11 @@ /* Try to read the entire TOC for the disk into our internal buffer. */ -static int cdrom_read_toc (ide_drive_t *drive) +static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) { int stat, ntracks, i; struct cdrom_info *info = drive->driver_data; struct atapi_toc *toc = info->toc; - int minor = drive->select.b.unit << PARTN_BITS; struct { struct atapi_toc_header hdr; struct atapi_toc_entry ent; @@ -1637,13 +1643,13 @@ /* Check to see if the existing data is still valid. If it is, just return. */ if (CDROM_STATE_FLAGS (drive)->toc_valid) - (void) cdrom_check_status(drive); + (void) cdrom_check_status(drive, sense); if (CDROM_STATE_FLAGS (drive)->toc_valid) return 0; /* First read just the header, so we know how long the TOC is. */ - stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header)); + stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, + sizeof(struct atapi_toc_header), sense); if (stat) return stat; #if ! STANDARD_ATAPI @@ -1658,10 +1664,11 @@ if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS; /* Now read the whole schmeer. */ - stat = cdrom_read_tocentry (drive, toc->hdr.first_track, 1, 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header) + - (ntracks + 1) * - sizeof (struct atapi_toc_entry)); + stat = cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0, + (char *)&toc->hdr, + sizeof(struct atapi_toc_header) + + (ntracks + 1) * + sizeof(struct atapi_toc_entry), sense); if (stat && toc->hdr.first_track > 1) { /* Cds with CDI tracks only don't have any TOC entries, @@ -1674,11 +1681,12 @@ the readable TOC is empty (CDI tracks are not included) and only holds the Leadout entry. Heiko Eißfeldt */ ntracks = 0; - stat = cdrom_read_tocentry (drive, CDROM_LEADOUT, 1, - 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header) + - (ntracks+1) * - sizeof (struct atapi_toc_entry)); + stat = cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0, + (char *)&toc->hdr, + sizeof(struct atapi_toc_header) + + (ntracks + 1) * + sizeof(struct atapi_toc_entry), + sense); if (stat) { return stat; } @@ -1722,8 +1730,8 @@ /* Read the multisession information. */ if (toc->hdr.first_track != CDROM_LEADOUT) { /* Read the multisession information. */ - stat = cdrom_read_tocentry (drive, 0, 1, 1, - (char *)&ms_tmp, sizeof (ms_tmp)); + stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp, + sizeof(ms_tmp), sense); if (stat) return stat; } else { ms_tmp.ent.addr.msf.minute = 0; @@ -1749,45 +1757,23 @@ (long *)&toc->capacity); if (stat) #endif - stat = cdrom_read_capacity (drive, &toc->capacity); + stat = cdrom_read_capacity(drive, &toc->capacity, sense); if (stat) toc->capacity = 0x1fffff; - /* for general /dev/cdrom like mounting, one big disc */ - drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME; - HWIF(drive)->gd->sizes[minor] = (toc->capacity * SECTORS_PER_FRAME) >> - (BLOCK_SIZE_BITS - 9); - /* Remember that we've read this stuff. */ CDROM_STATE_FLAGS (drive)->toc_valid = 1; - /* should be "if multisession", but it does no harm. */ - if (ntracks == 1) - return 0; - - /* setup each minor to respond to a session */ - minor++; - i = toc->hdr.first_track; - while ((i <= ntracks) && ((minor & CD_PART_MASK) < CD_PART_MAX)) { - drive->part[minor & PARTN_MASK].start_sect = 0; - drive->part[minor & PARTN_MASK].nr_sects = - (toc->ent[i].addr.lba * - SECTORS_PER_FRAME) << (BLOCK_SIZE_BITS - 9); - HWIF(drive)->gd->sizes[minor] = (toc->ent[i].addr.lba * - SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9); - i++; - minor++; - } - return 0; } static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf, - int buflen) + int buflen, struct request_sense *sense) { struct packet_command pc; memset(&pc, 0, sizeof(pc)); + pc.sense = sense; pc.buffer = buf; pc.buflen = buflen; @@ -1802,10 +1788,12 @@ /* ATAPI cdrom drives are free to select the speed you request or any slower rate :-( Requesting too fast a speed will _not_ produce an error. */ -static int cdrom_select_speed (ide_drive_t *drive, int speed) +static int cdrom_select_speed(ide_drive_t *drive, int speed, + struct request_sense *sense) { struct packet_command pc; memset(&pc, 0, sizeof(pc)); + pc.sense = sense; if (speed == 0) speed = 0xffff; /* set to max */ @@ -1825,7 +1813,7 @@ pc.c[5] = speed & 0xff; } - return cdrom_queue_packet_command (drive, &pc); + return cdrom_queue_packet_command(drive, &pc); } @@ -1869,10 +1857,7 @@ pc.buffer = cgc->buffer; pc.buflen = cgc->buflen; cgc->stat = cdrom_queue_packet_command(drive, &pc); - - /* There was an error, assign sense. */ - if (cgc->stat) - cgc->sense = pc.sense_data; + cgc->sense = pc.sense; return cgc->stat; } @@ -1938,7 +1923,7 @@ struct atapi_toc *toc; /* Make sure our saved TOC is valid. */ - stat = cdrom_read_toc(drive); + stat = cdrom_read_toc(drive, NULL); if (stat) return stat; toc = info->toc; @@ -1978,11 +1963,22 @@ int ide_cdrom_reset (struct cdrom_device_info *cdi) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct request_sense sense; struct request req; + int ret; ide_init_drive_cmd (&req); req.cmd = RESET_DRIVE_COMMAND; - return ide_do_drive_cmd (drive, &req, ide_wait); + ret = ide_do_drive_cmd(drive, &req, ide_wait); + + /* + * A reset will unlock the door. If it was previously locked, + * lock it again. + */ + if (CDROM_STATE_FLAGS(drive)->door_locked) + (void) cdrom_lockdoor(drive, 1, &sense); + + return ret; } @@ -1990,120 +1986,33 @@ int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct request_sense sense; if (position) { - int stat = cdrom_lockdoor (drive, 0); + int stat = cdrom_lockdoor(drive, 0, &sense); if (stat) return stat; } - return cdrom_eject(drive, !position); + return cdrom_eject(drive, !position, &sense); } static int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - return cdrom_lockdoor (drive, lock); -} - -#undef __ACER50__ - -#ifdef __ACER50__ -/* - * the buffer struct used by ide_cdrom_get_capabilities() - */ -struct get_capabilities_buf { - char pad[8]; - struct atapi_capabilities_page cap; /* this is 4 bytes short of ATAPI standard */ - char extra_cap[4]; /* Acer 50X needs the regulation size buffer */ -}; - -static -int ide_cdrom_get_capabilities (struct cdrom_device_info *cdi, struct get_capabilities_buf *buf) -{ - int stat, attempts = 3, buflen = sizeof(*buf); - ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_generic_command cgc; - - /* - * Most drives don't care about the buffer size; - * they return as much info as there's room for. - * But some older drives (?) had trouble with the - * standard size, preferring 4 bytes less. - * And the modern Acer 50X rejects anything smaller - * than the standard size. - */ - if (!(drive->id && !strcmp(drive->id->model,"ATAPI CD ROM DRIVE 50X MAX"))) - buflen -= sizeof(buf->extra_cap); /* for all drives except Acer 50X */ - - do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ - stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); - if (stat == 0) { - /* - * The ACER/AOpen 24X cdrom has the speed - * fields byte-swapped from the standard. - */ - if (!(drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4))) { - buf->cap.curspeed = ntohs(buf->cap.curspeed); - buf->cap.maxspeed = ntohs(buf->cap.maxspeed); - } - CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf->cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS(drive)->max_speed = (((unsigned int)buf->cap.maxspeed) + (176/2)) / 176; - return 0; - } - } while (--attempts); - return stat; + return cdrom_lockdoor(drive, lock, NULL); } -#endif /* __ACER50__ */ static int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) { -#ifndef __ACER50__ - int stat, attempts = 3; ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_generic_command cgc; - struct { - char pad[8]; - struct atapi_capabilities_page cap; - } buf; -#else + struct request_sense sense; int stat; - ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_generic_command cgc; - struct get_capabilities_buf buf; -#endif /* __ACER50__ */ - if ((stat = cdrom_select_speed (drive, speed)) < 0) + if ((stat = cdrom_select_speed (drive, speed, &sense)) < 0) return stat; - init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN); - -#ifndef __ACER50__ - /* Now with that done, update the speed fields */ - do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ - if (attempts-- <= 0) - return 0; - stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); - } while (stat); - - /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ - if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) { - CDROM_STATE_FLAGS (drive)->current_speed = - (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS (drive)->max_speed = - (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; - } else { - CDROM_STATE_FLAGS (drive)->current_speed = - (ntohs(buf.cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS (drive)->max_speed = - (ntohs(buf.cap.maxspeed) + (176/2)) / 176; - } -#else - if (ide_cdrom_get_capabilities(cdi,&buf)) - return 0; -#endif /* __ACER50__ */ - cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed; return 0; } @@ -2112,19 +2021,18 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; if (slot_nr == CDSL_CURRENT) { - struct request_sense *sense = &info->sense_data; - int stat = cdrom_check_status(drive); - if (stat == 0 || sense->sense_key == UNIT_ATTENTION) + struct request_sense sense; + int stat = cdrom_check_status(drive, &sense); + if (stat == 0 || sense.sense_key == UNIT_ATTENTION) return CDS_DISC_OK; - if (sense->sense_key == NOT_READY && sense->asc == 0x04 && - sense->ascq == 0x04) + if (sense.sense_key == NOT_READY && sense.asc == 0x04 && + sense.ascq == 0x04) return CDS_DISC_OK; - if (sense->sense_key == NOT_READY) { + if (sense.sense_key == NOT_READY) { /* ATAPI doesn't have anything that can help us decide whether the drive is really emtpy or the tray is just open. irk. */ @@ -2132,9 +2040,8 @@ } return CDS_DRIVE_NOT_READY; - } else { - return -EINVAL; } + return -EINVAL; } static @@ -2144,8 +2051,14 @@ struct atapi_toc *toc; ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct cdrom_info *info = drive->driver_data; + struct request_sense sense; + int ret; toc = info->toc; + if (!CDROM_STATE_FLAGS(drive)->toc_valid || toc == NULL) + if ((ret = cdrom_read_toc(drive, &sense))) + return ret; + ms_info->addr.lba = toc->last_session_lba; ms_info->xa_flag = toc->xa_flag; @@ -2161,7 +2074,7 @@ ide_drive_t *drive = (ide_drive_t*) cdi->handle; /* get MCN */ - if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf)))) + if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL))) return stat; memcpy (mcn_info->medium_catalog_number, mcnbuf+9, @@ -2183,11 +2096,13 @@ int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + int retval; if (slot_nr == CDSL_CURRENT) { - (void) cdrom_check_status(drive); + (void) cdrom_check_status(drive, NULL); + retval = CDROM_STATE_FLAGS (drive)->media_changed; CDROM_STATE_FLAGS (drive)->media_changed = 0; - return CDROM_STATE_FLAGS (drive)->media_changed; + return retval; } else { return -EINVAL; } @@ -2272,40 +2187,31 @@ if (!CDROM_CONFIG_FLAGS (drive)->close_tray) devinfo->mask |= CDC_CLOSE_TRAY; - devinfo->de = devfs_register (drive->de, "cd", 2, DEVFS_FL_DEFAULT, - HWIF(drive)->major, minor, - S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, - ide_fops, NULL); + devinfo->de = devfs_register(drive->de, "cd", 2, DEVFS_FL_DEFAULT, + HWIF(drive)->major, minor, + S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, + ide_fops, NULL); - return register_cdrom (devinfo); + return register_cdrom(devinfo); } +/* + * the buffer struct used by ide_cdrom_get_capabilities() + */ +struct get_capabilities_buf { + char pad[8]; + struct atapi_capabilities_page cap; + char extra_cap[4]; +}; static -int ide_cdrom_probe_capabilities (ide_drive_t *drive) +int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap) { struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; -#ifndef __ACER50__ - int stat, nslots = 1, attempts = 3; struct cdrom_generic_command cgc; - struct { - char pad[8]; - struct atapi_capabilities_page cap; - } buf; -#else - int nslots = 1; - struct cdrom_generic_command cgc; - struct get_capabilities_buf buf; -#endif /* __ACER50__ */ - - if (CDROM_CONFIG_FLAGS (drive)->nec260) { - CDROM_CONFIG_FLAGS (drive)->no_eject = 0; - CDROM_CONFIG_FLAGS (drive)->audio_play = 1; - return nslots; - } + int stat, attempts = 3; - init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN); /* we have to cheat a little here. the packet will eventually * be queued with ide_cdrom_packet(), which extracts the * drive from cdi->handle. Since this device hasn't been @@ -2314,37 +2220,51 @@ */ cdi->handle = (ide_drive_t *) drive; cdi->ops = &ide_cdrom_dops; -#ifndef __ACER50__ - /* we seem to get stat=0x01,err=0x00 the first time (??) */ - do { - if (attempts-- <= 0) - return 0; + init_cdrom_command(&cgc, cap, sizeof(*cap), CGC_DATA_UNKNOWN); + do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); - } while (stat); -#else - if (ide_cdrom_get_capabilities(cdi,&buf)) + if (!stat) + break; + } while (--attempts); + return stat; +} + +static +int ide_cdrom_probe_capabilities (ide_drive_t *drive) +{ + struct cdrom_info *info = drive->driver_data; + struct cdrom_device_info *cdi = &info->devinfo; + struct atapi_capabilities_page cap; + int nslots = 1; + + if (CDROM_CONFIG_FLAGS (drive)->nec260) { + CDROM_CONFIG_FLAGS (drive)->no_eject = 0; + CDROM_CONFIG_FLAGS (drive)->audio_play = 1; + return nslots; + } + + if (ide_cdrom_get_capabilities(drive, &cap)) return 0; -#endif /* __ACER50__ */ - if (buf.cap.lock == 0) + if (cap.lock == 0) CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; - if (buf.cap.eject) + if (cap.eject) CDROM_CONFIG_FLAGS (drive)->no_eject = 0; - if (buf.cap.cd_r_write) + if (cap.cd_r_write) CDROM_CONFIG_FLAGS (drive)->cd_r = 1; - if (buf.cap.cd_rw_write) + if (cap.cd_rw_write) CDROM_CONFIG_FLAGS (drive)->cd_rw = 1; - if (buf.cap.test_write) + if (cap.test_write) CDROM_CONFIG_FLAGS (drive)->test_write = 1; - if (buf.cap.dvd_ram_read || buf.cap.dvd_r_read || buf.cap.dvd_rom) + if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom) CDROM_CONFIG_FLAGS (drive)->dvd = 1; - if (buf.cap.dvd_ram_write) + if (cap.dvd_ram_write) CDROM_CONFIG_FLAGS (drive)->dvd_r = 1; - if (buf.cap.dvd_r_write) + if (cap.dvd_r_write) CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1; - if (buf.cap.audio_play) + if (cap.audio_play) CDROM_CONFIG_FLAGS (drive)->audio_play = 1; - if (buf.cap.mechtype == 0) + if (cap.mechtype == 0) CDROM_CONFIG_FLAGS (drive)->close_tray = 0; #if ! STANDARD_ATAPI @@ -2355,28 +2275,26 @@ else #endif /* not STANDARD_ATAPI */ - if (buf.cap.mechtype == mechtype_individual_changer || - buf.cap.mechtype == mechtype_cartridge_changer) { + if (cap.mechtype == mechtype_individual_changer || + cap.mechtype == mechtype_cartridge_changer) { if ((nslots = cdrom_number_of_slots(cdi)) > 1) { CDROM_CONFIG_FLAGS (drive)->is_changer = 1; CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1; } } -#ifndef __ACER50__ /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) { CDROM_STATE_FLAGS (drive)->current_speed = - (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; + (((unsigned int)cap.curspeed) + (176/2)) / 176; CDROM_CONFIG_FLAGS (drive)->max_speed = - (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; + (((unsigned int)cap.maxspeed) + (176/2)) / 176; } else { CDROM_STATE_FLAGS (drive)->current_speed = - (ntohs(buf.cap.curspeed) + (176/2)) / 176; + (ntohs(cap.curspeed) + (176/2)) / 176; CDROM_CONFIG_FLAGS (drive)->max_speed = - (ntohs(buf.cap.maxspeed) + (176/2)) / 176; + (ntohs(cap.maxspeed) + (176/2)) / 176; } -#endif /* __ACER50__ */ /* don't print speed if the drive reported 0. */ @@ -2400,7 +2318,7 @@ else printk (" drive"); - printk (", %dkB Cache", be16_to_cpu(buf.cap.buffer_size)); + printk (", %dkB Cache", be16_to_cpu(cap.buffer_size)); #ifdef CONFIG_BLK_DEV_IDEDMA if (drive->using_dma) @@ -2601,6 +2519,37 @@ } static +void ide_cdrom_revalidate (ide_drive_t *drive) +{ + struct cdrom_info *info = drive->driver_data; + struct atapi_toc *toc; + int minor = drive->select.b.unit << PARTN_BITS; + struct request_sense sense; + + cdrom_read_toc(drive, &sense); + + if (!CDROM_STATE_FLAGS(drive)->toc_valid) + return; + + toc = info->toc; + + /* for general /dev/cdrom like mounting, one big disc */ + drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME; + HWIF(drive)->gd->sizes[minor] = toc->capacity * BLOCKS_PER_FRAME; + + blk_size[HWIF(drive)->major] = HWIF(drive)->gd->sizes; +} + +static +unsigned long ide_cdrom_capacity (ide_drive_t *drive) +{ + unsigned capacity; + + capacity = cdrom_read_capacity(drive, &capacity, NULL); + return capacity ? 0 : capacity * SECTORS_PER_FRAME; +} + +static int ide_cdrom_cleanup(ide_drive_t *drive) { struct cdrom_info *info = drive->driver_data; @@ -2635,13 +2584,14 @@ ide_cdrom_open, /* open */ ide_cdrom_release, /* release */ ide_cdrom_check_media_change, /* media_change */ + ide_cdrom_revalidate, /* revalidate */ NULL, /* pre_reset */ - NULL, /* capacity */ + ide_cdrom_capacity, /* capacity */ NULL, /* special */ NULL /* proc */ }; -int ide_cdrom_init (void); +int ide_cdrom_init(void); static ide_module_t ide_cdrom_module = { IDE_DRIVER_MODULE, ide_cdrom_init, @@ -2670,7 +2620,7 @@ } #endif /* MODULE */ -int ide_cdrom_init (void) +int ide_cdrom_init(void) { ide_drive_t *drive; struct cdrom_info *info; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h --- v2.3.99-pre5/linux/drivers/ide/ide-cd.h Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ide-cd.h Wed Apr 26 15:30:39 2000 @@ -10,6 +10,15 @@ #include #include +/* + * Apparently older drives have problems with filling out the entire + * mode_sense capability structure. Define this to 1 if your drive isn't + * probed correctly. + */ +#ifndef BROKEN_CAP_PAGE +#define BROKEN_CAP_PAGE 0 +#endif + /* Turn this on to have the driver print out the meanings of the ATAPI error codes. This will use up additional kernel-space memory, though. */ @@ -43,6 +52,8 @@ #define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32) #define SECTORS_BUFFER (SECTOR_BUFFER_SIZE / SECTOR_SIZE) +#define BLOCKS_PER_FRAME (CD_FRAMESIZE / BLOCK_SIZE) + #define MIN(a,b) ((a) < (b) ? (a) : (b)) /* special command codes for strategy routine. */ @@ -103,7 +114,7 @@ char *buffer; int buflen; int stat; - struct request_sense *sense_data; + struct request_sense *sense; unsigned char c[12]; }; @@ -187,6 +198,7 @@ * generic stuff now in the Mt. Fuji spec. */ struct atapi_capabilities_page { + struct mode_page_header header; #if defined(__BIG_ENDIAN_BITFIELD) __u8 parameters_saveable : 1; __u8 reserved1 : 1; @@ -398,9 +410,9 @@ unsigned short buffer_size; /* Current speed (in kB/s). */ unsigned short curspeed; - - /* Truncate the structure here, so we don't have headaches reading - from older drives. */ +#if !BROKEN_CAP_PAGE + char pad[4]; +#endif }; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c --- v2.3.99-pre5/linux/drivers/ide/ide-disk.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/ide/ide-disk.c Thu Apr 13 22:50:32 2000 @@ -512,6 +512,13 @@ return drive->removable; /* if removable, always assume it was changed */ } +static void idedisk_revalidate (ide_drive_t *drive) +{ + grok_partitions(HWIF(drive)->gd, drive->select.b.unit, + 1<capacity, the full capacity of the drive * Called with drive->id != NULL. @@ -726,6 +733,7 @@ idedisk_open, /* open */ idedisk_release, /* release */ idedisk_media_change, /* media_change */ + idedisk_revalidate, /* revalidate */ idedisk_pre_reset, /* pre_reset */ idedisk_capacity, /* capacity */ idedisk_special, /* special */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c --- v2.3.99-pre5/linux/drivers/ide/ide-dma.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ide-dma.c Thu Apr 13 22:54:26 2000 @@ -368,7 +368,13 @@ } } else if ((id->field_valid & 4) && (id->dma_ultra & (id->dma_ultra >> 8) & 7)) { - printk(", UDMA(33)"); /* UDMA BIOS-enabled! */ + if ((id->dma_ultra >> 10) & 1) { + printk(", UDMA(33)"); /* UDMA BIOS-enabled! */ + } else if ((id->dma_ultra >> 9) & 1) { + printk(", UDMA(25)"); /* UDMA BIOS-enabled! */ + } else { + printk(", UDMA(16)"); /* UDMA BIOS-enabled! */ + } } else if (id->field_valid & 4) { printk(", (U)DMA"); /* Can be BIOS-enabled! */ } else { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c --- v2.3.99-pre5/linux/drivers/ide/ide-floppy.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ide-floppy.c Thu Apr 13 22:50:32 2000 @@ -1376,6 +1376,16 @@ } /* + * Revalidate the new media. Should set blk_size[] + */ +static void idefloppy_revalidate (ide_drive_t *drive) +{ + grok_partitions(HWIF(drive)->gd, drive->select.b.unit, + 1<irq; default: break; @@ -592,6 +601,7 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) autodma = 0; if (autodma) @@ -599,6 +609,8 @@ if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) || diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-pnp.c linux/drivers/ide/ide-pnp.c --- v2.3.99-pre5/linux/drivers/ide/ide-pnp.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ide-pnp.c Thu Apr 13 22:54:26 2000 @@ -17,6 +17,8 @@ */ #include +#include + #include #ifndef PREPARE_FUNC diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c --- v2.3.99-pre5/linux/drivers/ide/ide-probe.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ide-probe.c Thu Apr 13 22:54:26 2000 @@ -204,6 +204,10 @@ hd_status = IDE_STATUS_REG; } + /* set features register for atapi identify command to be sure of reply */ + if ((cmd == WIN_PIDENTIFY)) + OUT_BYTE(0,IDE_FEATURE_REG); /* disable dma & overlap */ + #if CONFIG_BLK_DEV_PDC4030 if (HWIF(drive)->chipset == ide_pdc4030) { /* DC4030 hosted drives need their own identify... */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-proc.c linux/drivers/ide/ide-proc.c --- v2.3.99-pre5/linux/drivers/ide/ide-proc.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ide-proc.c Thu Apr 13 22:54:26 2000 @@ -73,10 +73,10 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif -#ifdef CONFIG_BLK_DEV_AEC6210 -extern byte aec6210_proc; -int (*aec6210_display_info)(char *, char **, off_t, int) = NULL; -#endif /* CONFIG_BLK_DEV_AEC6210 */ +#ifdef CONFIG_BLK_DEV_AEC62XX +extern byte aec62xx_proc; +int (*aec62xx_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_AEC62XX */ #ifdef CONFIG_BLK_DEV_ALI15X3 extern byte ali_proc; int (*ali_display_info)(char *, char **, off_t, int) = NULL; @@ -801,10 +801,10 @@ create_proc_read_entry("drivers", 0, proc_ide_root, proc_ide_read_drivers, NULL); -#ifdef CONFIG_BLK_DEV_AEC6210 - if ((aec6210_display_info) && (aec6210_proc)) - create_proc_info_entry("aec6210", 0, proc_ide_root, aec6210_display_info); -#endif /* CONFIG_BLK_DEV_AEC6210 */ +#ifdef CONFIG_BLK_DEV_AEC62XX + if ((aec62xx_display_info) && (aec62xx_proc)) + create_proc_info_entry("aec62xx", 0, proc_ide_root, aec62xx_display_info); +#endif /* CONFIG_BLK_DEV_AEC62XX */ #ifdef CONFIG_BLK_DEV_ALI15X3 if ((ali_display_info) && (ali_proc)) create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info); @@ -853,10 +853,10 @@ * Mmmm.. does this free up all resources, * or do we need to do a more proper cleanup here ?? */ -#ifdef CONFIG_BLK_DEV_AEC6210 - if ((aec6210_display_info) && (aec6210_proc)) - remove_proc_entry("ide/aec6210",0); -#endif /* CONFIG_BLK_DEV_AEC6210 */ +#ifdef CONFIG_BLK_DEV_AEC62XX + if ((aec62xx_display_info) && (aec62xx_proc)) + remove_proc_entry("ide/aec62xx",0); +#endif /* CONFIG_BLK_DEV_AEC62XX */ #ifdef CONFIG_BLK_DEV_ALI15X3 if ((ali_display_info) && (ali_proc)) remove_proc_entry("ide/ali",0); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c --- v2.3.99-pre5/linux/drivers/ide/ide-tape.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ide-tape.c Thu Apr 13 22:50:32 2000 @@ -5900,6 +5900,7 @@ idetape_blkdev_open, /* open */ idetape_blkdev_release, /* release */ NULL, /* media_change */ + NULL, /* revalidate */ idetape_pre_reset, /* pre_reset */ NULL, /* capacity */ NULL, /* special */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.3.99-pre5/linux/drivers/ide/ide.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/ide/ide.c Fri Apr 21 16:14:58 2000 @@ -343,7 +343,7 @@ system_bus_speed = idebus_parameter; /* user supplied value */ #ifdef CONFIG_PCI else if (pci_present()) - system_bus_speed = 40; /* safe default value for PCI */ + system_bus_speed = 33; /* safe default value for PCI */ #endif /* CONFIG_PCI */ else system_bus_speed = 50; /* safe default value for VESA and PCI */ @@ -1091,11 +1091,9 @@ #endif block = rq->sector; blockend = block + rq->nr_sectors; -#if 0 + if ((rq->cmd == READ || rq->cmd == WRITE) && - (drive->media == ide_disk || drive->media == ide_floppy)) -#endif - { + (drive->media == ide_disk || drive->media == ide_floppy)) { if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); @@ -1777,10 +1775,8 @@ drive->part[p].nr_sects = 0; }; - grok_partitions(HWIF(drive)->gd, drive->select.b.unit, - (drive->media != ide_disk && - drive->media != ide_floppy) ? 1 : 1<revalidate) + DRIVER(drive)->revalidate(drive); drive->busy = 0; wake_up(&drive->wqueue); @@ -2095,7 +2091,9 @@ hwif->config_data = old_hwif.config_data; hwif->select_data = old_hwif.select_data; hwif->proc = old_hwif.proc; +#ifndef CONFIG_BLK_DEV_IDECS hwif->irq = old_hwif.irq; +#endif /* CONFIG_BLK_DEV_IDECS */ hwif->major = old_hwif.major; hwif->chipset = old_hwif.chipset; hwif->autodma = old_hwif.autodma; @@ -2447,8 +2445,18 @@ */ void ide_delay_50ms (void) { +#if 0 unsigned long timeout = jiffies + ((HZ + 19)/20) + 1; while (0 < (signed long)(timeout - jiffies)); +#else + __set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/20); +#endif +} + +int system_bus_clock (void) +{ + return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed )); } static int ide_ioctl (struct inode *inode, struct file *file, @@ -3350,7 +3358,7 @@ static unsigned long default_capacity (ide_drive_t *drive) { - return 0x7fffffff; /* cdrom or tape */ + return 0x7fffffff; } static ide_startstop_t default_special (ide_drive_t *drive) @@ -3578,6 +3586,8 @@ EXPORT_SYMBOL(get_info_ptr); EXPORT_SYMBOL(current_capacity); +EXPORT_SYMBOL(system_bus_clock); + /* * This is gets invoked once during initialization, to set *everything* up */ @@ -3589,7 +3599,7 @@ if (!banner_printed) { printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); ide_devfs_handle = devfs_mk_dir (NULL, "ide", 3, NULL); - (void) ide_system_bus_speed(); + system_bus_speed = ide_system_bus_speed(); banner_printed = 1; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ide_modes.h linux/drivers/ide/ide_modes.h --- v2.3.99-pre5/linux/drivers/ide/ide_modes.h Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ide_modes.h Wed Apr 26 15:30:39 2000 @@ -124,8 +124,11 @@ { "QUANTUM LPS540A", 3 }, { "QUANTUM LIGHTNING 540A", 3 }, { "QUANTUM LIGHTNING 730A", 3 }, - { "QUANTUM FIREBALL", 3 }, /* For models 540/640/1080/1280 */ - /* 1080A works fine in mode4 with triton */ + + { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */ + { "QUANTUM FIREBALL_640", 3 }, + { "QUANTUM FIREBALL_1080", 3 }, + { "QUANTUM FIREBALL_1280", 3 }, { NULL, 0 } }; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/macide.c linux/drivers/ide/macide.c --- v2.3.99-pre5/linux/drivers/ide/macide.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/macide.c Thu Apr 13 22:54:26 2000 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/ns87415.c linux/drivers/ide/ns87415.c --- v2.3.99-pre5/linux/drivers/ide/ns87415.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ns87415.c Thu Apr 13 22:54:26 2000 @@ -20,6 +20,7 @@ #include #include #include +#include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/opti621.c linux/drivers/ide/opti621.c --- v2.3.99-pre5/linux/drivers/ide/opti621.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/opti621.c Thu Apr 13 22:54:26 2000 @@ -215,8 +215,9 @@ static void compute_clocks(int pio, pio_clocks_t *clks) { if (pio != PIO_NOT_EXIST) { - int adr_setup, data_pls, bus_speed; - bus_speed = ide_system_bus_speed(); + int adr_setup, data_pls; + int bus_speed = system_bus_clock(); + adr_setup = ide_pio_timings[pio].setup_time; data_pls = ide_pio_timings[pio].active_time; clks->address_time = cmpt_clk(adr_setup, bus_speed); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c --- v2.3.99-pre5/linux/drivers/ide/pdc4030.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/pdc4030.c Thu Apr 13 22:54:26 2000 @@ -82,6 +82,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/piix.c linux/drivers/ide/piix.c --- v2.3.99-pre5/linux/drivers/ide/piix.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/piix.c Thu Apr 13 22:54:26 2000 @@ -61,6 +61,7 @@ #include #include #include +#include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/qd6580.c linux/drivers/ide/qd6580.c --- v2.3.99-pre5/linux/drivers/ide/qd6580.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/qd6580.c Thu Apr 13 22:54:26 2000 @@ -20,6 +20,7 @@ #include #include #include +#include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/rapide.c linux/drivers/ide/rapide.c --- v2.3.99-pre5/linux/drivers/ide/rapide.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/rapide.c Thu Apr 13 22:54:26 2000 @@ -13,6 +13,7 @@ #include #include #include +#include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/rz1000.c linux/drivers/ide/rz1000.c --- v2.3.99-pre5/linux/drivers/ide/rz1000.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/rz1000.c Thu Apr 13 22:54:26 2000 @@ -28,6 +28,7 @@ #include #include #include +#include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c --- v2.3.99-pre5/linux/drivers/ide/sis5513.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/sis5513.c Tue Apr 25 17:55:37 2000 @@ -170,7 +170,7 @@ reg2, reg3); rc = pci_read_config_byte(bmide_dev, 0x4b, ®); - p += sprintf(p, "Drvie 0: Postwrite %s \t \t Postwrite %s\n", + p += sprintf(p, "Drive 0: Postwrite %s \t \t Postwrite %s\n", (reg & 0x10) ? "Enabled" : "Disabled", (reg & 0x40) ? "Enabled" : "Disabled"); p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n", @@ -194,7 +194,7 @@ rc = pci_read_config_byte(bmide_dev, 0x4b, ®); - p += sprintf(p, "Drvie 1: Postwrite %s \t \t Postwrite %s\n", + p += sprintf(p, "Drive 1: Postwrite %s \t \t Postwrite %s\n", (reg & 0x20) ? "Enabled" : "Disabled", (reg & 0x80) ? "Enabled" : "Disabled"); p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n", diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/umc8672.c linux/drivers/ide/umc8672.c --- v2.3.99-pre5/linux/drivers/ide/umc8672.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/umc8672.c Thu Apr 13 22:54:26 2000 @@ -48,6 +48,7 @@ #include #include #include +#include #include diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c --- v2.3.99-pre5/linux/drivers/ide/via82cxxx.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/via82cxxx.c Thu Apr 13 22:54:26 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/via82cxxx.c Version 0.08 Mar. 18, 2000 + * linux/drivers/ide/via82cxxx.c Version 0.09 Apr. 02, 2000 * * Copyright (C) 1998-99 Michel Aubry, Maintainer * Copyright (C) 1999 Jeff Garzik, MVP4 Support @@ -93,27 +93,127 @@ #include +#include "ide_modes.h" + static struct pci_dev *host_dev = NULL; static struct pci_dev *isa_dev = NULL; +struct chipset_bus_clock_list_entry { + byte xfer_speed; + + byte chipset_settings_25; + byte ultra_settings_25; + byte chipset_settings_33; + byte ultra_settings_33; + byte chipset_settings_37; + byte ultra_settings_37; + byte chipset_settings_41; + byte ultra_settings_41; +}; + +static struct chipset_bus_clock_list_entry * via82cxxx_table = NULL; + +struct chipset_bus_clock_list_entry via82cxxx_type_one [] = { + /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ + { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { XFER_UDMA_3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { XFER_UDMA_2, 0x60, 0x20, 0x60, 0x20, 0x60, 0x21, 0x00, 0x00 }, + { XFER_UDMA_1, 0x61, 0x20, 0x61, 0x20, 0x61, 0x21, 0x00, 0x00 }, + { XFER_UDMA_0, 0x62, 0x20, 0x62, 0x20, 0x62, 0x21, 0x00, 0x00 }, + + { XFER_MW_DMA_2, 0x03, 0x20, 0x03, 0x20, 0x03, 0x21, 0x00, 0x00 }, + { XFER_MW_DMA_1, 0x03, 0x31, 0x03, 0x31, 0x03, 0x32, 0x00, 0x00 }, + { XFER_MW_DMA_0, 0x03, 0x31, 0x03, 0x31, 0x03, 0x32, 0x00, 0x00 }, + + { XFER_PIO_4, 0x03, 0x20, 0x03, 0x20, 0x03, 0x21, 0x00, 0x00 }, + { XFER_PIO_3, 0x03, 0x31, 0x03, 0x31, 0x03, 0x32, 0x00, 0x00 }, + { XFER_PIO_2, 0x03, 0x65, 0x03, 0x65, 0x03, 0x76, 0x00, 0x00 }, + { XFER_PIO_1, 0x03, 0x65, 0x03, 0x65, 0x03, 0x76, 0x00, 0x00 }, + { XFER_PIO_0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xA9, 0x00, 0x00 }, + { 0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xA9, 0x00, 0x00 } +}; + +struct chipset_bus_clock_list_entry via82cxxx_type_two [] = { + /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ + { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { XFER_UDMA_3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { XFER_UDMA_2, 0xE0, 0x20, 0xE0, 0x20, 0xE1, 0x31, 0xE1, 0x32 }, + { XFER_UDMA_1, 0xE1, 0x20, 0xE1, 0x20, 0xE2, 0x31, 0xE2, 0x32 }, + { XFER_UDMA_0, 0xE2, 0x20, 0xE2, 0x20, 0xE2, 0x31, 0xE2, 0x32 }, + + { XFER_MW_DMA_2, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, + { XFER_MW_DMA_1, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, + { XFER_MW_DMA_0, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, + + { XFER_PIO_4, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, + { XFER_PIO_3, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, + { XFER_PIO_2, 0x03, 0x65, 0x03, 0x65, 0x03, 0x87, 0x03, 0xA8 }, + { XFER_PIO_1, 0x03, 0x65, 0x03, 0x65, 0x03, 0x87, 0x03, 0xA8 }, + { XFER_PIO_0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xDB, 0x03, 0xFE }, + { 0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xDB, 0x03, 0xFE } +}; + +struct chipset_bus_clock_list_entry via82cxxx_type_three [] = { + /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ + { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { XFER_UDMA_3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { XFER_UDMA_2, 0xE0, 0x20, 0xE0, 0x20, 0xE1, 0x31, 0xE1, 0x32 }, + { XFER_UDMA_1, 0xE1, 0x20, 0xE1, 0x20, 0xE2, 0x31, 0xE2, 0x32 }, + { XFER_UDMA_0, 0xE2, 0x20, 0xE2, 0x20, 0xE2, 0x31, 0xE2, 0x32 }, + + { XFER_MW_DMA_2, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, + { XFER_MW_DMA_1, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, + { XFER_MW_DMA_0, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, + + { XFER_PIO_4, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, + { XFER_PIO_3, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, + { XFER_PIO_2, 0x03, 0x65, 0x03, 0x65, 0x03, 0x87, 0x03, 0xA8 }, + { XFER_PIO_1, 0x03, 0x65, 0x03, 0x65, 0x03, 0x87, 0x03, 0xA8 }, + { XFER_PIO_0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xDB, 0x03, 0xFE }, + { 0, 0x03, 0xA8, 0x03, 0xA8, 0x03, 0xDB, 0x03, 0xFE } +}; + +struct chipset_bus_clock_list_entry via82cxxx_type_four [] = { + /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ + { XFER_UDMA_4, 0x00, 0x00, 0xE0, 0x20, 0xE1, 0x31, 0x00, 0x00 }, + { XFER_UDMA_3, 0x00, 0x00, 0xE1, 0x20, 0xE2, 0x31, 0x00, 0x00 }, + { XFER_UDMA_2, 0x00, 0x00, 0xE2, 0x20, 0xE4, 0x31, 0x00, 0x00 }, + { XFER_UDMA_1, 0x00, 0x00, 0xE4, 0x20, 0xE6, 0x31, 0x00, 0x00 }, + { XFER_UDMA_0, 0x00, 0x00, 0xE6, 0x20, 0xE6, 0x31, 0x00, 0x00 }, + + { XFER_MW_DMA_2, 0x00, 0x00, 0x03, 0x20, 0x03, 0x31, 0x00, 0x00 }, + { XFER_MW_DMA_1, 0x00, 0x00, 0x03, 0x31, 0x03, 0x42, 0x00, 0x00 }, + { XFER_MW_DMA_0, 0x00, 0x00, 0x03, 0x31, 0x03, 0x42, 0x00, 0x00 }, + + { XFER_PIO_4, 0x00, 0x00, 0x03, 0x20, 0x03, 0x31, 0x00, 0x00 }, + { XFER_PIO_3, 0x00, 0x00, 0x03, 0x31, 0x03, 0x42, 0x00, 0x00 }, + { XFER_PIO_2, 0x00, 0x00, 0x03, 0x65, 0x03, 0x87, 0x00, 0x00 }, + { XFER_PIO_1, 0x00, 0x00, 0x03, 0x65, 0x03, 0x87, 0x00, 0x00 }, + { XFER_PIO_0, 0x00, 0x00, 0x03, 0xA8, 0x03, 0xDB, 0x00, 0x00 }, + { 0, 0x00, 0x00, 0x03, 0xA8, 0x03, 0xDB, 0x00, 0x00 } +}; + static const struct { const char *name; + unsigned short vendor_id; unsigned short host_id; } ApolloHostChipInfo[] = { - { "VT 82C585 Apollo VP1/VPX", PCI_DEVICE_ID_VIA_82C585, }, - { "VT 82C595 Apollo VP2", PCI_DEVICE_ID_VIA_82C595, }, - { "VT 82C597 Apollo VP3", PCI_DEVICE_ID_VIA_82C597_0, }, - { "VT 82C598 Apollo MVP3", PCI_DEVICE_ID_VIA_82C598_0, }, - { "VT 82C598 Apollo MVP3", PCI_DEVICE_ID_VIA_82C598_0, }, - { "VT 82C680 Apollo P6", PCI_DEVICE_ID_VIA_82C680, }, - { "VT 82C691 Apollo Pro", PCI_DEVICE_ID_VIA_82C691, }, - { "VT 82C693 Apollo Pro Plus", PCI_DEVICE_ID_VIA_82C693, }, - { "Apollo MVP4", PCI_DEVICE_ID_VIA_8501_0, }, - { "VT 8371", PCI_DEVICE_ID_VIA_8371_0, }, - { "VT 8601", PCI_DEVICE_ID_VIA_8601_0, }, + { "VT 82C585 Apollo VP1/VPX", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C585, }, + { "VT 82C595 Apollo VP2", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C595, }, + { "VT 82C597 Apollo VP3", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, }, + { "VT 82C598 Apollo MVP3", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_0, }, + { "VT 82C598 Apollo MVP3", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_0, }, + { "VT 82C680 Apollo P6", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C680, }, + { "VT 82C691 Apollo Pro", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C691, }, + { "VT 82C693 Apollo Pro Plus", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C693, }, + { "Apollo MVP4", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8501_0, }, + { "VT 8371", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_0, }, + { "VT 8601", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, }, + { "AMD IronGate", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_7006, }, }; #define NUM_APOLLO_ISA_CHIP_DEVICES 2 +#define VIA_FLAG_NULL 0x00000000 #define VIA_FLAG_CHECK_REV 0x00000001 #define VIA_FLAG_ATA_66 0x00000002 @@ -121,18 +221,20 @@ unsigned short host_id; unsigned short isa_id; unsigned int flags; + struct chipset_bus_clock_list_entry * chipset_table; } ApolloISAChipInfo[] = { - { PCI_DEVICE_ID_VIA_82C585, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV }, - { PCI_DEVICE_ID_VIA_82C595, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV }, - { PCI_DEVICE_ID_VIA_82C597_0, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV }, - { PCI_DEVICE_ID_VIA_82C598_0, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV }, - { PCI_DEVICE_ID_VIA_82C598_0, PCI_DEVICE_ID_VIA_82C596, 0 }, - { PCI_DEVICE_ID_VIA_82C680, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV }, - { PCI_DEVICE_ID_VIA_82C691, PCI_DEVICE_ID_VIA_82C596, VIA_FLAG_ATA_66 }, - { PCI_DEVICE_ID_VIA_82C693, PCI_DEVICE_ID_VIA_82C596, 0 }, - { PCI_DEVICE_ID_VIA_8501_0, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66 }, - { PCI_DEVICE_ID_VIA_8371_0, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66 }, - { PCI_DEVICE_ID_VIA_8601_0, PCI_DEVICE_ID_VIA_8231, VIA_FLAG_ATA_66 }, + { PCI_DEVICE_ID_VIA_82C585, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV, via82cxxx_type_one }, + { PCI_DEVICE_ID_VIA_82C595, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV, via82cxxx_type_one }, + { PCI_DEVICE_ID_VIA_82C597_0, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV, via82cxxx_type_one }, + { PCI_DEVICE_ID_VIA_82C598_0, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV, via82cxxx_type_one }, + { PCI_DEVICE_ID_VIA_82C598_0, PCI_DEVICE_ID_VIA_82C596, VIA_FLAG_NULL, via82cxxx_type_one }, + { PCI_DEVICE_ID_VIA_82C680, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV, via82cxxx_type_one }, + { PCI_DEVICE_ID_VIA_82C691, PCI_DEVICE_ID_VIA_82C596, VIA_FLAG_ATA_66, via82cxxx_type_two }, + { PCI_DEVICE_ID_VIA_82C693, PCI_DEVICE_ID_VIA_82C596, VIA_FLAG_NULL, via82cxxx_type_one }, + { PCI_DEVICE_ID_VIA_8501_0, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66, via82cxxx_type_two }, + { PCI_DEVICE_ID_VIA_8371_0, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66, via82cxxx_type_two }, + { PCI_DEVICE_ID_VIA_8601_0, PCI_DEVICE_ID_VIA_8231, VIA_FLAG_ATA_66, via82cxxx_type_two }, + { PCI_DEVICE_ID_AMD_FE_GATE_7006, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66, via82cxxx_type_two }, }; #define arraysize(x) (sizeof(x)/sizeof(*(x))) @@ -515,69 +617,40 @@ } #ifdef CONFIG_VIA82CXXX_TUNING +static byte pci_bus_clock_list (byte speed, int ide_clock, struct chipset_bus_clock_list_entry * chipset_table) +{ + for ( ; chipset_table->xfer_speed ; chipset_table++) + if (chipset_table->xfer_speed == speed) { + switch(ide_clock) { + case 25: return chipset_table->chipset_settings_25; + case 33: return chipset_table->chipset_settings_33; + case 37: return chipset_table->chipset_settings_37; + case 41: return chipset_table->chipset_settings_41; + default: break; + } + } + return 0x00; +} -struct chipset_bus_clock_list_entry { - unsigned short bus_speed; - byte xfer_speed; - byte chipset_settings; -}; - -PCI_DEVICE_ID_VIA_82C586_1 -PCI_DEVICE_ID_VIA_82C596 -PCI_DEVICE_ID_VIA_82C686 -PCI_DEVICE_ID_VIA_8231 - -PCI_DEVICE_ID_VIA_82C586_1 TYPE_1 -PCI_DEVICE_ID_VIA_82C596 TYPE_2 -PCI_DEVICE_ID_VIA_82C686 TYPE_2 -PCI_DEVICE_ID_VIA_82C596 TYPE_3 -PCI_DEVICE_ID_VIA_82C686 TYPE_3 -PCI_DEVICE_ID_VIA_8231 TYPE_4 - -struct chipset_bus_clock_list_entry ultra_33_base [] = { -{ TYPE_1,25,0x00,0x00,0x60,0x61,0x62,0x03,0x20,0x31,0x65,0x65,0xA8 }, -{ TYPE_1,33,0x00,0x00,0x60,0x61,0x62,0x03,0x20,0x31,0x65,0x65,0xA8 }, -{ TYPE_1,37,0x00,0x00,0x60,0x61,0x62,0x03,0x21,0x32,0x76,0x76,0xA9 }, -{ TYPE_2,25,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 }, -{ TYPE_2,33,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 }, -{ TYPE_2,37,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x31,0x42,0x87,0x87,0xDB }, -{ TYPE_2,41,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x32,0x53,0xA8,0xA8,0xFE }, -{ TYPE_3,25,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 }, -{ TYPE_3,33,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 }, -{ TYPE_3,37,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x31,0x42,0x87,0x87,0xDB }, -{ TYPE_3,41,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x32,0x53,0xA8,0xA8,0xFE }, -{ TYPE_4,0,0,0,0,0,0,0,0,0,0,0,0 }, -{ 0,0,0,0,0,0,0,0,0,0,0,0,0 } -}; - -struct chipset_bus_clock_list_entry timing_66_base [] = { - { 37, XFER_PIO_4, 0x21 }, - { 37, XFER_PIO_3, 0x32 }, - { 37, XFER_PIO_2, 0x76 }, - { 37, XFER_PIO_1, 0x76 }, - { 37, XFER_PIO_0, 0xA9 }, - { ANY, XFER_PIO_4, 0x20 }, - { ANY, XFER_PIO_3, 0x31 }, - { ANY, XFER_PIO_2, 0x65 }, - { ANY, XFER_PIO_1, 0x65 }, - { ANY, XFER_PIO_0, 0xA8 }, -}; - -static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) +static byte pci_bus_clock_list_ultra (byte speed, int ide_clock, struct chipset_bus_clock_list_entry * chipset_table) { for ( ; chipset_table->xfer_speed ; chipset_table++) if (chipset_table->xfer_speed == speed) { - return chipset_table->chipset_settings; + switch(ide_clock) { + case 25: return chipset_table->ultra_settings_25; + case 33: return chipset_table->ultra_settings_33; + case 37: return chipset_table->ultra_settings_37; + case 41: return chipset_table->ultra_settings_41; + default: break; + } } - return 0x01208585; + return 0x00; } static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed) { - struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - unsigned long dma_base = hwif->dma_base; byte unit = (drive->select.b.unit & 0x01); int drive_number = ((hwif->channel ? 2 : 0) + unit); @@ -587,43 +660,23 @@ byte ultra = 0x00; int err; - int bus_speed = ide_system_bus_speed(); + int bus_speed = system_bus_clock(); switch(drive_number) { - case 0: ata2_pci = 0x48; ata3_pci = 0x50; break; - case 1: ata2_pci = 0x49; ata3_pci = 0x51; break; - case 2: ata2_pci = 0x4a; ata3_pci = 0x52; break; - case 3: ata2_pci = 0x4b; ata3_pci = 0x53; break; + case 0: ata2_pci = 0x4b; ata3_pci = 0x53; break; + case 1: ata2_pci = 0x4a; ata3_pci = 0x52; break; + case 2: ata2_pci = 0x49; ata3_pci = 0x51; break; + case 3: ata2_pci = 0x48; ata3_pci = 0x50; break; default: return -1; } pci_read_config_byte(dev, ata2_pci, &timing); - pci_read_config_byte(dev, ata3_pci, &ultra); - - switch(speed) { - 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_MW_DMA_1: - case XFER_MW_DMA_0: - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - case XFER_PIO_SLOW: - default: - break; - } - + timing = pci_bus_clock_list(speed, bus_speed, via82cxxx_table); pci_write_config_byte(dev, ata2_pci, timing); + + pci_read_config_byte(dev, ata3_pci, &ultra); + ultra = pci_bus_clock_list_ultra(speed, bus_speed, via82cxxx_table); pci_write_config_byte(dev, ata3_pci, ultra); err = ide_config_drive_speed(drive, speed); @@ -830,6 +883,8 @@ if (ata33 | ata66) printk(" Chipset Core ATA-%s", ata66 ? "66" : "33"); + + via82cxxx_table = ApolloISAChipInfo[j].chipset_table; } printk("\n"); } @@ -847,8 +902,11 @@ unsigned int __init ata66_via82cxxx (ide_hwif_t *hwif) { - /* (Jeff Garzik) FIXME!!! for MVP4 */ - return 0; + byte ata66 = 0; + byte ata66reg = hwif->channel ? 0x50 : 0x52; + pci_read_config_byte(hwif->pci_dev, ata66reg, &ata66); + + return ((ata66 & 0x04) ? 1 : 0); } void __init ide_init_via82cxxx (ide_hwif_t *hwif) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/b1dma.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/isdn/avmb1/b1dma.c Thu Apr 13 09:03:03 2000 @@ -1,11 +1,14 @@ /* - * $Id: b1dma.c,v 1.3 2000/02/26 01:00:53 keil Exp $ + * $Id: b1dma.c,v 1.4 2000/04/03 16:38:05 calle Exp $ * * Common module for AVM B1 cards that support dma with AMCC * * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1dma.c,v $ + * Revision 1.4 2000/04/03 16:38:05 calle + * made suppress_pollack static. + * * Revision 1.3 2000/02/26 01:00:53 keil * changes from 2.3.47 * @@ -34,13 +37,13 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.3 $"; +static char *revision = "$Revision: 1.4 $"; /* ------------------------------------------------------------- */ MODULE_AUTHOR("Carsten Paeth "); -int suppress_pollack = 0; +static int suppress_pollack = 0; MODULE_PARM(suppress_pollack, "0-1i"); /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/b1isa.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/b1isa.c Thu Apr 13 09:03:03 2000 @@ -1,11 +1,15 @@ /* - * $Id: b1isa.c,v 1.7 2000/02/02 18:36:03 calle Exp $ + * $Id: b1isa.c,v 1.8 2000/04/03 13:29:24 calle Exp $ * * Module for AVM B1 ISA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1isa.c,v $ + * Revision 1.8 2000/04/03 13:29:24 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.7 2000/02/02 18:36:03 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -69,7 +73,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.7 $"; +static char *revision = "$Revision: 1.8 $"; /* ------------------------------------------------------------- */ @@ -265,6 +269,9 @@ { struct capi_driver *driver = &b1isa_driver; char *p; + int retval = 0; + + MOD_INC_USE_COUNT; if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); @@ -279,9 +286,10 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); - return -EIO; + retval = -EIO; } - return 0; + MOD_DEC_USE_COUNT; + return retval; } #ifdef MODULE diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/b1pci.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/b1pci.c Thu Apr 13 09:03:03 2000 @@ -1,11 +1,15 @@ /* - * $Id: b1pci.c,v 1.20 2000/02/02 18:36:03 calle Exp $ + * $Id: b1pci.c,v 1.21 2000/04/03 13:29:24 calle Exp $ * * Module for AVM B1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pci.c,v $ + * Revision 1.21 2000/04/03 13:29:24 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.20 2000/02/02 18:36:03 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -75,7 +79,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.20 $"; +static char *revision = "$Revision: 1.21 $"; /* ------------------------------------------------------------- */ @@ -509,6 +513,8 @@ char *p; int retval; + MOD_INC_USE_COUNT; + if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); p = strchr(driver->revision, '$'); @@ -522,6 +528,7 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; } @@ -534,6 +541,7 @@ detach_capi_driver(driver); printk(KERN_ERR "%s: failed to attach capi_driver\n", driverv4->name); + MOD_DEC_USE_COUNT; return -EIO; } #endif @@ -545,6 +553,7 @@ #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 detach_capi_driver(driverv4); #endif + MOD_DEC_USE_COUNT; return -EIO; } @@ -554,6 +563,7 @@ #ifdef MODULE cleanup_module(); #endif + MOD_DEC_USE_COUNT; return retval; } ncards++; @@ -561,12 +571,15 @@ if (ncards) { printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n", driver->name, ncards); + MOD_DEC_USE_COUNT; return 0; } printk(KERN_ERR "%s: NO B1-PCI card detected\n", driver->name); + MOD_DEC_USE_COUNT; return -ESRCH; #else printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; #endif } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/b1pcmcia.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/avmb1/b1pcmcia.c Thu Apr 13 17:06:00 2000 @@ -1,11 +1,15 @@ /* - * $Id: b1pcmcia.c,v 1.8 2000/03/06 18:00:23 calle Exp $ + * $Id: b1pcmcia.c,v 1.9 2000/04/03 13:29:24 calle Exp $ * * Module for AVM B1/M1/M2 PCMCIA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pcmcia.c,v $ + * Revision 1.9 2000/04/03 13:29:24 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.8 2000/03/06 18:00:23 calle * - Middleware extention now working with 2.3.49 (capifs). * - Fixed typos in debug section of capi.c @@ -75,7 +79,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.8 $"; +static char *revision = "$Revision: 1.9 $"; /* ------------------------------------------------------------- */ @@ -301,6 +305,9 @@ { struct capi_driver *driver = &b1pcmcia_driver; char *p; + int retval = 0; + + MOD_INC_USE_COUNT; if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); @@ -315,9 +322,10 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); - return -EIO; + retval = -EIO; } - return 0; + MOD_DEC_USE_COUNT; + return retval; } #ifdef MODULE diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/c4.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/avmb1/c4.c Thu Apr 13 09:03:03 2000 @@ -1,11 +1,18 @@ /* - * $Id: c4.c,v 1.6 2000/03/17 12:21:08 calle Exp $ + * $Id: c4.c,v 1.8 2000/04/03 16:38:05 calle Exp $ * * Module for AVM C4 card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: c4.c,v $ + * Revision 1.8 2000/04/03 16:38:05 calle + * made suppress_pollack static. + * + * Revision 1.7 2000/04/03 13:29:24 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.6 2000/03/17 12:21:08 calle * send patchvalues now working. * @@ -46,7 +53,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.6 $"; +static char *revision = "$Revision: 1.8 $"; #undef CONFIG_C4_DEBUG #undef CONFIG_C4_POLLDEBUG @@ -71,7 +78,7 @@ /* ------------------------------------------------------------- */ -int suppress_pollack = 0; +static int suppress_pollack = 0; MODULE_AUTHOR("Carsten Paeth "); @@ -1294,6 +1301,8 @@ char *p; int retval; + MOD_INC_USE_COUNT; + if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); p = strchr(driver->revision, '$'); @@ -1307,6 +1316,7 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; } @@ -1314,6 +1324,7 @@ if (!pci_present()) { printk(KERN_ERR "%s: no PCI bus present\n", driver->name); detach_capi_driver(driver); + MOD_DEC_USE_COUNT; return -EIO; } @@ -1337,6 +1348,7 @@ #ifdef MODULE cleanup_module(); #endif + MOD_DEC_USE_COUNT; return retval; } ncards++; @@ -1344,12 +1356,15 @@ if (ncards) { printk(KERN_INFO "%s: %d C4 card(s) detected\n", driver->name, ncards); + MOD_DEC_USE_COUNT; return 0; } printk(KERN_ERR "%s: NO C4 card detected\n", driver->name); + MOD_DEC_USE_COUNT; return -ESRCH; #else printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; #endif } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/capi.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/avmb1/capi.c Fri Apr 21 15:17:57 2000 @@ -1,11 +1,15 @@ /* - * $Id: capi.c,v 1.30 2000/03/19 12:31:36 calle Exp $ + * $Id: capi.c,v 1.31 2000/04/03 13:29:24 calle Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.31 2000/04/03 13:29:24 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.30 2000/03/19 12:31:36 calle * PPP over CAPI raw driver disabled for now, ppp_generic has been changed. * @@ -189,7 +193,7 @@ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #include -static char *revision = "$Revision: 1.30 $"; +static char *revision = "$Revision: 1.31 $"; MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); @@ -362,12 +366,13 @@ struct capiminor *mp, **pp; unsigned int minor = 0; + MOD_INC_USE_COUNT; mp = (struct capiminor *)kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC); if (!mp) { + MOD_DEC_USE_COUNT; printk(KERN_ERR "capi: can't alloc capiminor\n"); return 0; } - MOD_INC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capiminor_alloc %d\n", GET_USE_COUNT(THIS_MODULE)); #endif @@ -1835,7 +1840,7 @@ *eof = 1; if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/capidrv.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/avmb1/capidrv.c Thu Apr 13 09:03:03 2000 @@ -1,11 +1,21 @@ /* - * $Id: capidrv.c,v 1.30 2000/03/03 15:50:42 calle Exp $ + * $Id: capidrv.c,v 1.32 2000/04/07 15:19:58 calle Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.c,v $ + * Revision 1.32 2000/04/07 15:19:58 calle + * remove warnings + * + * Revision 1.31 2000/04/06 15:01:25 calle + * Bugfix: crash in capidrv.c when reseting a capi controller. + * - changed code order on remove of controller. + * - using tq_schedule for notifier in kcapi.c. + * - now using spin_lock_irqsave() and spin_unlock_irqrestore(). + * strange: sometimes even MP hang on unload of isdn.o ... + * * Revision 1.30 2000/03/03 15:50:42 calle * - kernel CAPI: * - Changed parameter "param" in capi_signal from __u32 to void *. @@ -182,8 +192,8 @@ #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.30 $"; -int debugmode = 0; +static char *revision = "$Revision: 1.32 $"; +static int debugmode = 0; MODULE_AUTHOR("Carsten Paeth "); MODULE_PARM(debugmode, "i"); @@ -291,6 +301,7 @@ /* -------- data definitions ----------------------------------------- */ static capidrv_data global; +static spinlock_t global_lock = SPIN_LOCK_UNLOCKED; static struct capi_interface *capifuncs; static void handle_dtrace_data(capidrv_contr *card, @@ -450,33 +461,27 @@ static inline capidrv_contr *findcontrbydriverid(int driverid) { - capidrv_contr *p = global.contr_list; - long flags; + unsigned long flags; + capidrv_contr *p; - save_flags(flags); - cli(); - while (p) { + spin_lock_irqsave(&global_lock, flags); + for (p = global.contr_list; p; p = p->next) if (p->myid == driverid) break; - p = p->next; - } - restore_flags(flags); + spin_unlock_irqrestore(&global_lock, flags); return p; } static capidrv_contr *findcontrbynumber(__u32 contr) { + unsigned long flags; capidrv_contr *p = global.contr_list; - long flags; - save_flags(flags); - cli(); - while (p) { + spin_lock_irqsave(&global_lock, flags); + for (p = global.contr_list; p; p = p->next) if (p->contrnr == contr) break; - p = p->next; - } - restore_flags(flags); + spin_unlock_irqrestore(&global_lock, flags); return p; } @@ -1564,47 +1569,41 @@ static void handle_dtrace_data(capidrv_contr *card, int send, int level2, __u8 *data, __u16 len) { - long flags; - __u8 *p, *end; - isdn_ctrl cmd; + __u8 *p, *end; + isdn_ctrl cmd; - if (!len) { - printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n", + if (!len) { + printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n", card->contrnr, len); - return; - } - - save_flags(flags); - cli(); - - if (level2) { - PUTBYTE_TO_STATUS(card, 'D'); - PUTBYTE_TO_STATUS(card, '2'); - PUTBYTE_TO_STATUS(card, send ? '>' : '<'); - PUTBYTE_TO_STATUS(card, ':'); - } else { - PUTBYTE_TO_STATUS(card, 'D'); - PUTBYTE_TO_STATUS(card, '3'); - PUTBYTE_TO_STATUS(card, send ? '>' : '<'); - PUTBYTE_TO_STATUS(card, ':'); - } + return; + } - for (p = data, end = data+len; p < end; p++) { - __u8 w; - PUTBYTE_TO_STATUS(card, ' '); - w = (*p >> 4) & 0xf; - PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); - w = *p & 0xf; - PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); - } - PUTBYTE_TO_STATUS(card, '\n'); + if (level2) { + PUTBYTE_TO_STATUS(card, 'D'); + PUTBYTE_TO_STATUS(card, '2'); + PUTBYTE_TO_STATUS(card, send ? '>' : '<'); + PUTBYTE_TO_STATUS(card, ':'); + } else { + PUTBYTE_TO_STATUS(card, 'D'); + PUTBYTE_TO_STATUS(card, '3'); + PUTBYTE_TO_STATUS(card, send ? '>' : '<'); + PUTBYTE_TO_STATUS(card, ':'); + } + + for (p = data, end = data+len; p < end; p++) { + __u8 w; + PUTBYTE_TO_STATUS(card, ' '); + w = (*p >> 4) & 0xf; + PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); + w = *p & 0xf; + PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); + } + PUTBYTE_TO_STATUS(card, '\n'); - restore_flags(flags); - - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = len*3+5; - card->interface.statcallb(&cmd); + cmd.command = ISDN_STAT_STAVAIL; + cmd.driver = card->myid; + cmd.arg = len*3+5; + card->interface.statcallb(&cmd); } /* ------------------------------------------------------------------- */ @@ -2009,8 +2008,8 @@ return capidrv_command(c, card); printk(KERN_ERR - "capidrv-%d: if_command %d called with invalid driverId %d!\n", - card->contrnr, c->command, c->driver); + "capidrv: if_command %d called with invalid driverId %d!\n", + c->command, c->driver); return -ENODEV; } @@ -2297,12 +2296,11 @@ } card->myid = card->interface.channels; - save_flags(flags); - cli(); + spin_lock_irqsave(&global_lock, flags); card->next = global.contr_list; global.contr_list = card; global.ncontr++; - restore_flags(flags); + spin_unlock_irqrestore(&global_lock, flags); memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan); for (i = 0; i < card->nbchan; i++) { @@ -2333,25 +2331,22 @@ static int capidrv_delcontr(__u16 contr) { capidrv_contr **pp, *card; + unsigned long flags; isdn_ctrl cmd; - long flags; - int i; - save_flags(flags); - cli(); - for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { - if ((*pp)->contrnr == contr) + spin_lock_irqsave(&global_lock, flags); + for (card = global.contr_list; card; card = card->next) { + if (card->contrnr == contr) break; } - if (!*pp) { - restore_flags(flags); + if (!card) { + spin_unlock_irqrestore(&global_lock, flags); printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr); return -1; } - card = *pp; - *pp = (*pp)->next; - global.ncontr--; - restore_flags(flags); + spin_unlock_irqrestore(&global_lock, flags); + + del_timer(&card->listentimer); if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n", @@ -2361,28 +2356,51 @@ cmd.driver = card->myid; card->interface.statcallb(&cmd); - for (i = 0; i < card->nbchan; i++) { + while (card->nbchan) { cmd.command = ISDN_STAT_DISCH; cmd.driver = card->myid; - cmd.arg = i; + cmd.arg = card->nbchan-1; cmd.parm.num[0] = 0; + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n", + card->contrnr, card->myid, cmd.arg); card->interface.statcallb(&cmd); - if (card->bchans[i].nccip) - free_ncci(card, card->bchans[i].nccip); - if (card->bchans[i].plcip) - free_plci(card, card->bchans[i].plcip); + if (card->bchans[card->nbchan-1].nccip) + 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--; } kfree(card->bchans); - del_timer(&card->listentimer); + card->bchans = 0; + + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n", + card->contrnr, card->myid); cmd.command = ISDN_STAT_UNLOAD; cmd.driver = card->myid; card->interface.statcallb(&cmd); + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n", + card->contrnr, card->myid); + + spin_lock_irqsave(&global_lock, flags); + for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { + if (*pp == card) { + *pp = (*pp)->next; + card->next = 0; + global.ncontr--; + break; + } + } + spin_unlock_irqrestore(&global_lock, flags); + kfree(card); printk(KERN_INFO "%s: now down.\n", card->name); @@ -2539,12 +2557,10 @@ #ifdef MODULE void cleanup_module(void) { - capidrv_contr *card, *next; - long flags; char rev[10]; char *p; - if ((p = strchr(revision, ':'))) { + if ((p = strchr(revision, ':')) != 0) { strcpy(rev, p + 1); p = strchr(rev, '$'); *p = 0; @@ -2552,21 +2568,10 @@ strcpy(rev, " ??? "); } - for (card = global.contr_list; card; card = next) { - next = card->next; - disable_dchannel_trace(card); - } - - save_flags(flags); - cli(); - for (card = global.contr_list; card; card = next) { - next = card->next; - capidrv_delcontr(card->contrnr); - } - restore_flags(flags); - (void) (*capifuncs->capi_release) (global.appid); + detach_capi_interface(&cuser); + proc_exit(); printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/capifs.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/avmb1/capifs.c Thu Apr 13 17:06:00 2000 @@ -1,11 +1,15 @@ /* - * $Id: capifs.c,v 1.5 2000/03/13 17:49:52 calle Exp $ + * $Id: capifs.c,v 1.6 2000/04/03 13:29:25 calle Exp $ * * (c) Copyright 2000 by Carsten Paeth (calle@calle.de) * * Heavily based on devpts filesystem from H. Peter Anvin * * $Log: capifs.c,v $ + * Revision 1.6 2000/04/03 13:29:25 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.5 2000/03/13 17:49:52 calle * make it running with 2.3.51. * @@ -56,7 +60,7 @@ MODULE_AUTHOR("Carsten Paeth "); -static char *revision = "$Revision: 1.5 $"; +static char *revision = "$Revision: 1.6 $"; struct capifs_ncci { struct inode *inode; @@ -554,6 +558,8 @@ char *p; int err; + MOD_INC_USE_COUNT; + if ((p = strchr(revision, ':'))) { strcpy(rev, p + 1); p = strchr(rev, '$'); @@ -562,13 +568,16 @@ strcpy(rev, "1.0"); err = register_filesystem(&capifs_fs_type); - if (err) + if (err) { + MOD_DEC_USE_COUNT; return err; + } #ifdef MODULE printk(KERN_NOTICE "capifs: Rev%s: loaded\n", rev); #else printk(KERN_NOTICE "capifs: Rev%s: started\n", rev); #endif + MOD_DEC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/kcapi.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/avmb1/kcapi.c Fri Apr 21 15:17:57 2000 @@ -1,11 +1,22 @@ /* - * $Id: kcapi.c,v 1.13 2000/03/03 15:50:42 calle Exp $ + * $Id: kcapi.c,v 1.15 2000/04/06 15:01:25 calle Exp $ * * Kernel CAPI 2.0 Module * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: kcapi.c,v $ + * Revision 1.15 2000/04/06 15:01:25 calle + * Bugfix: crash in capidrv.c when reseting a capi controller. + * - changed code order on remove of controller. + * - using tq_schedule for notifier in kcapi.c. + * - now using spin_lock_irqsave() and spin_unlock_irqrestore(). + * strange: sometimes even MP hang on unload of isdn.o ... + * + * Revision 1.14 2000/04/03 13:29:25 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.13 2000/03/03 15:50:42 calle * - kernel CAPI: * - Changed parameter "param" in capi_signal from __u32 to void *. @@ -98,7 +109,7 @@ #include #endif -static char *revision = "$Revision: 1.13 $"; +static char *revision = "$Revision: 1.15 $"; /* ------------------------------------------------------------- */ @@ -270,7 +281,7 @@ *eof = 1; if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -541,20 +552,21 @@ struct capi_notifier *tail; } notifier_list; +static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED; + static inline void notify_enqueue(struct capi_notifier *np) { struct capi_notifier_list *q = ¬ifier_list; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(¬ifier_lock, flags); if (q->tail) { q->tail->next = np; q->tail = np; } else { q->head = q->tail = np; } - restore_flags(flags); + spin_unlock_irqrestore(¬ifier_lock, flags); } static inline struct capi_notifier *notify_dequeue(void) @@ -563,15 +575,14 @@ struct capi_notifier *np = 0; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(¬ifier_lock, flags); if (q->head) { np = q->head; if ((q->head = np->next) == 0) q->tail = 0; np->next = 0; } - restore_flags(flags); + spin_unlock_irqrestore(¬ifier_lock, flags); return np; } @@ -580,18 +591,24 @@ { struct capi_notifier *np; + MOD_INC_USE_COUNT; np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC); - if (!np) + if (!np) { + MOD_DEC_USE_COUNT; return -1; + } memset(np, 0, sizeof(struct capi_notifier)); np->cmd = cmd; np->controller = controller; np->applid = applid; np->ncci = ncci; notify_enqueue(np); - MOD_INC_USE_COUNT; - queue_task(&tq_state_notify, &tq_immediate); - mark_bh(IMMEDIATE_BH); + /* + * The notifier will result in adding/deleteing + * of devices. Devices can only removed in + * user process, not in bh. + */ + queue_task(&tq_state_notify, &tq_scheduler); return 0; } @@ -1732,6 +1749,8 @@ char *p; char rev[10]; + MOD_INC_USE_COUNT; + skb_queue_head_init(&recv_queue); /* init_bh(CAPI_BH, do_capi_bh); */ @@ -1773,6 +1792,7 @@ (void)c4_init(); #endif #endif + MOD_DEC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/t1isa.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/t1isa.c Thu Apr 13 09:03:03 2000 @@ -1,11 +1,15 @@ /* - * $Id: t1isa.c,v 1.10 2000/02/02 18:36:04 calle Exp $ + * $Id: t1isa.c,v 1.11 2000/04/03 13:29:25 calle Exp $ * * Module for AVM T1 HEMA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1isa.c,v $ + * Revision 1.11 2000/04/03 13:29:25 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.10 2000/02/02 18:36:04 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -81,7 +85,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.10 $"; +static char *revision = "$Revision: 1.11 $"; /* ------------------------------------------------------------- */ @@ -598,6 +602,9 @@ { struct capi_driver *driver = &t1isa_driver; char *p; + int retval = 0; + + MOD_INC_USE_COUNT; if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); @@ -612,9 +619,11 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); - return -EIO; + retval = -EIO; } - return 0; + + MOD_DEC_USE_COUNT; + return retval; } #ifdef MODULE diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c --- v2.3.99-pre5/linux/drivers/isdn/avmb1/t1pci.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/t1pci.c Thu Apr 13 09:03:03 2000 @@ -1,11 +1,18 @@ /* - * $Id: t1pci.c,v 1.5 2000/02/02 18:36:04 calle Exp $ + * $Id: t1pci.c,v 1.7 2000/04/07 15:26:55 calle Exp $ * * Module for AVM T1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1pci.c,v $ + * Revision 1.7 2000/04/07 15:26:55 calle + * better error message if cabel not connected or T1 has no power. + * + * Revision 1.6 2000/04/03 13:29:25 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.5 2000/02/02 18:36:04 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -47,7 +54,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.5 $"; +static char *revision = "$Revision: 1.7 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG @@ -164,7 +171,11 @@ b1dma_reset(card); if ((retval = t1pci_detect(card)) != 0) { - printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", + if (retval < 6) + printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", + driver->name, card->port, retval); + else + printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n", driver->name, card->port, retval); iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); kfree(card->ctrlinfo); @@ -264,6 +275,8 @@ char *p; int retval; + MOD_INC_USE_COUNT; + if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); p = strchr(driver->revision, '$'); @@ -277,6 +290,7 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; } @@ -284,6 +298,7 @@ if (!pci_present()) { printk(KERN_ERR "%s: no PCI bus present\n", driver->name); detach_capi_driver(driver); + MOD_DEC_USE_COUNT; return -EIO; } @@ -305,6 +320,7 @@ #ifdef MODULE cleanup_module(); #endif + MOD_DEC_USE_COUNT; return retval; } ncards++; @@ -312,12 +328,15 @@ if (ncards) { printk(KERN_INFO "%s: %d T1-PCI card(s) detected\n", driver->name, ncards); + MOD_DEC_USE_COUNT; return 0; } printk(KERN_ERR "%s: NO T1-PCI card detected\n", driver->name); + MOD_DEC_USE_COUNT; return -ESRCH; #else printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; #endif } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.3.99-pre5/linux/drivers/isdn/hisax/hisax.h Sat Feb 26 22:31:46 2000 +++ linux/drivers/isdn/hisax/hisax.h Thu Apr 13 09:03:03 2000 @@ -1,8 +1,11 @@ -/* $Id: hisax.h,v 2.41 2000/02/26 00:35:13 keil Exp $ +/* $Id: hisax.h,v 2.42 2000/04/09 19:02:44 keil Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 2.42 2000/04/09 19:02:44 keil + * retry pump modulation settings if it fails + * * Revision 2.41 2000/02/26 00:35:13 keil * Fix skb freeing in interrupt context * @@ -500,6 +503,7 @@ u_char mod; u_char newcmd; u_char newmod; + char try_mod; struct timer_list ftimer; u_char *rcvbuf; /* B-Channel receive Buffer */ u_char conmsg[16]; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c --- v2.3.99-pre5/linux/drivers/isdn/hisax/isar.c Sat Feb 26 22:31:46 2000 +++ linux/drivers/isdn/hisax/isar.c Thu Apr 13 09:03:03 2000 @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.10 2000/02/26 00:35:13 keil Exp $ +/* $Id: isar.c,v 1.11 2000/04/09 19:02:44 keil Exp $ * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -6,6 +6,9 @@ * * * $Log: isar.c,v $ + * Revision 1.11 2000/04/09 19:02:44 keil + * retry pump modulation settings if it fails + * * Revision 1.10 2000/02/26 00:35:13 keil * Fix skb freeing in interrupt context * @@ -1085,13 +1088,14 @@ break; case PCTRL_CMD_FRH: case PCTRL_CMD_FRM: - p1 = bcs->hw.isar.newmod; + p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod; bcs->hw.isar.newmod = 0; bcs->hw.isar.cmd = bcs->hw.isar.newcmd; bcs->hw.isar.newcmd = 0; sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, bcs->hw.isar.cmd, 1, &p1); bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.try_mod = 3; break; default: if (cs->debug & L1_DEB_HSCX) @@ -1117,13 +1121,14 @@ if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev RSP_SILDET"); if (bcs->hw.isar.state == STFAX_SILDET) { - p1 = bcs->hw.isar.newmod; + p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod; bcs->hw.isar.newmod = 0; bcs->hw.isar.cmd = bcs->hw.isar.newcmd; bcs->hw.isar.newcmd = 0; sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, bcs->hw.isar.cmd, 1, &p1); bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.try_mod = 3; } break; case PSEV_RSP_SILOFF: @@ -1131,6 +1136,17 @@ debugl1(cs, "pump stev RSP_SILOFF"); break; case PSEV_RSP_FCERR: + if (bcs->hw.isar.state == STFAX_LINE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_FCERR try %d", + bcs->hw.isar.try_mod); + if (bcs->hw.isar.try_mod--) { + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, + bcs->hw.isar.cmd, 1, + &bcs->hw.isar.mod); + break; + } + } if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev RSP_FCERR"); bcs->hw.isar.state = STFAX_ESCAPE; @@ -1441,6 +1457,7 @@ bcs->hw.isar.mod = para; bcs->hw.isar.newmod = 0; bcs->hw.isar.newcmd = 0; + bcs->hw.isar.try_mod = 3; } else if ((bcs->hw.isar.state == STFAX_ACTIV) && (bcs->hw.isar.cmd == PCTRL_CMD_FTM) && (bcs->hw.isar.mod == para)) { @@ -1463,6 +1480,7 @@ bcs->hw.isar.mod = para; bcs->hw.isar.newmod = 0; bcs->hw.isar.newcmd = 0; + bcs->hw.isar.try_mod = 3; } else if ((bcs->hw.isar.state == STFAX_ACTIV) && (bcs->hw.isar.cmd == PCTRL_CMD_FTH) && (bcs->hw.isar.mod == para)) { @@ -1485,6 +1503,7 @@ bcs->hw.isar.mod = para; bcs->hw.isar.newmod = 0; bcs->hw.isar.newcmd = 0; + bcs->hw.isar.try_mod = 3; } else if ((bcs->hw.isar.state == STFAX_ACTIV) && (bcs->hw.isar.cmd == PCTRL_CMD_FRM) && (bcs->hw.isar.mod == para)) { @@ -1507,6 +1526,7 @@ bcs->hw.isar.mod = para; bcs->hw.isar.newmod = 0; bcs->hw.isar.newcmd = 0; + bcs->hw.isar.try_mod = 3; } else if ((bcs->hw.isar.state == STFAX_ACTIV) && (bcs->hw.isar.cmd == PCTRL_CMD_FRH) && (bcs->hw.isar.mod == para)) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c --- v2.3.99-pre5/linux/drivers/isdn/hisax/isdnl2.c Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/hisax/isdnl2.c Thu Apr 13 09:03:03 2000 @@ -1,4 +1,4 @@ -/* $Id: isdnl2.c,v 2.20 1999/08/25 16:52:04 keil Exp $ +/* $Id: isdnl2.c,v 2.22 2000/04/12 20:28:37 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -11,6 +11,13 @@ * Fritz Elfert * * $Log: isdnl2.c,v $ + * Revision 2.22 2000/04/12 20:28:37 keil + * a I frame may be contain zero information bytes + * + * Revision 2.21 2000/04/12 16:41:01 kai + * fix max iframe size + * fix bug in multicasting DL_RELEASE_IND + * * Revision 2.20 1999/08/25 16:52:04 keil * Make gcc on AXP happy * @@ -83,7 +90,7 @@ #include "hisax.h" #include "isdnl2.h" -const char *l2_revision = "$Revision: 2.20 $"; +const char *l2_revision = "$Revision: 2.22 $"; static void l2m_debug(struct FsmInst *fi, char *fmt, ...); @@ -361,7 +368,7 @@ int iframe_error(struct PStack *st, struct sk_buff *skb) { - int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 1 : 0); + int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1); int rsp = *skb->data & 0x2; if (test_bit(FLG_ORIG, &st->l2.flag)) @@ -371,7 +378,7 @@ return 'L'; - if (skb->len <= i) + if (skb->len < i) return 'N'; if ((skb->len - i) > st->l2.maxlen) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c --- v2.3.99-pre5/linux/drivers/isdn/hisax/isdnl3.c Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/hisax/isdnl3.c Thu Apr 13 09:03:03 2000 @@ -1,4 +1,4 @@ -/* $Id: isdnl3.c,v 2.10 1999/07/21 14:46:19 keil Exp $ +/* $Id: isdnl3.c,v 2.11 2000/04/12 16:41:01 kai Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -11,6 +11,10 @@ * Fritz Elfert * * $Log: isdnl3.c,v $ + * Revision 2.11 2000/04/12 16:41:01 kai + * fix max iframe size + * fix bug in multicasting DL_RELEASE_IND + * * Revision 2.10 1999/07/21 14:46:19 keil * changes from EICON certification * @@ -68,7 +72,7 @@ #include "isdnl3.h" #include -const char *l3_revision = "$Revision: 2.10 $"; +const char *l3_revision = "$Revision: 2.11 $"; static struct Fsm l3fsm = @@ -375,10 +379,13 @@ l3ml3p(struct PStack *st, int pr) { struct l3_process *p = st->l3.proc; + struct l3_process *np; while (p) { + /* p might be kfreed under us, so we need to save where we want to go on */ + np = p->next; st->l3.l3ml3(st, pr, p); - p = p->next; + p = np; } } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc --- v2.3.99-pre5/linux/drivers/isdn/hisax/md5sums.asc Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/hisax/md5sums.asc Thu Apr 13 09:03:03 2000 @@ -8,8 +8,8 @@ # 3fb9c99465857a4c136ae2881f4e30ba isac.c dd3955847bbf680b41233478fe521d88 isdnl1.c -bb51bd223040b511c18f091da5ab6456 isdnl2.c -b7aa7f97b2374967a4aca7c52991142c isdnl3.c +d362523462c424a8bce8b596ed5bdf2e isdnl2.c +92ea268891c222963a6ca70935bf1556 isdnl3.c a23fbf8879c1432b04640b8b04bdf419 tei.c 838791b14269ec94c74ba4ae89c022e6 callc.c bf9605b36429898f7be6630034e83230 cert.c @@ -23,9 +23,9 @@ Version: 2.6.3i Charset: noconv -iQCVAwUBONlcejpxHvX/mS9tAQFWYAP/WmxgwQ7W6gVnsMkUlwzE1TKGWVJdGUTC -7WrKEtdweuzW3/7WEzjBoZgUEcpugJYK3JENby1xjh3yIHfws4HqLme1yXAmkYUK -6LmW96HC2g4wj7PH0hvLnzTOtXDGTppU7KJibbB+ziyhBbs6SGXOD4zHrCWmT9ld -CURhfNgftIs= -=AA+Q +iQCVAwUBOPT2aTpxHvX/mS9tAQFJyAQAj+eY8MhPxQ2TS3rtfjK7bv8jrOGeJYu6 +P0YPnkkc09pCA6UdmYP6VSFkhtDS43HEZiGMb1MV/Y4LQ4wVDNrFDk9AyUNhP2/0 +gY+nYON6hT9ilXYqsbqoqGmh5qLaxj64p9mKu+MIgZ69CS4g7aj/OAXWB06zh7li +MiC65PNo6k0= +=d7xA -----END PGP SIGNATURE----- diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c --- v2.3.99-pre5/linux/drivers/isdn/hisax/niccy.c Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/hisax/niccy.c Thu Apr 13 09:03:03 2000 @@ -1,4 +1,4 @@ -/* $Id: niccy.c,v 1.8 1999/08/11 21:01:33 keil Exp $ +/* $Id: niccy.c,v 1.10 2000/04/11 11:12:39 keil Exp $ * niccy.c low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and * compatible (SAGEM cybermodem) @@ -8,6 +8,12 @@ * Thanks to Dr. Neuhaus and SAGEM for informations * * $Log: niccy.c,v $ + * Revision 1.10 2000/04/11 11:12:39 keil + * cleanup + * + * Revision 1.9 2000/04/09 19:09:19 keil + * Bugfix: reset IRQ enable only valid for PCI version + * * Revision 1.8 1999/08/11 21:01:33 keil * new PCI codefix * @@ -42,7 +48,7 @@ #include extern const char *CardType[]; -const char *niccy_revision = "$Revision: 1.8 $"; +const char *niccy_revision = "$Revision: 1.10 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -228,12 +234,13 @@ static void niccy_reset(struct IsdnCardState *cs) { - int val, nval; - - val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - nval = val | PCI_IRQ_ENABLE; - outl(nval, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + if (cs->subtyp == NICCY_PCI) { + int val; + val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + val |= PCI_IRQ_ENABLE; + outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + } inithscxisac(cs, 3); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.3.99-pre5/linux/drivers/isdn/isdn_common.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/isdn_common.c Thu Apr 13 09:03:03 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.100 2000/03/03 16:37:11 kai Exp $ +/* $Id: isdn_common.c,v 1.101 2000/04/07 14:50:34 calle Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.101 2000/04/07 14:50:34 calle + * Bugfix: on my system 2.3.99-pre3 Dual PII 350, unload of module isdn.o + * hangs if vfree is called with interrupt disabled. After moving + * restore_flags in front of vfree it doesn't hang. + * * Revision 1.100 2000/03/03 16:37:11 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS @@ -453,7 +458,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.100 $"; +static char *isdn_revision = "$Revision: 1.101 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -2780,12 +2785,14 @@ } if (devfs_unregister_chrdev(ISDN_MAJOR, "isdn") != 0) { printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n"); + restore_flags(flags); } else { isdn_cleanup_devfs(); del_timer(&dev->timer); + restore_flags(flags); + /* call vfree with interrupts enabled, else it will hang */ vfree(dev); printk(KERN_NOTICE "ISDN-subsystem unloaded\n"); } - restore_flags(flags); } #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.3.99-pre5/linux/drivers/isdn/isdn_net.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/isdn_net.c Thu Apr 13 09:03:03 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.122 2000/03/20 22:37:46 detabc Exp $ +/* $Id: isdn_net.c,v 1.125 2000/04/05 21:25:55 detabc Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.125 2000/04/05 21:25:55 detabc + * add leased-line support to abc-stuff + * + * Revision 1.124 2000/04/03 21:07:22 detabc + * change write_super handling for abc-stuff + * + * Revision 1.123 2000/04/03 19:14:36 kai + * fix "isdn BUG at isdn_net.c:1440!" + * * Revision 1.122 2000/03/20 22:37:46 detabc * modify abc-extension to work together with the new LL. * remove abc frame-counter (is obsolete now). @@ -647,7 +656,7 @@ int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); -char *isdn_net_revision = "$Revision: 1.122 $"; +char *isdn_net_revision = "$Revision: 1.125 $"; /* * Code for raw-networking over ISDN @@ -1437,12 +1446,16 @@ void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb) { if (in_interrupt()) { - printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + // we can't grab the lock from irq context, + // so we just queue the packet + skb_queue_tail(&lp->super_tx_queue, skb); + queue_task(&lp->tqueue, &tq_immediate); return; } spin_lock_bh(&lp->xmit_lock); - if (!isdn_net_lp_busy(lp)) { + if (!isdn_net_lp_busy(lp)) + { isdn_net_writebuf_skb(lp, skb); } else { skb_queue_tail(&lp->super_tx_queue, skb); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.3.99-pre5/linux/drivers/net/3c509.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/net/3c509.c Tue Apr 25 16:53:13 2000 @@ -168,7 +168,7 @@ }; #endif -#ifdef CONFIG_ISAPNP +#ifdef __ISAPNP__ struct el3_isapnp_adapters_struct { unsigned short vendor, function; char *name; @@ -187,7 +187,7 @@ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0} }; #endif /* CONFIG_ISAPNP */ -#if defined(CONFIG_ISAPNP) || defined(MODULE) +#if defined(__ISAPNP__) || defined(MODULE) static int nopnp = 0; #endif @@ -198,7 +198,7 @@ u16 phys_addr[3]; static int current_tag = 0; int mca_slot = -1; -#ifdef CONFIG_ISAPNP +#ifdef __ISAPNP__ static int pnp_cards = 0; #endif @@ -294,7 +294,7 @@ } #endif -#ifdef CONFIG_ISAPNP +#ifdef __ISAPNP__ if (nopnp == 1) goto no_pnp; @@ -376,7 +376,7 @@ phys_addr[i] = htons(id_read_eeprom(i)); } -#ifdef CONFIG_ISAPNP +#ifdef __ISAPNP__ if (nopnp == 0) { /* The ISA PnP 3c509 cards respond to the ID sequence. This check is needed in order not to register them twice. */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/3c515.c linux/drivers/net/3c515.c --- v2.3.99-pre5/linux/drivers/net/3c515.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/net/3c515.c Tue Apr 25 16:53:13 2000 @@ -46,7 +46,6 @@ #define RX_RING_SIZE 16 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ -#include #include #include #include @@ -353,7 +352,7 @@ { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -#ifdef CONFIG_ISAPNP +#ifdef __ISAPNP__ struct corkscrew_isapnp_adapters_struct { unsigned short vendor, function; char *name; @@ -445,7 +444,7 @@ static int ioaddr; static int pnp_cards = 0; -#ifdef CONFIG_ISAPNP +#ifdef __ISAPNP__ if(nopnp == 1) goto no_pnp; for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) { @@ -503,12 +502,12 @@ } } no_pnp: -#endif /* not CONFIG_ISAPNP */ +#endif /* not __ISAPNP__ */ /* Check all locations on the ISA bus -- evil! */ for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { int irq; -#ifdef CONFIG_ISAPNP +#ifdef __ISAPNP__ /* Make sure this was not already picked up by isapnp */ if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue; if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.3.99-pre5/linux/drivers/net/3c59x.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/net/3c59x.c Mon Apr 24 15:17:06 2000 @@ -1,6 +1,6 @@ -/* 3c59x.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */ +/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */ /* - Written 1996-1998 by Donald Becker. + Written 1996-1999 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. @@ -13,14 +13,51 @@ Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - Version history: - 0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates - 0.99H+lk1.0 - Jeff Garzik - Remove compatibility defines for kernel versions < 2.2.x. - Update for new 2.3.x module interface - + Linux Kernel Additions: + + LK1.1.2 (March 19, 2000) + * New PCI interface (jgarzik) + +*/ + +/* + 22Apr00, Andrew Morton + - Merged with 3c575_cb.c + - Don't set RxComplete in boomerang interrupt enable reg + - spinlock in vortex_timer to protect mdio functions + - disable local interrupts around call to vortex_interrupt in + vortex_tx_timeout() (So vortex_interrupt can use spin_lock()) + - Select window 3 in vortex_timer()'s write to Wn3_MAC_Ctrl + - In vortex_start_xmit(), move the lock to _after_ we've altered + vp->cur_tx and vp->tx_full. This defeats the race between + vortex_start_xmit() and vortex_interrupt which was identified + by Bogdan Costescu. + - Merged back support for six new cards from various sources + - Set vortex_have_pci if pci_module_init returns zero (fixes cardbus + insertion oops) + - Tell it that 3c905C has NWAY for 100bT autoneg + - Fix handling of SetStatusEnd in 'Too much work..' code, as + per 2.3.99's 3c575_cb (Dave Hinds). + - Split ISR into two for vortex & boomerang + - Fix MOD_INC/DEC races + - Handle resource allocation failures. + - Fix 3CCFE575CT LED polarity + - Make tx_interrupt_mitigation the default + - Add extra TxReset to vortex_up() to fix 575_cb hotplug initialisation probs. + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. +*/ + +/* + * FIXME: This driver _could_ support MTU changing, but doesn't. See Don's hamaci.c implementation + * as well as other drivers + * + * NOTE: If you make 'vortex_debug' a constant (#define vortex_debug 0) the driver shrinks by 2k + * due to dead code elimination. There will be some performance benefits from this due to + * elimination of all the tests and reduced cache footprint. */ +static char *version = +"3c59x.c:v0.99L+LK1.1.2+AKPM 24 Apr 2000 Donald Becker and others http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -29,7 +66,13 @@ /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */ static const int mtu = 1500; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; +static int max_interrupt_work = 32; + +/* Allow aggregation of Tx interrupts. Saves CPU load at the cost + * of possible Tx stalls if the system is blocking interrupts + * somewhere else. Undefine this to disable. + */ +#define tx_interrupt_mitigation 1 /* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */ #define vortex_debug debug @@ -52,8 +95,12 @@ #define RX_RING_SIZE 32 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -#include -#include +#ifndef __OPTIMIZE__ +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + #include #include #include @@ -61,11 +108,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -80,14 +127,8 @@ #include -#define PCI_SUPPORT_VER2 -#define DEV_FREE_SKB(skb) dev_kfree_skb(skb); - -static char *version __initdata = -"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; - MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); +MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); @@ -111,6 +152,10 @@ code size of a per-interface flag is not worthwhile. */ static char mii_preamble_required = 0; +#define PFX "3c59x: " + + + /* Theory of Operation @@ -168,7 +213,6 @@ passing the full-sized skbuff to the queue layer for all frames vs. the copying cost of copying a frame to a correctly-sized skbuff. - IIIC. Synchronization The driver runs as two independent, single-threaded flows of control. One is the send-packet routine, which enforces single-threaded use by the @@ -195,68 +239,163 @@ PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; -struct pci_id_info { + +enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, + EEPROM_230=8, /* AKPM: Uses 0x230 as the base bitmpas for EEPROM reads */ + HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; + + +enum vortex_chips { + CH_3C590 = 0, + CH_3C592, + CH_3C597, + CH_3C595_1, + CH_3C595_2, + + CH_3C595_3, + CH_VORTEX, + CH_3C900_1, + CH_3C900_2, + CH_3C900_3, + + CH_3C900_4, + CH_3C900_5, + CH_3C900B_FL, + CH_3C905_1, + CH_3C905_2, + + CH_3C905B_1, + CH_3C905B_2, + CH_3C905B_FX, + CH_3C905C, + CH_3C980, + + CH_3CSOHO100_TX, + CH_3C555, + CH_3C575_1, + CH_3CCFE575, + CH_3CCFE575CT, + + CH_3CCFE656, + CH_3CCFEM656, + CH_3C450, +}; + + +/* note: this array directly indexed by above enums, and MUST + * be kept in sync with both the enums above, and the PCI device + * table below + */ +static struct vortex_chip_info { const char *name; - u16 vendor_id, device_id, device_id_mask, flags; - int drv_flags, io_size; - struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt); -}; - -enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, - HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; -static struct net_device *vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq, int dev_id, int card_idx); - -static struct pci_id_info pci_tbl[] = { - {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3c595 Vortex 100baseTx", 0x10B7, 0x5950, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3c595 Vortex 100baseT4", 0x10B7, 0x5951, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3c595 Vortex 100base-MII", 0x10B7, 0x5952, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3Com Vortex", 0x10B7, 0x5900, 0xff00, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, - {"3c900 Boomerang 10baseT", 0x10B7, 0x9000, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, - {"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, - {"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3c905 Boomerang 100baseT4", 0x10B7, 0x9051, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3c905B Cyclone 100baseTx", 0x10B7, 0x9055, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, - {"3c905B Cyclone 10/100/BNC", 0x10B7, 0x9058, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, - {"3c905B-FX Cyclone 100baseFx", 0x10B7, 0x905A, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c905C Tornado", 0x10B7, 0x9200, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3cSOHO100-TX Hurricane", 0x10B7, 0x7646, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c555 Laptop Hurricane", 0x10B7, 0x5055, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, - 128, vortex_probe1}, - {"3CCFE656 Cyclone CardBus", 0x10B7, 0x6560, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, - 128, vortex_probe1}, - {"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3Com Boomerang (unknown version)", 0x10B7, 0x9000, 0xff00, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, + int flags; + int drv_flags; + int io_size; +} vortex_info_tbl[] = { + {"3c590 Vortex 10Mbps", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3c592 EISA 10mbps Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3c597 EISA Fast Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3c595 Vortex 100baseTx", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3c595 Vortex 100baseT4", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + + {"3c595 Vortex 100base-MII", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, +#define EISA_TBL_OFFSET 6 /* Offset of this entry for vortex_eisa_init */ + {"3Com Vortex", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {"3c900 Boomerang 10baseT", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {"3c900 Boomerang 10Mbps Combo", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + + {"3c900 Cyclone 10Mbps Combo", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */ + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c900B-FL Cyclone 10base-FL", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c905 Boomerang 100baseTx", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + {"3c905 Boomerang 100baseT4", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + + {"3c905B Cyclone 100baseTx", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + {"3c905B Cyclone 10/100/BNC", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + {"3c905B-FX Cyclone 100baseFx", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c905C Tornado", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + {"3c980 Cyclone", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + + {"3cSOHO100-TX Hurricane", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c555 Laptop Hurricane", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c575 Boomerang CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 64, }, + {"3CCFE575 Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + {"3CCFE575CT Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + + {"3CCFE656 Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + {"3CCFEM656 Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + {"3c450 Cyclone/unknown", /* AKPM: from Don's 0.99N */ + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + {0,}, /* 0 terminated list. */ +}; + + +static struct pci_device_id vortex_pci_tbl[] __devinitdata = { + { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 }, + { 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 }, + { 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 }, + { 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 }, + { 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 }, + + { 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 }, + { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX }, + { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 }, + { 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 }, + { 0x10B7, 0x9004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 }, + + { 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_4 }, + { 0x10B7, 0x9006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_5 }, + { 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL }, + { 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 }, + { 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 }, + + { 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 }, + { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 }, + { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX }, + { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C }, + { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 }, + + { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX }, + { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 }, + { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 }, + { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, + { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, + + { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 }, + { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 }, + { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, {0,}, /* 0 terminated list. */ }; +MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); + /* Operational definitions. These are not used by other compilation units and thus are not @@ -392,7 +531,7 @@ }; /* Chip features we care about in vp->capabilities, read from the EEPROM. */ -enum ChipCaps { CapBusMaster=0x20 }; +enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 }; struct vortex_private { /* The Rx and Tx rings should be quad-word-aligned. */ @@ -403,36 +542,38 @@ /* The addresses of transmit- and receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; - struct net_device *next_module; + struct net_device *next_module; /* NULL if PCI device */ unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; - struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ - dma_addr_t tx_skb_dma; /* Allocated DMA address for bus master ctrl DMA. */ + struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ + dma_addr_t tx_skb_dma; /* Allocated DMA address for bus master ctrl DMA. */ /* PCI configuration space information. */ - u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */ + struct pci_dev *pdev; char *cb_fn_base; /* CardBus function status addr space. */ int chip_id; - struct pci_dev *pdev; /* Device for DMA mapping */ /* The remainder are related to chip state, mostly media selection. */ - unsigned long in_interrupt; - struct timer_list timer; /* Media selection timer. */ - int options; /* User-settable misc. driver options. */ - unsigned int media_override:3, /* Passed-in media type. */ + struct timer_list timer; /* Media selection timer. */ + int options; /* User-settable misc. driver options. */ + unsigned int media_override:4, /* Passed-in media type. */ default_media:4, /* Read from the EEPROM/Wn3_Config. */ full_duplex:1, force_fd:1, autoselect:1, - bus_master:1, /* Vortex can only do a fragment bus-m. */ + bus_master:1, /* Vortex can only do a fragment bus-m. */ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ - hw_csums:1, /* Has hardware checksums. */ - tx_full:1; + hw_csums:1, /* Has hardware checksums. */ + tx_full:1, + open:1; u16 status_enable; u16 intr_enable; u16 available_media; /* From Wn3_Options. */ u16 capabilities, info1, info2; /* Various, from EEPROM. */ u16 advertising; /* NWay media advertisement */ unsigned char phys[2]; /* MII device addresses. */ + u16 deferred; /* Resend these interrupts when we + * bale from the ISR */ + spinlock_t lock; }; /* The action to take with a media selection timer tick. @@ -446,9 +587,9 @@ static struct media_table { char *name; unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ - mask:8, /* The transceiver-present bit in Wn3_Config.*/ - next:8; /* The media type to try next. */ - int wait; /* Time before we check media status. */ + mask:8, /* The transceiver-present bit in Wn3_Config.*/ + next:8; /* The media type to try next. */ + int wait; /* Time before we check media status. */ } media_tbl[] = { { "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10}, { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10}, @@ -463,329 +604,245 @@ { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -#ifndef CARDBUS -static int vortex_scan(struct pci_id_info pci_tbl[]); -#endif +static int vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq, + int chip_idx, int card_idx); +static void vortex_up(struct net_device *dev); +static void vortex_down(struct net_device *dev); static int vortex_open(struct net_device *dev); static void mdio_sync(long ioaddr, int bits); static int mdio_read(long ioaddr, int phy_id, int location); static void mdio_write(long ioaddr, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); -static void vortex_tx_timeout(struct net_device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev); static int vortex_rx(struct net_device *dev); static int boomerang_rx(struct net_device *dev); static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int vortex_close(struct net_device *dev); static void update_stats(long ioaddr, struct net_device *dev); static struct net_device_stats *vortex_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void vortex_tx_timeout(struct net_device *dev); +static void acpi_set_WOL(struct net_device *dev); - /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Option count limit only -- unlimited interfaces are supported. */ #define MAX_UNITS 8 static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -/* A list of all installed Vortex devices, for removing the driver module. */ -static struct net_device *root_vortex_dev = NULL; -#ifndef CARDBUS + +/* A list of all installed Vortex EISA devices, for removing the driver module. */ +static struct net_device *root_vortex_eisa_dev = NULL; + /* Variables to work-around the Compaq PCI BIOS32 problem. */ static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900; -#endif -#ifdef CARDBUS +static int vortex_cards_found = 0; -#include - -static dev_node_t *vortex_attach(dev_locator_t *loc) +static void vortex_suspend (struct pci_dev *pdev) { - u16 dev_id, vendor_id; - u32 io; - u8 irq; - struct net_device *dev; - struct pci_dev *pdev; - int chip_idx; + struct net_device *dev = pdev->driver_data; - if (loc->bus != LOC_PCI) return NULL; - pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); - if (!pdev) return NULL; - io = pdev->resource[0].start; - irq = pdev->irq; - vendor_id = pdev->vendor; - dev_id = pdev->device; - printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n", - pdev->bus->number, pdev->devfn, dev_id); - io &= ~3; - if (io == 0 || irq == 0) { - printk(KERN_ERR "The 3Com CardBus Ethernet interface was not " - "assigned an %s.\n" KERN_ERR " It will not be activated.\n", - io == 0 ? "I/O address" : "IRQ"); - return NULL; - } - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor_id == pci_tbl[chip_idx].vendor_id - && (dev_id & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */ - printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in " - "vortex_attach().\n", vendor_id, dev_id); - return NULL; - } - dev = vortex_probe1(pdev, io, irq, chip_idx, MAX_UNITS+1); - if (dev) { - dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); - strcpy(node->dev_name, dev->name); - node->major = node->minor = 0; - node->next = NULL; - MOD_INC_USE_COUNT; - return node; - } - return NULL; -} + printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name); -static void vortex_detach(dev_node_t *node) -{ - struct net_device **devp, **next; - printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name); - for (devp = &root_vortex_dev; *devp; devp = next) { - next = &((struct vortex_private *)(*devp)->priv)->next_module; - if (strcmp((*devp)->name, node->dev_name) == 0) break; - } - if (*devp) { - struct net_device *dev = *devp; - struct vortex_private *vp = dev->priv; - if (dev->flags & IFF_UP) - vortex_close(dev); - dev->flags &= ~(IFF_UP|IFF_RUNNING); - unregister_netdev(dev); - if (vp->cb_fn_base) iounmap(vp->cb_fn_base); - kfree(dev); - *devp = *next; - kfree(vp); - kfree(node); - MOD_DEC_USE_COUNT; + if (dev && dev->priv) { + struct vortex_private *vp = (struct vortex_private *)dev->priv; + if (vp->open) { + netif_device_detach(dev); + vortex_down(dev); + } } } -struct driver_operations vortex_ops = { - "3c575_cb", vortex_attach, NULL, NULL, vortex_detach -}; - -#endif /* Cardbus support */ +static void vortex_resume (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name); -static int __init vortex_init_module (void) -{ - if (vortex_debug) - printk(KERN_INFO "%s", version); -#ifdef CARDBUS - register_driver(&vortex_ops); - return 0; -#else - return vortex_scan(pci_tbl); -#endif + if (dev && dev->priv) { + struct vortex_private *vp = (struct vortex_private *)dev->priv; + if (vp->open) { + vortex_up(dev); + netif_device_attach(dev); + } + } } -#ifndef CARDBUS -static int vortex_scan(struct pci_id_info pci_tbl[]) +/* returns count found (>= 0), or negative on error */ +static int __init vortex_eisa_init (void) { - int cards_found = 0; - struct net_device *dev; - - /* Allow an EISA-only driver. */ -#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI)) - /* Ideally we would detect all cards in slot order. That would - be best done a central PCI probe dispatch, which wouldn't work - well with the current structure. So instead we detect 3Com cards - in slot order. */ - if (pci_present()) { - static int pci_index = 0; - unsigned char pci_bus, pci_device_fn; - - for (;pci_index < 0xff; pci_index++) { - u16 vendor, device, pci_command, new_command, pwr_cmd; - int chip_idx, irq; - long ioaddr; - struct pci_dev *pdev; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - break; - pdev = pci_find_slot (pci_bus, pci_device_fn); - if (!pdev) continue; - vendor = pdev->vendor; - device = pdev->device; - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pci_tbl[chip_idx].vendor_id - && (device & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ - continue; - - { - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->resource[0].start; - irq = pdev->irq; - } - - /* Power-up the card. */ - pci_read_config_word(pdev, 0xe0, &pwr_cmd); - - if (pwr_cmd & 0x3) { - /* Save the ioaddr and IRQ info! */ - printk(KERN_INFO " A 3Com network adapter is powered down!" - " Setting the power state %4.4x->%4.4x.\n", - pwr_cmd, pwr_cmd & ~3); - pci_write_config_word(pdev, 0xe0, pwr_cmd & ~3); - printk(KERN_INFO " Setting the IRQ to %d, IOADDR to %#lx.\n", - irq, ioaddr); - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); - pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, ioaddr); - } - - if (ioaddr == 0) { - printk(KERN_WARNING " A 3Com network adapter has been found, " - "however it has not been assigned an I/O address.\n" - " You may need to power-cycle the machine for this " - "device to work!\n"); - continue; - } - - if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) - continue; - - /* Activate the card. */ - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + long ioaddr; + int rc; + int orig_cards_found = vortex_cards_found; - new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the device " - "at %d/%d. Updating PCI command %4.4x->%4.4x.\n", - pci_bus, pci_device_fn, pci_command, new_command); - pci_write_config_word(pdev, PCI_COMMAND, new_command); - } + /* Now check all slots of the EISA bus. */ + if (!EISA_bus) + return 0; - dev = vortex_probe1(pdev, ioaddr, irq, - chip_idx, cards_found); + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { + int device_id; - if (dev) { - /* Get and check the latency values. On the 3c590 series - the latency timer must be set to the maximum value to avoid - data corruption that occurs when the timer expires during - a transfer -- a bug in the Vortex chip only. */ - u8 pci_latency; - u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32; - - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < new_latency) { - printk(KERN_INFO "%s: Overriding PCI latency" - " timer (CFLT) setting of %d, new value is %d.\n", - dev->name, pci_latency, new_latency); - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency); - } - dev = 0; - cards_found++; - } - } - } -#endif /* NO_PCI */ + if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL) + continue; - /* Now check all slots of the EISA bus. */ - if (EISA_bus) { - static long ioaddr = 0x1000; - for ( ; ioaddr < 0x9000; ioaddr += 0x1000) { - int device_id; - if (check_region(ioaddr, VORTEX_TOTAL_SIZE)) - continue; - /* Check the standard EISA ID register for an encoded '3Com'. */ - if (inw(ioaddr + 0xC80) != 0x6d50) - continue; - /* Check for a product that we support, 3c59{2,7} any rev. */ - device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); - if ((device_id & 0xFF00) != 0x5900) - continue; - vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12, - 4, cards_found); - cards_found++; - } + /* Check the standard EISA ID register for an encoded '3Com'. */ + if (inw(ioaddr + 0xC80) != 0x6d50) { + release_region (ioaddr, VORTEX_TOTAL_SIZE); + continue; + } + + /* Check for a product that we support, 3c59{2,7} any rev. */ + device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); + if ((device_id & 0xFF00) != 0x5900) { + release_region (ioaddr, VORTEX_TOTAL_SIZE); + continue; + } + + rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12, + EISA_TBL_OFFSET, + vortex_cards_found); + if (rc == 0) + vortex_cards_found++; + else + release_region (ioaddr, VORTEX_TOTAL_SIZE); } /* Special code to work-around the Compaq PCI BIOS32 problem. */ if (compaq_ioaddr) { vortex_probe1(NULL, compaq_ioaddr, compaq_irq, - compaq_device_id, cards_found++); - dev = 0; + compaq_device_id, vortex_cards_found++); } - return cards_found ? 0 : -ENODEV; + return vortex_cards_found - orig_cards_found; +} + + +/* returns count (>= 0), or negative on error */ +static int __devinit vortex_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int rc; + + rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq, + ent->driver_data, vortex_cards_found); + if (rc == 0) + vortex_cards_found++; + return rc; } -#endif /* ! Cardbus */ /* - * vortex_probe1 - initialize one vortex board, after probing - * has located one during bus scan. + * Start up the PCI device which is described by *pdev. + * Return 0 on success. * - * NOTE: pdev==NULL is a valid condition, indicating - * non-PCI (generally EISA) bus device + * NOTE: pdev can be NULL, for the case of an EISA driver */ -static struct net_device *vortex_probe1(struct pci_dev *pdev, - long ioaddr, int irq, - int chip_idx, int card_idx) +static int __devinit vortex_probe1(struct pci_dev *pdev, + long ioaddr, int irq, + int chip_idx, int card_idx) { struct vortex_private *vp; int option; unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; struct net_device *dev; + static int printed_version = 0; + int retval; - dev = init_etherdev(NULL, 0); + if (!printed_version) { + printk (KERN_INFO "%s", version); + printed_version = 1; + } - printk(KERN_INFO "%s: 3Com %s at 0x%lx, ", - dev->name, pci_tbl[chip_idx].name, ioaddr); + dev = init_etherdev(NULL, sizeof(*vp)); + if (!dev) { + printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); + retval = -ENOMEM; + goto out; + } + + printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ", + dev->name, + pdev ? "PCI" : "EISA", + vortex_info_tbl[chip_idx].name, + ioaddr); + /* private struct aligned and zeroed by init_etherdev */ + vp = dev->priv; dev->base_addr = ioaddr; dev->irq = irq; dev->mtu = mtu; - /* Make certain the descriptor lists are aligned. */ - vp = kmalloc(sizeof(*vp), GFP_KERNEL); - - memset(vp, 0, sizeof(*vp)); - dev->priv = vp; - - vp->next_module = root_vortex_dev; - root_vortex_dev = dev; + /* module list only for EISA devices */ + if (pdev == NULL) { + vp->next_module = root_vortex_eisa_dev; + root_vortex_eisa_dev = dev; + } + + /* PCI-only startup logic */ + if (pdev) { + /* EISA resources already marked, so only PCI needs to do this here */ + if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size, + dev->name)) { + printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n", + dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr); + retval = -EBUSY; + goto free_dev; + } + + /* wake up and enable device */ + if (pci_enable_device (pdev)) { + printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name); + retval = -EIO; + goto free_region; + } + + /* enable bus-mastering if necessary */ + if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER) + pci_set_master (pdev); + } + vp->lock = SPIN_LOCK_UNLOCKED; vp->chip_id = chip_idx; - vp->pci_bus = pdev == NULL ? 0 : pdev->bus->number; - vp->pci_devfn = pdev == NULL ? 0 : pdev->devfn; vp->pdev = pdev; /* Makes sure rings are at least 16 byte aligned. */ vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE, &vp->rx_ring_dma); + if (vp->rx_ring == 0) + { + retval = -ENOMEM; + goto free_region; + } + vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE); vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE; + /* if we are a PCI driver, we store info in pdev->driver_data + * instead of a module list */ + if (pdev) + pdev->driver_data = dev; + /* The lower four bits are the media type. */ if (dev->mem_start) + { /* + * AKPM: ewww.. The 'options' param is passed in as the third arg to the + * LILO 'ether=' argument for non-modular use + */ option = dev->mem_start; + } else if (card_idx < MAX_UNITS) option = options[card_idx]; else option = -1; if (option >= 0) { - vp->media_override = ((option & 7) == 2) ? 0 : option & 7; - vp->full_duplex = (option & 8) ? 1 : 0; + vp->media_override = ((option & 7) == 2) ? 0 : option & 15; + vp->full_duplex = (option & 0x200) ? 1 : 0; vp->bus_master = (option & 16) ? 1 : 0; } else { vp->media_override = 7; @@ -797,23 +854,21 @@ vp->force_fd = vp->full_duplex; vp->options = option; - /* Read the station address from the EEPROM. */ EL3WINDOW(0); - for (i = 0; i < 0x40; i++) { - int timer; -#ifdef CARDBUS - outw(0x230 + i, ioaddr + Wn0EepromCmd); -#else - outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); -#endif - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 10; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) - break; + { + int base = (vortex_info_tbl[chip_idx].drv_flags & EEPROM_230) ? 0x230 : EEPROM_Read; + for (i = 0; i < 0x40; i++) { + int timer; + outw(base + i, ioaddr + Wn0EepromCmd); + /* Pause for at least 162 us. for the read to take place. */ + for (timer = 10; timer >= 0; timer--) { + udelay(162); + if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) + break; + } + eeprom[i] = inw(ioaddr + Wn0EepromData); } - eeprom[i] = inw(ioaddr + Wn0EepromData); } for (i = 0; i < 0x18; i++) checksum ^= eeprom[i]; @@ -825,11 +880,14 @@ } if (checksum != 0x00) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); - for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); for (i = 0; i < 6; i++) printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); + EL3WINDOW(2); + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + i); + #ifdef __sparc__ printk(", IRQ %s\n", __irq_itoa(dev->irq)); #else @@ -840,15 +898,19 @@ dev->irq); #endif - if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { + if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { u32 fn_st_addr; /* Cardbus function status space */ - fn_st_addr = pdev == NULL ? 0 : pdev->resource[2].start; + fn_st_addr = pci_resource_start (pdev, 2); if (fn_st_addr) - vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128); - printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee" - " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base); - EL3WINDOW(2); - outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions); + vp->cb_fn_base = ioremap(fn_st_addr, 128); + printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p\n", + dev->name, fn_st_addr, vp->cb_fn_base); +#if 0 /* AKPM */ + if (vortex_pci_tbl[vp->chip_id].device != 0x5257) { + EL3WINDOW(2); + outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions); + } +#endif } /* Extract our information from the EEPROM data. */ @@ -857,10 +919,13 @@ vp->capabilities = eeprom[16]; if (vp->info1 & 0x8000) + { vp->full_duplex = 1; + printk(KERN_INFO "Full duplex capable\n"); + } { - char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + static char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; union wn3_config config; EL3WINDOW(3); vp->available_media = inw(ioaddr + Wn3_Options); @@ -919,38 +984,65 @@ } } + if (vp->capabilities & CapPwrMgmt) + acpi_set_WOL(dev); + if (vp->capabilities & CapBusMaster) { vp->full_bus_master_tx = 1; printk(KERN_INFO" Enabling bus-master transmits and %s receives.\n", (vp->info2 & 1) ? "early" : "whole-frame" ); vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2; + vp->bus_master = 0; /* AKPM: vortex only */ } - /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); - /* The 3c59x-specific entries in the device structure. */ dev->open = &vortex_open; dev->hard_start_xmit = &vortex_start_xmit; - dev->tx_timeout = &vortex_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; dev->stop = &vortex_close; dev->get_stats = &vortex_get_stats; dev->do_ioctl = &vortex_ioctl; dev->set_multicast_list = &set_rx_mode; + dev->tx_timeout = &vortex_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + return 0; - return dev; +free_region: + release_region (ioaddr, vortex_info_tbl[chip_idx].io_size); +free_dev: + kfree (dev); + printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); +out: + return retval; } - -static int -vortex_open(struct net_device *dev) +static void wait_for_completion(struct net_device *dev, int cmd) +{ + int i = 2000; + + outw(cmd, dev->base_addr + EL3_CMD); + while (--i > 0) + { + if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) + return; + } + printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n", + dev->name, cmd, inw(dev->base_addr + EL3_STATUS)); +} + +static void +vortex_up(struct net_device *dev) { long ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; union wn3_config config; - int i; + int i, device_id; + if (vp->pdev) + device_id = vp->pdev->device; + else + device_id = 0x5900; /* EISA */ + /* Before initializing select the active media port. */ EL3WINDOW(3); config.i = inl(ioaddr + Wn3_Config); @@ -961,15 +1053,24 @@ dev->name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; - } else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) { - dev->if_port = XCVR_NWAY; } else if (vp->autoselect) { - /* Find first available media type, starting with 100baseTx. */ - dev->if_port = XCVR_100baseTx; - while (! (vp->available_media & media_tbl[dev->if_port].mask)) - dev->if_port = media_tbl[dev->if_port].next; - } else + if (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY) { + printk(KERN_INFO "%s: using NWAY autonegotiation\n", dev->name); + dev->if_port = XCVR_NWAY; + } else { + /* Find first available media type, starting with 100baseTx. */ + dev->if_port = XCVR_100baseTx; + while (! (vp->available_media & media_tbl[dev->if_port].mask)) + dev->if_port = media_tbl[dev->if_port].next; + printk(KERN_INFO "%s: first avaialble mdeia type: %s\n", + dev->name, + media_tbl[dev->if_port].name); + } + } else { dev->if_port = vp->default_media; + printk(KERN_INFO "%s: using default media %s\n", + dev->name, media_tbl[dev->if_port].name); + } init_timer(&vp->timer); vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); @@ -983,7 +1084,13 @@ vp->full_duplex = vp->force_fd; config.u.xcvr = dev->if_port; - outl(config.i, ioaddr + Wn3_Config); + if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY)) + { + if (vortex_debug > 6) + printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", + config.i); + outl(config.i, ioaddr + Wn3_Config); + } if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { int mii_reg1, mii_reg5; @@ -1008,31 +1115,18 @@ (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n", + printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n", dev->name, config.i); } - outw(TxReset, ioaddr + EL3_CMD); - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - - outw(RxReset, ioaddr + EL3_CMD); - /* Wait a few ticks for the RxReset command to complete. */ - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, TxReset); + wait_for_completion(dev, RxReset); outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); - /* Use the now-standard shared IRQ implementation. */ - if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) { - return -EAGAIN; - } - if (vortex_debug > 1) { EL3WINDOW(4); - printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n", + printk(KERN_DEBUG "%s: vortex_up() irq %d media status %4.4x.\n", dev->name, dev->irq, inw(ioaddr + Wn4_Media)); } @@ -1042,6 +1136,19 @@ outb(dev->dev_addr[i], ioaddr + i); for (; i < 12; i+=2) outw(0, ioaddr + i); + if (vp->cb_fn_base) { + u_short n = inw(ioaddr + Wn2_ResetOptions); +#if 0 /* AKPM: This is done in vortex_probe1, and seems to be wrong anyway... */ + /* Inverted LED polarity */ + if (device_id != 0x5257) + n |= 0x0010; +#endif + /* Inverted polarity of MII power bit */ + if ((device_id == 0x6560) || (device_id == 0x6562) || + (device_id == 0x5257)) + n |= 0x4000; + outw(n, ioaddr + Wn2_ResetOptions); + } if (dev->if_port == XCVR_10base2) /* Start the thinnet transceiver. We should really wait 50ms...*/ @@ -1073,39 +1180,24 @@ /* Initialize the RxEarly register as recommended. */ outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD); outl(0x0020, ioaddr + PktStatus); - if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name); - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1)); - vp->rx_ring[i].status = 0; /* Clear complete bit. */ - vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG); - skb = dev_alloc_skb(PKT_BUF_SZ); - vp->rx_skbuff[i] = skb; - if (skb == NULL) - break; /* Bad news! */ - skb->dev = dev; /* Mark as being used by this device. */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); - } - /* Wrap the ring. */ - vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma); - outl(vp->rx_ring_dma, ioaddr + UpListPtr); + outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); } if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ dev->hard_start_xmit = &boomerang_start_xmit; vp->cur_tx = vp->dirty_tx = 0; outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ - /* Clear the Tx ring. */ + /* Clear the Rx, Tx rings. */ + for (i = 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_open, too */ + vp->rx_ring[i].status = 0; for (i = 0; i < TX_RING_SIZE; i++) vp->tx_skbuff[i] = 0; outl(0, ioaddr + DownListPtr); } - /* Set reciever mode: presumably accept b-case and phys addr only. */ + /* Set receiver mode: presumably accept b-case and phys addr only. */ set_rx_mode(dev); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - vp->in_interrupt = 0; + netif_start_queue (dev); outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ @@ -1114,7 +1206,8 @@ (vp->full_bus_master_tx ? DownComplete : TxAvailable) | (vp->full_bus_master_rx ? UpComplete : RxComplete) | (vp->bus_master ? DMADone : 0); - vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete | + vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | + (vp->full_bus_master_rx ? 0 : RxComplete) | StatsFull | HostError | TxComplete | IntReq | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete; outw(vp->status_enable, ioaddr + EL3_CMD); @@ -1125,11 +1218,55 @@ if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ writel(0x8000, vp->cb_fn_base + 4); - netif_start_queue(dev); + /* AKPM: unjam the 3CCFE575CT */ + wait_for_completion(dev, TxReset); + outw(TxEnable, ioaddr + EL3_CMD); +} + +static int +vortex_open(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + int i; + int retval; MOD_INC_USE_COUNT; + /* Use the now-standard shared IRQ implementation. */ + if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, + SA_SHIRQ, dev->name, dev)) { + retval = -EAGAIN; + goto out; + } + + if (vp->full_bus_master_rx) { /* Boomerang bus master. */ + if (vortex_debug > 2) + printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name); + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb; + vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1])); + vp->rx_ring[i].status = 0; /* Clear complete bit. */ + vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG); + skb = dev_alloc_skb(PKT_BUF_SZ); + vp->rx_skbuff[i] = skb; + if (skb == NULL) + break; /* Bad news! */ + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail)); + } + /* Wrap the ring. */ + vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0])); + } + + vortex_up(dev); + vp->open = 1; return 0; +out: + MOD_DEC_USE_COUNT; + if (vortex_debug > 1) + printk(KERN_ERR PFX "vortex_open() fails: returning %d\n", retval); + return retval; } static void vortex_timer(unsigned long data) @@ -1137,7 +1274,7 @@ struct net_device *dev = (struct net_device *)data; struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - int next_tick = 0; + int next_tick = 60*HZ; int ok = 0; int media_status, mii_status, old_window; @@ -1152,43 +1289,50 @@ switch (dev->if_port) { case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx: if (media_status & Media_LnkBeat) { - ok = 1; - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); + ok = 1; + if (vortex_debug > 1) + printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n", + dev->name, media_tbl[dev->if_port].name, media_status); } else if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n", + printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); break; - case XCVR_MII: case XCVR_NWAY: - mii_status = mdio_read(ioaddr, vp->phys[0], 1); - ok = 1; - if (debug > 1) - printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", - dev->name, mii_status); - if (mii_status & 0x0004) { - int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); - if (! vp->force_fd && mii_reg5 != 0xffff) { - int duplex = (mii_reg5&0x0100) || - (mii_reg5 & 0x01C0) == 0x0040; - if (vp->full_duplex != duplex) { - vp->full_duplex = duplex; - printk(KERN_INFO "%s: Setting %s-duplex based on MII " - "#%d link partner capability of %4.4x.\n", - dev->name, vp->full_duplex ? "full" : "half", - vp->phys[0], mii_reg5); - /* Set the full-duplex bit. */ - outb((vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), - ioaddr + Wn3_MAC_Ctrl); - } - next_tick = 60*HZ; - } - } - break; + case XCVR_MII: case XCVR_NWAY: + { + unsigned long flags; + spin_lock_irqsave(&vp->lock, flags); /* AKPM: protect mdio state */ + + mii_status = mdio_read(ioaddr, vp->phys[0], 1); + ok = 1; + if (vortex_debug > 1) + printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", + dev->name, mii_status); + if (mii_status & 0x0004) { + int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); + if (! vp->force_fd && mii_reg5 != 0xffff) { + int duplex = (mii_reg5&0x0100) || + (mii_reg5 & 0x01C0) == 0x0040; + if (vp->full_duplex != duplex) { + vp->full_duplex = duplex; + printk(KERN_INFO "%s: Setting %s-duplex based on MII " + "#%d link partner capability of %4.4x.\n", + dev->name, vp->full_duplex ? "full" : "half", + vp->phys[0], mii_reg5); + /* Set the full-duplex bit. */ + EL3WINDOW(3); /* AKPM: this was missing from 2.3.99 3c59x.c! */ + outb((vp->full_duplex ? 0x20 : 0) | + (dev->mtu > 1500 ? 0x40 : 0), + ioaddr + Wn3_MAC_Ctrl); + } + next_tick = 60*HZ; + } + } + spin_unlock_irqrestore(&vp->lock, flags); + } + break; default: /* Other media types handled by Tx timeouts. */ if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n", + printk(KERN_DEBUG "%s: Media %s has no indication, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); ok = 1; } @@ -1205,11 +1349,11 @@ "%s port.\n", dev->name, media_tbl[dev->if_port].name); } else { - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media selection failed, now trying " - "%s port.\n", - dev->name, media_tbl[dev->if_port].name); - next_tick = media_tbl[dev->if_port].wait; + if (vortex_debug > 1) + printk(KERN_DEBUG "%s: Media selection failed, now trying " + "%s port.\n", + dev->name, media_tbl[dev->if_port].name); + next_tick = media_tbl[dev->if_port].wait; } outw((media_status & ~(Media_10TP|Media_SQE)) | media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); @@ -1225,14 +1369,14 @@ EL3WINDOW(old_window); enable_irq(dev->irq); - if (vortex_debug > 2) + if (vortex_debug > 1) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); - if (next_tick) { - vp->timer.expires = RUN_AT(next_tick); - add_timer(&vp->timer); - } + vp->timer.expires = RUN_AT(next_tick); + add_timer(&vp->timer); + if (vp->deferred) + outw(FakeIntr, ioaddr + EL3_CMD); return; } @@ -1240,7 +1384,6 @@ { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - int j; printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", dev->name, inb(ioaddr + TxStatus), @@ -1253,30 +1396,41 @@ printk(KERN_ERR "%s: Interrupt posted but not delivered --" " IRQ blocked by another device?\n", dev->name); /* Bad idea here.. but we might as well handle a few events. */ - vortex_interrupt(dev->irq, dev, 0); + { + /* + * AKPM: block interrupts because vortex_interrupt + * does a bare spin_lock() + */ + unsigned long flags; + local_irq_save(flags); + if (vp->full_bus_master_tx) + boomerang_interrupt(dev->irq, dev, 0); + else + vortex_interrupt(dev->irq, dev, 0); + local_irq_restore(flags); + } } - outw(TxReset, ioaddr + EL3_CMD); - for (j = 200; j >= 0 ; j--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; -#if ! defined(final_version) - if (vp->full_bus_master_tx) { - int i; - printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d " - "current %d.\n", - vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx); - printk(KERN_DEBUG " Transmit list %8.8x vs. %p.\n", - inl(ioaddr + DownListPtr), - &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); - for (i = 0; i < TX_RING_SIZE; i++) { - printk(KERN_DEBUG " %d: @%p length %8.8x status %8.8x\n", i, - &vp->tx_ring[i], - le32_to_cpu(vp->tx_ring[i].length), - le32_to_cpu(vp->tx_ring[i].status)); + if (vortex_debug > 0) { + if (vp->full_bus_master_tx) { + int i; + printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d " + "current %d.\n", + vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx); + printk(KERN_DEBUG " Transmit list %8.8x vs. %p.\n", + inl(ioaddr + DownListPtr), + &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); + for (i = 0; i < TX_RING_SIZE; i++) { + printk(KERN_DEBUG " %d: @%p length %8.8x status %8.8x\n", i, + &vp->tx_ring[i], + le32_to_cpu(vp->tx_ring[i].length), + le32_to_cpu(vp->tx_ring[i].status)); + } } } -#endif + + wait_for_completion(dev, TxReset); + vp->stats.tx_errors++; if (vp->full_bus_master_tx) { if (vortex_debug > 0) @@ -1287,8 +1441,10 @@ ioaddr + DownListPtr); if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) { vp->tx_full = 0; - netif_wake_queue(dev); + netif_start_queue (dev); } + if (vp->tx_full) + netif_stop_queue (dev); outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); outw(DownUnstall, ioaddr + EL3_CMD); } else @@ -1312,7 +1468,9 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; int do_tx_reset = 0; - int i; + + if (vortex_debug > 2) + printk(KERN_DEBUG "%s: vortex_error(), status=0x%x\n", dev->name, status); if (status & TxComplete) { /* Really "TxError" for us. */ unsigned char tx_status = inb(ioaddr + TxStatus); @@ -1358,25 +1516,18 @@ u16 fifo_diag; EL3WINDOW(4); fifo_diag = inw(ioaddr + Wn4_FIFODiag); - if (vortex_debug > 0) - printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n", - dev->name, fifo_diag); + printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n", + dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { - outw(TotalReset | 0xff, ioaddr + EL3_CMD); - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - /* Re-enable the receiver. */ - outw(RxEnable, ioaddr + EL3_CMD); - outw(TxEnable, ioaddr + EL3_CMD); + /* In this case, blow the card away */ + vortex_down(dev); + wait_for_completion(dev, TotalReset | 0xff); + vortex_up(dev); } else if (fifo_diag & 0x0400) do_tx_reset = 1; if (fifo_diag & 0x3000) { - outw(RxReset, ioaddr + EL3_CMD); - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, RxReset); /* Set the Rx filter to the current state. */ set_rx_mode(dev); outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ @@ -1384,40 +1535,37 @@ } } if (do_tx_reset) { - int j; - outw(TxReset, ioaddr + EL3_CMD); - for (j = 200; j >= 0 ; j--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); } } - static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - netif_stop_queue(dev); - + netif_stop_queue (dev); + /* Put out the doubleword header... */ outl(skb->len, ioaddr + TX_FIFO); if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ int len = (skb->len + 3) & ~3; - outl(vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE), ioaddr + Wn7_MasterAddr); + outl( vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE), + ioaddr + Wn7_MasterAddr); outw(len, ioaddr + Wn7_MasterLen); vp->tx_skb = skb; outw(StartDMADown, ioaddr + EL3_CMD); + /* dev->tbusy will be cleared at the DMADone interrupt. */ } else { /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - DEV_FREE_SKB(skb); + dev_kfree_skb (skb); if (inw(ioaddr + TxFree) > 1536) { - netif_wake_queue(dev); + netif_start_queue (dev); } else /* Interrupt us when the FIFO has room for max-sized packet. */ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); @@ -1438,18 +1586,13 @@ if (tx_status & 0x04) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; if (tx_status & 0x30) { - int j; - outw(TxReset, ioaddr + EL3_CMD); - for (j = 200; j >= 0 ; j--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, TxReset); } outw(TxEnable, ioaddr + EL3_CMD); } outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } - vp->stats.tx_bytes += skb->len; return 0; } @@ -1459,21 +1602,22 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - netif_stop_queue(dev); + if (vortex_debug > 6) + printk(KERN_DEBUG "boomerang_start_xmit()\n"); - if (1) { + netif_stop_queue (dev); + { /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; unsigned long flags; - int i; if (vortex_debug > 3) printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", dev->name, vp->cur_tx); if (vp->tx_full) { - if (vortex_debug >0) + if (vortex_debug > 0) printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n", dev->name); return 1; @@ -1484,37 +1628,40 @@ vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); - /* Hmm... And some poor people try to use it on SMP machines 8) */ - save_flags(flags); - cli(); - outw(DownStall, ioaddr + EL3_CMD); + spin_lock_irqsave(&vp->lock, flags); /* Wait for the stall to complete. */ - for (i = 600; i >= 0 ; i--) - if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) - break; + wait_for_completion(dev, DownStall); prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)); if (inl(ioaddr + DownListPtr) == 0) { outl(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); queued_packet++; } - outw(DownUnstall, ioaddr + EL3_CMD); - restore_flags(flags); vp->cur_tx++; if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) { vp->tx_full = 1; + netif_stop_queue (dev); } else { /* Clear previous interrupt enable. */ +#if defined(tx_interrupt_mitigation) prev_entry->status &= cpu_to_le32(~TxIntrUploaded); - netif_wake_queue(dev); +#endif + netif_start_queue (dev); } + outw(DownUnstall, ioaddr + EL3_CMD); + spin_unlock_irqrestore(&vp->lock, flags); dev->trans_start = jiffies; - vp->stats.tx_bytes += skb->len; return 0; } } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ + +/* + * This is the ISR for the vortex series chips. + * full_bus_master_tx == 0 && full_bus_master_rx == 0 + */ + static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; @@ -1523,10 +1670,23 @@ int latency, status; int work_done = max_interrupt_work; + spin_lock(&vp->lock); + ioaddr = dev->base_addr; latency = inb(ioaddr + Timer); status = inw(ioaddr + EL3_STATUS); + if (vortex_debug > 6) + printk("AKPM: vortex_interrupt. status=0x%4x\n", status); + + if (status & IntReq) { + status |= vp->deferred; + vp->deferred = 0; + } + + if (status == 0xffff) /* AKPM: h/w no longer present (hotplug)? */ + goto handler_exit; + if (vortex_debug > 4) printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", dev->name, status, latency); @@ -1536,22 +1696,117 @@ dev->name, status); if (status & RxComplete) vortex_rx(dev); - if (status & UpComplete) { - outw(AckIntr | UpComplete, ioaddr + EL3_CMD); - boomerang_rx(dev); - } if (status & TxAvailable) { if (vortex_debug > 5) printk(KERN_DEBUG " TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue(dev); + netif_wake_queue (dev); + } + + if (status & DMADone) { + if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { + outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ + pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */ + if (inw(ioaddr + TxFree) > 1536) { + netif_wake_queue (dev); + } else { /* Interrupt when FIFO has room for max-sized packet. */ + outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); + netif_stop_queue (dev); /* AKPM: This is new */ + } + } + } + /* Check for all uncommon interrupts at once. */ + if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { + if (status == 0xffff) + break; + vortex_error(dev, status); + } + + if (--work_done < 0) { + printk(KERN_WARNING "%s: Too much work in interrupt, status " + "%4.4x.\n", dev->name, status); + /* Disable all pending interrupts. */ + do { + vp->deferred |= status; + outw(SetStatusEnb | (~vp->deferred & vp->status_enable), + ioaddr + EL3_CMD); + outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); + } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch); + /* The timer will reenable interrupts. */ + del_timer(&vp->timer); + vp->timer.expires = RUN_AT(1); + add_timer(&vp->timer); + break; + } + /* Acknowledge the IRQ. */ + outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); + if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ + writel(0x8000, vp->cb_fn_base + 4); + + } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); + + if (vortex_debug > 4) + printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", + dev->name, status); +handler_exit: + spin_unlock(&vp->lock); +} + +/* + * This is the ISR for the boomerang series chips. + * full_bus_master_tx == 1 && full_bus_master_rx == 1 + */ + +static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr; + int latency, status; + int work_done = max_interrupt_work; + + spin_lock(&vp->lock); + + ioaddr = dev->base_addr; + latency = inb(ioaddr + Timer); + status = inw(ioaddr + EL3_STATUS); + + if (vortex_debug > 6) + printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status); + + if (status & IntReq) { + status |= vp->deferred; + vp->deferred = 0; + } + + if (status == 0xffff) /* AKPM: h/w no longer present (hotplug)? */ + { + if (vortex_debug > 1) + printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n"); + goto handler_exit; + } + + if (vortex_debug > 4) + printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", + dev->name, status, latency); + do { + if (vortex_debug > 5) + printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", + dev->name, status); + if (status & UpComplete) { + outw(AckIntr | UpComplete, ioaddr + EL3_CMD); + if (vortex_debug > 5) + printk(KERN_DEBUG "boomerang_interrupt->boomerang_rx\n"); + boomerang_rx(dev); } if (status & DownComplete) { unsigned int dirty_tx = vp->dirty_tx; + outw(AckIntr | DownComplete, ioaddr + EL3_CMD); while (vp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % TX_RING_SIZE; if (inl(ioaddr + DownListPtr) == @@ -1560,31 +1815,27 @@ if (vp->tx_skbuff[entry]) { struct sk_buff *skb = vp->tx_skbuff[entry]; - pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(vp->tx_skbuff[entry]); + pci_unmap_single(vp->pdev, + le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); vp->tx_skbuff[entry] = 0; + } else { + printk(KERN_DEBUG "boomerang_interrupt: no skb!\n"); } /* vp->stats.tx_packets++; Counted below. */ dirty_tx++; } vp->dirty_tx = dirty_tx; - outw(AckIntr | DownComplete, ioaddr + EL3_CMD); if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { - vp->tx_full= 0; - netif_wake_queue(dev); - } - } - if (status & DMADone) { - if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { - outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */ - if (inw(ioaddr + TxFree) > 1536) { - netif_wake_queue(dev); - } else /* Interrupt when FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); + if (vortex_debug > 6) + printk(KERN_DEBUG "boomerang_interrupt: clearing tx_full\n"); + vp->tx_full = 0; + netif_wake_queue (dev); } } + if (vp->tx_full) + netif_stop_queue (dev); + /* Check for all uncommon interrupts at once. */ if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { if (status == 0xffff) @@ -1593,19 +1844,20 @@ } if (--work_done < 0) { - if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) { - /* Just ack these and return. */ - outw(AckIntr | UpComplete | DownComplete, ioaddr + EL3_CMD); - } else { - printk(KERN_WARNING "%s: Too much work in interrupt, status " - "%4.4x. Temporarily disabling functions (%4.4x).\n", - dev->name, status, SetStatusEnb | ((~status) & 0x7FE)); - /* Disable all pending interrupts. */ - outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD); - outw(AckIntr | 0x7FF, ioaddr + EL3_CMD); - /* The timer will reenable interrupts. */ - break; - } + printk(KERN_WARNING "%s: Too much work in interrupt, status " + "%4.4x.\n", dev->name, status); + /* Disable all pending interrupts. */ + do { + vp->deferred |= status; + outw(SetStatusEnb | (~vp->deferred & vp->status_enable), + ioaddr + EL3_CMD); + outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); + } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch); + /* The timer will reenable interrupts. */ + del_timer(&vp->timer); + vp->timer.expires = RUN_AT(1); + add_timer(&vp->timer); + break; } /* Acknowledge the IRQ. */ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); @@ -1617,8 +1869,8 @@ if (vortex_debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name, status); - - return; +handler_exit: + spin_unlock(&vp->lock); } static int vortex_rx(struct net_device *dev) @@ -1629,7 +1881,7 @@ short rx_status; if (vortex_debug > 5) - printk(KERN_DEBUG" In rx_packet(), status %4.4x, rx_status %4.4x.\n", + printk(KERN_DEBUG "vortex_rx(): status %4.4x, rx_status %4.4x.\n", inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); while ((rx_status = inw(ioaddr + RxStatus)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ @@ -1674,22 +1926,17 @@ netif_rx(skb); dev->last_rx = jiffies; vp->stats.rx_packets++; - vp->stats.rx_bytes += skb->len; /* Wait a limited time to go to next packet. */ for (i = 200; i >= 0; i--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; continue; - } else if (vortex_debug) + } else if (vortex_debug > 0) printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of " "size %d.\n", dev->name, pkt_len); } - outw(RxDiscard, ioaddr + EL3_CMD); vp->stats.rx_dropped++; - /* Wait a limited time to skip this packet. */ - for (i = 200; i >= 0; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, RxDiscard); } return 0; @@ -1705,7 +1952,7 @@ int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx; if (vortex_debug > 5) - printk(KERN_DEBUG " In boomerang_rx(), status %4.4x, rx_status " + printk(KERN_DEBUG "boomerang_rx(): status %4.4x, rx_status " "%4.4x.\n", inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){ @@ -1787,22 +2034,13 @@ return 0; } -static int -vortex_close(struct net_device *dev) +static void +vortex_down(struct net_device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - int i; - - netif_stop_queue(dev); - if (vortex_debug > 1) { - printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n", - dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); - printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d" - " tx_queued %d Rx pre-checksummed %d.\n", - dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits); - } + netif_stop_queue (dev); del_timer(&vp->timer); @@ -1817,34 +2055,60 @@ /* Turn off thinnet power. Green! */ outw(StopCoax, ioaddr + EL3_CMD); - free_irq(dev->irq, dev); - outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); update_stats(ioaddr, dev); - if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ + if (vp->full_bus_master_rx) outl(0, ioaddr + UpListPtr); + if (vp->full_bus_master_tx) + outl(0, ioaddr + DownListPtr); + + if (vp->capabilities & CapPwrMgmt) + acpi_set_WOL(dev); +} + +static int +vortex_close(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + if (netif_device_present(dev)) + vortex_down(dev); + + if (vortex_debug > 1) { + printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n", + dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); + printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d" + " tx_queued %d Rx pre-checksummed %d.\n", + dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits); + } + + free_irq(dev->irq, dev); + + if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ for (i = 0; i < RX_RING_SIZE; i++) if (vp->rx_skbuff[i]) { - pci_unmap_single(vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - DEV_FREE_SKB(vp->rx_skbuff[i]); + pci_unmap_single( vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + dev_kfree_skb(vp->rx_skbuff[i]); vp->rx_skbuff[i] = 0; } } if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ - outl(0, ioaddr + DownListPtr); for (i = 0; i < TX_RING_SIZE; i++) if (vp->tx_skbuff[i]) { struct sk_buff *skb = vp->tx_skbuff[i]; pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE); - DEV_FREE_SKB(skb); + dev_kfree_skb(skb); vp->tx_skbuff[i] = 0; } } MOD_DEC_USE_COUNT; - + vp->open = 0; return 0; } @@ -1853,11 +2117,10 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned long flags; - if (netif_running(dev)) { - save_flags(flags); - cli(); + if (netif_device_present(dev)) { /* AKPM: Used to be netif_running */ + spin_lock_irqsave (&vp->lock, flags); update_stats(dev->base_addr, dev); - restore_flags(flags); + spin_unlock_irqrestore (&vp->lock, flags); } return &vp->stats; } @@ -1872,7 +2135,10 @@ static void update_stats(long ioaddr, struct net_device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; + int old_window = inw(ioaddr + EL3_CMD); + if (old_window == 0xffff) /* Chip suspended or ejected. */ + return; /* Unlike the 3c5x9 we need not turn off stats updates while reading. */ /* Switch to the stats window, and read everything. */ EL3WINDOW(6); @@ -1889,14 +2155,21 @@ /* Don't bother with register 9, an extension of registers 6&7. If we do use the 6&7 values the atomic update assumption above is invalid. */ - inw(ioaddr + 10); /* Total Rx and Tx octets. */ - inw(ioaddr + 12); + vp->stats.rx_bytes += inw(ioaddr + 10); + vp->stats.tx_bytes += inw(ioaddr + 12); /* New: On the Vortex we must also clear the BadSSD counter. */ EL3WINDOW(4); inb(ioaddr + 12); + { + u8 up = inb(ioaddr + 13); + vp->stats.rx_bytes += (up & 0x0f) << 16; + vp->stats.tx_bytes += (up & 0xf0) << 12; + } + /* We change back to window 7 (not 1) with the Vortex. */ - EL3WINDOW(7); + /* AKPM: the previous comment is obsolete - we switch back to the old window */ + EL3WINDOW(old_window >> 13); return; } @@ -1906,6 +2179,10 @@ long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; int phy = vp->phys[0] & 0x1f; + int retval; + unsigned long flags; + + spin_lock_irqsave(&vp->lock, flags); switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ @@ -1913,16 +2190,24 @@ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ EL3WINDOW(4); data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); - return 0; + retval = 0; + break; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - EL3WINDOW(4); - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); - return 0; + if (!capable(CAP_NET_ADMIN)) { + retval = -EPERM; + } else { + EL3WINDOW(4); + mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + retval = 0; + } + break; default: - return -EOPNOTSUPP; + retval = -EOPNOTSUPP; + break; } + + spin_unlock_irqrestore(&vp->lock, flags); + return retval; } /* Pre-Cyclone chips have no documented multicast filter, so the only @@ -1945,7 +2230,6 @@ outw(new_mode, ioaddr + EL3_CMD); } - /* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet @@ -2004,11 +2288,7 @@ outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } -#if 0 - return (retval>>1) & 0x1ffff; -#else return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff; -#endif } static void mdio_write(long ioaddr, int phy_id, int location, int value) @@ -2038,42 +2318,131 @@ return; } + +/* ACPI: Advanced Configuration and Power Interface. */ +/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */ +static void acpi_set_WOL(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; + + /* AKPM: This kills the 905 */ + if (vortex_debug > 0) { + printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n"); + } + return; + + /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ + EL3WINDOW(7); + outw(2, ioaddr + 0x0c); + /* The RxFilter must accept the WOL frames. */ + outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); + outw(RxEnable, ioaddr + EL3_CMD); + /* Change the power state to D3; RxEnable doesn't take effect. */ + pci_write_config_word(vp->pdev, 0xe0, 0x8103); +} -static void __exit vortex_cleanup_module (void) +static void __devexit vortex_remove_one (struct pci_dev *pdev) { - struct net_device *next_dev; + struct net_device *dev = pdev->driver_data; + struct vortex_private *vp; -#ifdef CARDBUS - unregister_driver(&vortex_ops); -#endif + if (!dev) + return; + + vp = (void *)(dev->priv); /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_vortex_dev) { - struct vortex_private *vp=(void *)(root_vortex_dev->priv); - next_dev = vp->next_module; - unregister_netdev(root_vortex_dev); - outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD); - release_region(root_vortex_dev->base_addr, - pci_tbl[vp->chip_id].io_size); - kfree(root_vortex_dev); - pci_free_consistent(vp->pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE - + sizeof(struct boom_tx_desc) * TX_RING_SIZE - + 15, vp->rx_ring, vp->rx_ring_dma); - kfree(vp); - root_vortex_dev = next_dev; + unregister_netdev(dev); + outw(TotalReset, dev->base_addr + EL3_CMD); + release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size); + kfree(dev); +} + + +static struct pci_driver vortex_driver = { + name: "3c575_cb", + probe: vortex_init_one, + remove: vortex_remove_one, + suspend: vortex_suspend, + resume: vortex_resume, + id_table: vortex_pci_tbl, +}; + + +static int vortex_have_pci = 0; +static int vortex_have_eisa = 0; + + +static int __init vortex_init (void) +{ + int rc; + + MOD_INC_USE_COUNT; + + rc = pci_module_init (&vortex_driver); + if (rc < 0) + goto out; + + if (rc >= 0) /* AKPM: had "> 0" */ + vortex_have_pci = 1; + + rc = vortex_eisa_init (); + if (rc < 0) + goto out; + + if (rc > 0) + vortex_have_eisa = 1; + +out: + MOD_DEC_USE_COUNT; + return rc; +} + + +static void __exit vortex_eisa_cleanup (void) +{ + struct net_device *dev, *tmp; + struct vortex_private *vp; + long ioaddr; + + dev = root_vortex_eisa_dev; + + while (dev) { + vp = dev->priv; + ioaddr = dev->base_addr; + + unregister_netdev (dev); + outw (TotalReset, ioaddr + EL3_CMD); + release_region (ioaddr, VORTEX_TOTAL_SIZE); + + tmp = dev; + dev = vp->next_module; + + kfree (tmp); } } -module_init(vortex_init_module); -module_exit(vortex_cleanup_module); + +static void __exit vortex_cleanup (void) +{ + if (vortex_have_pci) + pci_unregister_driver (&vortex_driver); + if (vortex_have_eisa) + vortex_eisa_cleanup (); +} +module_init(vortex_init); +module_exit(vortex_cleanup); + + + /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c" - * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/" + * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.3.99-pre5/linux/drivers/net/8139too.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/8139too.c Fri Apr 14 09:37:10 2000 @@ -439,7 +439,7 @@ u8 tmp8; int rc; u32 pio_start, pio_end, pio_flags, pio_len; - u32 mmio_start, mmio_end, mmio_flags, mmio_len; + unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; DPRINTK ("ENTER\n"); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/82596.c linux/drivers/net/82596.c --- v2.3.99-pre5/linux/drivers/net/82596.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/82596.c Tue Apr 25 17:38:33 2000 @@ -40,7 +40,7 @@ */ -static const char *version = "82596.c:v1.0 15/07/98\n"; +static const char *version = "82596.c $Revision: 1.4 $\n"; #include #include @@ -63,6 +63,32 @@ #include #include #include +#include + +/* DEBUG flags + */ + +#define DEB_INIT 0x0001 +#define DEB_PROBE 0x0002 +#define DEB_SERIOUS 0x0004 +#define DEB_ERRORS 0x0008 +#define DEB_MULTI 0x0010 +#define DEB_TDR 0x0020 +#define DEB_OPEN 0x0040 +#define DEB_RESET 0x0080 +#define DEB_ADDCMD 0x0100 +#define DEB_STATUS 0x0200 +#define DEB_STARTTX 0x0400 +#define DEB_RXADDR 0x0800 +#define DEB_TXADDR 0x1000 +#define DEB_RXFRAME 0x2000 +#define DEB_INTS 0x4000 +#define DEB_STRUCT 0x8000 +#define DEB_ANY 0xffff + + +#define DEB(x,y) if (i596_debug & (x)) y + #if defined(CONFIG_MVME16x_NET) || defined(CONFIG_MVME16x_NET_MODULE) #define ENABLE_MVME16x_NET @@ -97,13 +123,13 @@ #define ISCP_BUSY 0x00010000 #define MACH_IS_APRICOT 0 #else -#define WSWAPrfd(x) x -#define WSWAPrbd(x) ((struct i596_rbd *)(x)) -#define WSWAPiscp(x) ((struct i596_iscp *)(x)) -#define WSWAPscb(x) ((struct i596_scb *)(x)) -#define WSWAPcmd(x) x -#define WSWAPtbd(x) x -#define WSWAPchar(x) ((char *)(x)) +#define WSWAPrfd(x) ((struct i596_rfd *)(x)) +#define WSWAPrbd(x) ((struct i596_rbd *)(x)) +#define WSWAPiscp(x) ((struct i596_iscp *)(x)) +#define WSWAPscb(x) ((struct i596_scb *)(x)) +#define WSWAPcmd(x) ((struct i596_cmd *)(x)) +#define WSWAPtbd(x) ((struct i596_tbd *)(x)) +#define WSWAPchar(x) ((char *)(x)) #define ISCP_BUSY 0x0001 #define MACH_IS_APRICOT 1 #endif @@ -119,13 +145,12 @@ #define PORT_ALTSCP 0x02 /* alternate SCB address */ #define PORT_ALTDUMP 0x03 /* Alternate DUMP address */ -#define I82596_DEBUG 1 +static int i596_debug = (DEB_SERIOUS|DEB_PROBE); + +MODULE_AUTHOR("Richard Hirst"); +MODULE_DESCRIPTION("i82596 driver"); +MODULE_PARM(i596_debug, "i"); -#ifdef I82596_DEBUG -int i596_debug = I82596_DEBUG; -#else -int i596_debug = 1; -#endif /* Copy frames shorter than rx_copybreak, otherwise pass on up in * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha). @@ -137,7 +162,7 @@ #define I596_TOTAL_SIZE 17 -#define I596_NULL -1 +#define I596_NULL ((void *)0xffffffff) #define CMD_EOL 0x8000 /* The last command of the list, stop. */ #define CMD_SUSP 0x4000 /* Suspend after doing cmd. */ @@ -164,7 +189,8 @@ #define RX_SUSPEND 0x0030 #define RX_ABORT 0x0040 -#define TX_TIMEOUT 5 +#define TX_TIMEOUT 5 + struct i596_reg { unsigned short porthi; @@ -172,12 +198,6 @@ unsigned long ca; }; -struct i596_cmd { - unsigned short status; - unsigned short command; - struct i596_cmd *next; -}; - #define EOF 0x8000 #define SIZE_MASK 0x3fff @@ -188,6 +208,23 @@ char *data; }; +/* The command structure has two 'next' pointers; v_next is the address of + * the next command as seen by the CPU, b_next is the address of the next + * command as seen by the 82596. The b_next pointer, as used by the 82596 + * always references the status field of the next command, rather than the + * v_next field, because the 82596 is unaware of v_next. It may seem more + * logical to put v_next at the end of the structure, but we cannot do that + * because the 82596 expects other fields to be there, depending on command + * type. + */ + +struct i596_cmd { + struct i596_cmd *v_next; /* Address from CPUs viewpoint */ + unsigned short status; + unsigned short command; + struct i596_cmd *b_next; /* Address from i596 viewpoint */ +}; + struct tx_cmd { struct i596_cmd cmd; struct i596_tbd *tbd; @@ -196,26 +233,53 @@ struct sk_buff *skb; /* So we can free it after tx */ }; +struct tdr_cmd { + struct i596_cmd cmd; + unsigned short status; + unsigned short pad; +}; + +struct mc_cmd { + struct i596_cmd cmd; + short mc_cnt; + char mc_addrs[MAX_MC_CNT*6]; +}; + +struct sa_cmd { + struct i596_cmd cmd; + char eth_addr[8]; +}; + +struct cf_cmd { + struct i596_cmd cmd; + char i596_config[16]; +}; + struct i596_rfd { unsigned short stat; unsigned short cmd; - struct i596_rfd *next; + struct i596_rfd *b_next; /* Address from i596 viewpoint */ struct i596_rbd *rbd; unsigned short count; unsigned short size; + struct i596_rfd *v_next; /* Address from CPUs viewpoint */ + struct i596_rfd *v_prev; }; struct i596_rbd { unsigned short count; unsigned short zero1; - struct i596_rbd *next; - char *data; + struct i596_rbd *b_next; + unsigned char *b_data; /* Address from i596 viewpoint */ unsigned short size; unsigned short zero2; struct sk_buff *skb; + struct i596_rbd *v_next; + struct i596_rbd *b_addr; /* This rbd addr from i596 view */ + unsigned char *v_data; /* Address from CPUs viewpoint */ }; -#define TX_RING_SIZE 16 +#define TX_RING_SIZE 64 #define RX_RING_SIZE 16 struct i596_scb { @@ -248,17 +312,14 @@ volatile struct i596_scp scp; volatile struct i596_iscp iscp; volatile struct i596_scb scb; - struct i596_cmd set_add; - char eth_addr[8]; - struct i596_cmd set_conf; - char i596_config[16]; - struct i596_cmd tdr; - struct i596_cmd mc_cmd; /* Keep these three together!!! */ - short mc_cnt; /* Keep these three together!!! */ - char mc_addrs[MAX_MC_CNT*6]; /* Keep these three together!!! */ + struct sa_cmd sa_cmd; + struct cf_cmd cf_cmd; + struct tdr_cmd tdr_cmd; + struct mc_cmd mc_cmd; unsigned long stat; int last_restart __attribute__((aligned(4))); - struct i596_rfd *rx_tail; + struct i596_rfd *rfd_head; + struct i596_rbd *rbd_head; struct i596_cmd *cmd_tail; struct i596_cmd *cmd_head; int cmd_backlog; @@ -300,13 +361,13 @@ static struct net_device_stats *i596_get_stats(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); static void i596_tx_timeout (struct net_device *dev); -static void print_eth(char *); +static void print_eth(unsigned char *buf, char *str); static void set_multicast_list(struct net_device *dev); static int rx_ring_size = RX_RING_SIZE; static int ticks_limit = 25; -static int max_cmd_backlog = 16; - +static int max_cmd_backlog = TX_RING_SIZE-1; + static inline void CA(struct net_device *dev) { @@ -317,7 +378,9 @@ #endif #ifdef ENABLE_BVME6000_NET if (MACH_IS_BVME6000) { - volatile u32 i = *(volatile u32 *) (dev->base_addr); + volatile u32 i; + + i = *(volatile u32 *) (dev->base_addr); } #endif #ifdef ENABLE_APRICOT @@ -349,29 +412,88 @@ } +static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str) +{ + while (--delcnt && lp->iscp.stat) + udelay(10); + if (!delcnt) { + printk("%s: %s, status %4.4x, cmd %4.4x.\n", + dev->name, str, lp->scb.status, lp->scb.command); + return -1; + } + else + return 0; +} + + +static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str) +{ + while (--delcnt && lp->scb.command) + udelay(10); + if (!delcnt) { + printk("%s: %s, status %4.4x, cmd %4.4x.\n", + dev->name, str, lp->scb.status, lp->scb.command); + return -1; + } + else + return 0; +} + + +static void i596_display_data(struct net_device *dev) +{ + struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_cmd *cmd; + struct i596_rfd *rfd; + struct i596_rbd *rbd; + + printk("lp and scp at %p, .sysbus = %08lx, .iscp = %p\n", + &lp->scp, lp->scp.sysbus, lp->scp.iscp); + printk("iscp at %p, iscp.stat = %08lx, .scb = %p\n", + &lp->iscp, lp->iscp.stat, lp->iscp.scb); + printk("scb at %p, scb.status = %04x, .command = %04x," + " .cmd = %p, .rfd = %p\n", + &lp->scb, lp->scb.status, lp->scb.command, + lp->scb.cmd, lp->scb.rfd); + printk(" errors: crc %lx, align %lx, resource %lx," + " over %lx, rcvdt %lx, short %lx\n", + lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err, + lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err); + cmd = lp->cmd_head; + while (cmd != I596_NULL) { + printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n", + cmd, cmd->status, cmd->command, cmd->b_next); + cmd = cmd->v_next; + } + rfd = lp->rfd_head; + printk("rfd_head = %p\n", rfd); + do { + printk (" %p .stat %04x, .cmd %04x, b_next %p, rbd %p," + " count %04x\n", + rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd, + rfd->count); + rfd = rfd->v_next; + } while (rfd != lp->rfd_head); + rbd = lp->rbd_head; + printk("rbd_head = %p\n", rbd); + do { + printk(" %p .count %04x, b_next %p, b_data %p, size %04x\n", + rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size); + rbd = rbd->v_next; + } while (rbd != lp->rbd_head); +} + + #if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET) static void i596_error(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - struct i596_cmd *cmd; + volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; - struct i596_private *lp = (struct i596_private *) dev->priv; - printk("i596_error: lp = 0x%08x\n", (u32) lp); - printk("scp at %08x, .sysbus = %08x, .iscp = %08x\n", - (u32) & lp->scp, (u32) lp->scp.sysbus, (u32) lp->scp.iscp); - printk("iscp at %08x, .stat = %08x, .scb = %08x\n", - (u32) & lp->iscp, (u32) lp->iscp.stat, (u32) lp->iscp.scb); - printk("scb at %08x, .status = %04x, .command = %04x\n", - (u32) & lp->scb, lp->scb.status, lp->scb.command); - printk(" .cmd = %08x, .rfd = %08x\n", (u32) lp->scb.cmd, - (u32) lp->scb.rfd); - cmd = WSWAPcmd(lp->scb.cmd); - while (cmd && (u32) cmd < 0x1000000) { - printk("cmd at %08x, .status = %04x, .command = %04x, .next = %08x\n", - (u32) cmd, cmd->status, cmd->command, (u32) cmd->next); - cmd = WSWAPcmd(cmd->next); - } - while (1); + pcc2[0x28] = 1; + pcc2[0x2b] = 0x1d; + printk("%s: Error interrupt\n", dev->name); + i596_display_data(dev); } #endif @@ -382,9 +504,6 @@ struct i596_rfd *rfd; struct i596_rbd *rbd; - if (i596_debug > 1) - printk ("%s: init_rx_bufs %d.\n", dev->name, rx_ring_size); - /* First build the Receive Buffer Descriptor List */ for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) { @@ -393,28 +512,39 @@ if (skb == NULL) panic("82596: alloc_skb() failed"); skb->dev = dev; - rbd->next = WSWAPrbd(rbd+1); + rbd->v_next = rbd+1; + rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1)); + rbd->b_addr = WSWAPrbd(virt_to_bus(rbd)); rbd->skb = skb; - rbd->data = WSWAPchar(skb->tail); + rbd->v_data = skb->tail; + rbd->b_data = WSWAPchar(virt_to_bus(skb->tail)); rbd->size = PKT_BUF_SZ; #ifdef __mc68000__ cache_clear(virt_to_phys(skb->tail), PKT_BUF_SZ); #endif } - lp->rbds[rx_ring_size-1].next = WSWAPrbd(lp->rbds); + lp->rbd_head = lp->rbds; + rbd = lp->rbds + rx_ring_size - 1; + rbd->v_next = lp->rbds; + rbd->b_next = WSWAPrbd(virt_to_bus(lp->rbds)); /* Now build the Receive Frame Descriptor List */ for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) { - rfd->rbd = (struct i596_rbd *)I596_NULL; - rfd->next = WSWAPrfd(rfd+1); + rfd->rbd = I596_NULL; + rfd->v_next = rfd+1; + rfd->v_prev = rfd-1; + rfd->b_next = WSWAPrfd(virt_to_bus(rfd+1)); rfd->cmd = CMD_FLEX; } - lp->scb.rfd = WSWAPrfd(lp->rfds); - lp->rfds[0].rbd = WSWAPrbd(lp->rbds); + lp->rfd_head = lp->rfds; + lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds)); + rfd = lp->rfds; + rfd->rbd = lp->rbd_head; + rfd->v_prev = lp->rfds + rx_ring_size - 1; rfd = lp->rfds + rx_ring_size - 1; - lp->rx_tail = rfd; - rfd->next = WSWAPrfd(lp->rfds); + rfd->v_next = lp->rfds; + rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds)); rfd->cmd = CMD_EOL|CMD_FLEX; } @@ -431,15 +561,37 @@ } } -static inline void init_i596_mem(struct net_device *dev) + +static void rebuild_rx_bufs(struct net_device *dev) +{ + struct i596_private *lp = (struct i596_private *) dev->priv; + int i; + + /* Ensure rx frame/buffer descriptors are tidy */ + + for (i = 0; i < rx_ring_size; i++) { + lp->rfds[i].rbd = I596_NULL; + lp->rfds[i].cmd = CMD_FLEX; + } + lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX; + lp->rfd_head = lp->rfds; + lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds)); + lp->rbd_head = lp->rbds; + lp->rfds[0].rbd = WSWAPrbd(virt_to_bus(lp->rbds)); +} + + +static int init_i596_mem(struct net_device *dev) { struct i596_private *lp = (struct i596_private *) dev->priv; #if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) short ioaddr = dev->base_addr; #endif - int boguscnt = 100000; unsigned long flags; - int i; + + MPU_PORT(dev, PORT_RESET, 0); + + udelay(100); /* Wait 100us - seems to help */ #if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET) #ifdef ENABLE_MVME16x_NET @@ -448,12 +600,12 @@ /* Disable all ints for now */ pcc2[0x28] = 1; - pcc2[0x2a] = 0x40; + pcc2[0x2a] = 0x48; /* Following disables snooping. Snooping is not required * as we make appropriate use of non-cached pages for * shared data, and cache_push/cache_clear. */ - pcc2[0x2b] = 0x00; + pcc2[0x2b] = 0x08; } #endif #ifdef ENABLE_BVME6000_NET @@ -464,22 +616,22 @@ } #endif - MPU_PORT(dev, PORT_RESET, 0); - - udelay(100); /* Wait 100us - seems to help */ - /* change the scp address */ - MPU_PORT(dev, PORT_ALTSCP, &lp->scp); + MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus(&lp->scp)); #elif defined(ENABLE_APRICOT) - /* change the scp address */ - outw(0, ioaddr); - outw(0, ioaddr); - outb(4, ioaddr + 0xf); - outw(((((int) &lp->scp) & 0xffff) | 2), ioaddr); - outw((((int) &lp->scp) >> 16) & 0xffff, ioaddr); + { + u32 scp = virt_to_bus(&lp->scp); + + /* change the scp address */ + outw(0, ioaddr); + outw(0, ioaddr); + outb(4, ioaddr + 0xf); + outw(scp | 2, ioaddr); + outw(scp >> 16, ioaddr); + } #endif lp->last_cmd = jiffies; @@ -497,15 +649,14 @@ lp->scp.sysbus = 0x00440000; #endif - lp->scp.iscp = WSWAPiscp(&(lp->iscp)); - lp->iscp.scb = WSWAPscb(&(lp->scb)); + lp->scp.iscp = WSWAPiscp(virt_to_bus(&(lp->iscp))); + lp->iscp.scb = WSWAPscb(virt_to_bus(&(lp->scb))); lp->iscp.stat = ISCP_BUSY; lp->cmd_backlog = 0; - lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL; + lp->cmd_head = lp->scb.cmd = I596_NULL; - if (i596_debug > 1) - printk("%s: starting i82596.\n", dev->name); + DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name)); #if defined(ENABLE_APRICOT) (void) inb(ioaddr + 0x10); @@ -513,25 +664,12 @@ #endif CA(dev); - while (lp->iscp.stat) - if (--boguscnt == 0) { - printk("%s: i82596 initialization timed out with status %4.4x, cmd %4.4x.\n", - dev->name, lp->scb.status, lp->scb.command); - break; - } + if (wait_istat(dev,lp,1000,"initialization timed out")) + goto failed; + DEB(DEB_INIT,printk("%s: i82596 initialization successful\n", dev->name)); /* Ensure rx frame/buffer descriptors are tidy */ - /* Bit naff doing this here as well as in init_rx_bufs() */ - - for (i = 0; i < rx_ring_size; i++) { - lp->rfds[i].rbd = (struct i596_rbd *)I596_NULL; - lp->rfds[i].cmd = CMD_FLEX; - } - lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX; - lp->scb.rfd = WSWAPrfd(lp->rfds); - lp->rfds[0].rbd = WSWAPrbd(lp->rbds); - lp->rx_tail = lp->rfds + rx_ring_size - 1; - + rebuild_rx_bufs(dev); lp->scb.command = 0; #ifdef ENABLE_MVME16x_NET @@ -539,9 +677,8 @@ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000; /* Enable ints, etc. now */ - pcc2[0x2a] = 0x08; pcc2[0x2a] = 0x55; /* Edge sensitive */ - pcc2[0x2b] = 0x55; + pcc2[0x2b] = 0x15; } #endif #ifdef ENABLE_BVME6000_NET @@ -552,40 +689,40 @@ } #endif - memcpy(lp->i596_config, init_setup, 14); - lp->set_conf.command = CmdConfigure; - i596_add_cmd(dev, &lp->set_conf); - - memcpy(lp->eth_addr, dev->dev_addr, 6); - lp->set_add.command = CmdSASetup; - i596_add_cmd(dev, &lp->set_add); - lp->tdr.command = CmdTDR; - i596_add_cmd(dev, &lp->tdr); - - boguscnt = 200000; + DEB(DEB_INIT,printk("%s: queuing CmdConfigure\n", dev->name)); + memcpy(lp->cf_cmd.i596_config, init_setup, 14); + lp->cf_cmd.cmd.command = CmdConfigure; + i596_add_cmd(dev, &lp->cf_cmd.cmd); + + DEB(DEB_INIT,printk("%s: queuing CmdSASetup\n", dev->name)); + memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6); + lp->sa_cmd.cmd.command = CmdSASetup; + i596_add_cmd(dev, &lp->sa_cmd.cmd); + + DEB(DEB_INIT,printk("%s: queuing CmdTDR\n", dev->name)); + lp->tdr_cmd.cmd.command = CmdTDR; + i596_add_cmd(dev, &lp->tdr_cmd.cmd); spin_lock_irqsave (&lp->lock, flags); - while (lp->scb.command) - if (--boguscnt == 0) { - printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n", - dev->name, lp->scb.status, lp->scb.command); - break; - } + if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START")) + goto failed; + DEB(DEB_INIT,printk("%s: Issuing RX_START\n", dev->name)); lp->scb.command = RX_START; CA(dev); spin_unlock_irqrestore (&lp->lock, flags); - boguscnt = 2000; - while (lp->scb.command) - if (--boguscnt == 0) { - printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n", - lp->scb.status, lp->scb.command); - break; - } - return; + if (wait_cmd(dev,lp,1000,"RX_START not processed")) + goto failed; + DEB(DEB_INIT,printk("%s: Receive unit started OK\n", dev->name)); + return 0; + +failed: + printk("%s: Failed to initialise 82596\n", dev->name); + MPU_PORT(dev, PORT_RESET, 0); + return -1; } static inline int i596_rx(struct net_device *dev) @@ -595,23 +732,31 @@ struct i596_rbd *rbd; int frames = 0; - if (i596_debug > 3) - printk ("i596_rx()\n"); + DEB(DEB_RXFRAME,printk ("i596_rx(), rfd_head %p, rbd_head %p\n", + lp->rfd_head, lp->rbd_head)); - rfd = WSWAPrfd(lp->scb.rfd); /* Ref next frame to check */ + rfd = lp->rfd_head; /* Ref next frame to check */ - while ((rfd->stat) & STAT_C) { /* Loop while complete frames */ - rbd = WSWAPrbd(rfd->rbd); /* Ref associated buffer desc */ - - if (i596_debug >2) - print_eth(WSWAPchar(rbd->data)); - - if ((rfd->stat) & STAT_OK) { + while ((rfd->stat) & STAT_C) { /* Loop while complete frames */ + if (rfd->rbd == I596_NULL) + rbd = I596_NULL; + else if (rfd->rbd == lp->rbd_head->b_addr) + rbd = lp->rbd_head; + else { + printk("%s: rbd chain broken!\n", dev->name); + /* XXX Now what? */ + rbd = I596_NULL; + } + DEB(DEB_RXFRAME, printk(" rfd %p, rfd.rbd %p, rfd.stat %04x\n", + rfd, rfd->rbd, rfd->stat)); + + if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) { /* a good frame */ int pkt_len = rbd->count & 0x3fff; struct sk_buff *skb = rbd->skb; int rx_in_place = 0; + DEB(DEB_RXADDR,print_eth(rbd->v_data, "received")); frames++; /* Check if the packet is long enough to just accept @@ -620,7 +765,6 @@ if (pkt_len > rx_copybreak) { struct sk_buff *newskb; - char *temp; /* Get fresh skbuff to replace filled one. */ newskb = dev_alloc_skb(PKT_BUF_SZ); @@ -629,17 +773,12 @@ goto memory_squeeze; } /* Pass up the skb already on the Rx ring. */ - temp = skb_put(skb, pkt_len); - if (WSWAPchar(rbd->data) != temp) - printk(KERN_ERR "%s: Internal consistency error " - "-- the skbuff addresses do not match" - " in i596_rx: %p vs. %p / %p.\n", dev->name, - WSWAPchar(rbd->data), - skb->head, temp); + skb_put(skb, pkt_len); rx_in_place = 1; rbd->skb = newskb; newskb->dev = dev; - rbd->data = WSWAPchar(newskb->tail); + rbd->v_data = newskb->tail; + rbd->b_data = WSWAPchar(virt_to_bus(newskb->tail)); #ifdef __mc68000__ cache_clear(virt_to_phys(newskb->tail), PKT_BUF_SZ); #endif @@ -657,8 +796,7 @@ if (!rx_in_place) { /* 16 byte align the data fields */ skb_reserve(skb, 2); - memcpy(skb_put(skb,pkt_len), - WSWAPchar(rbd->data), pkt_len); + memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len); } skb->protocol=eth_type_trans(skb,dev); skb->len = pkt_len; @@ -672,6 +810,8 @@ } } else { + DEB(DEB_ERRORS, printk("%s: Error, rfd.stat = 0x%04x\n", + dev->name, rfd->stat)); lp->stats.rx_errors++; if ((rfd->stat) & 0x0001) lp->stats.collisions++; @@ -691,52 +831,42 @@ /* Clear the buffer descriptor count and EOF + F flags */ - if (rbd != (struct i596_rbd *)I596_NULL) - rbd->count=0; - else - printk("%s: Null rbd - oops!\n", dev->name); + if (rbd != I596_NULL && (rbd->count & 0x4000)) { + rbd->count = 0; + lp->rbd_head = rbd->v_next; + } /* Tidy the frame descriptor, marking it as end of list */ - rfd->rbd = (struct i596_rbd *)I596_NULL; + rfd->rbd = I596_NULL; rfd->stat = 0; rfd->cmd = CMD_EOL|CMD_FLEX; rfd->count = 0; /* Remove end-of-list from old end descriptor */ - lp->rx_tail->cmd = CMD_FLEX; - - /* Update last frame descriptor to reference the one just - * processed */ - - lp->rx_tail = rfd; + rfd->v_prev->cmd = CMD_FLEX; /* Update record of next frame descriptor to process */ - lp->scb.rfd = rfd->next; - rfd = WSWAPrfd(lp->scb.rfd); /* Next frame desc. to check */ + lp->scb.rfd = rfd->b_next; + lp->rfd_head = rfd->v_next; + rfd = lp->rfd_head; } - if (i596_debug > 3) - printk ("frames %d\n", frames); + DEB(DEB_RXFRAME,printk ("frames %d\n", frames)); return 0; } -static inline void i596_cleanup_cmd(struct i596_private *lp) +static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp) { struct i596_cmd *ptr; - int boguscnt = 1000; - if (i596_debug > 4) - printk("i596_cleanup_cmd\n"); - - while (lp->cmd_head != (struct i596_cmd *) I596_NULL) { + while (lp->cmd_head != I596_NULL) { ptr = lp->cmd_head; - - lp->cmd_head = WSWAPcmd(lp->cmd_head->next); + lp->cmd_head = ptr->v_next; lp->cmd_backlog--; switch ((ptr->command) & 0x7) { @@ -750,45 +880,28 @@ lp->stats.tx_errors++; lp->stats.tx_aborted_errors++; - ptr->next = (struct i596_cmd *) I596_NULL; + ptr->v_next = ptr->b_next = I596_NULL; tx_cmd->cmd.command = 0; /* Mark as free */ break; } - case CmdMulticastList: - { - ptr->next = (struct i596_cmd *) I596_NULL; - break; - } default: - ptr->next = (struct i596_cmd *) I596_NULL; + ptr->v_next = ptr->b_next = I596_NULL; } } - while (lp->scb.command) - if (--boguscnt == 0) { - printk("i596_cleanup_cmd timed out with status %4.4x, cmd %4.4x.\n", - lp->scb.status, lp->scb.command); - break; - } - lp->scb.cmd = WSWAPcmd(lp->cmd_head); + wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out"); + lp->scb.cmd = I596_NULL; } static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) { - int boguscnt = 1000; unsigned long flags; - if (i596_debug > 1) - printk("i596_reset\n"); + DEB(DEB_RESET,printk("i596_reset\n")); spin_lock_irqsave (&lp->lock, flags); - while (lp->scb.command) - if (--boguscnt == 0) { - printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n", - lp->scb.status, lp->scb.command); - break; - } + wait_cmd(dev,lp,100,"i596_reset timed out"); netif_stop_queue(dev); @@ -796,17 +909,10 @@ CA(dev); /* wait for shutdown */ - boguscnt = 4000; - - while (lp->scb.command) - if (--boguscnt == 0) { - printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n", - lp->scb.status, lp->scb.command); - break; - } + wait_cmd(dev,lp,1000,"i596_reset 2 timed out"); spin_unlock_irqrestore (&lp->lock, flags); - i596_cleanup_cmd(lp); + i596_cleanup_cmd(dev,lp); i596_rx(dev); netif_start_queue(dev); @@ -818,46 +924,28 @@ struct i596_private *lp = (struct i596_private *) dev->priv; int ioaddr = dev->base_addr; unsigned long flags; - int boguscnt = 1000; - if (i596_debug > 4) - printk("i596_add_cmd\n"); + DEB(DEB_ADDCMD,printk("i596_add_cmd\n")); cmd->status = 0; cmd->command |= (CMD_EOL | CMD_INTR); - cmd->next = (struct i596_cmd *) I596_NULL; + cmd->v_next = cmd->b_next = I596_NULL; spin_lock_irqsave (&lp->lock, flags); - /* - * RGH 300597: Looks to me like there could be a race condition - * here. Just because we havn't picked up all the command items - * yet, doesn't mean that the 82596 hasn't finished processing - * them. So, we may need to do a CUC_START anyway. - * Maybe not. If it interrupts saying the CU is idle when there - * is still something in the cmd queue, the int handler with restart - * the CU. - */ - - if (lp->cmd_head != (struct i596_cmd *) I596_NULL) { - lp->cmd_tail->next = WSWAPcmd(cmd); + if (lp->cmd_head != I596_NULL) { + lp->cmd_tail->v_next = cmd; + lp->cmd_tail->b_next = WSWAPcmd(virt_to_bus(&cmd->status)); } else { lp->cmd_head = cmd; - while (lp->scb.command) - if (--boguscnt == 0) { - printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n", - lp->scb.status, lp->scb.command); - break; - } - lp->scb.cmd = WSWAPcmd(cmd); + wait_cmd(dev,lp,100,"i596_add_cmd timed out"); + lp->scb.cmd = WSWAPcmd(virt_to_bus(&cmd->status)); lp->scb.command = CUC_START; CA(dev); } lp->cmd_tail = cmd; lp->cmd_backlog++; - lp->cmd_head = WSWAPcmd(lp->scb.cmd); /* Is this redundant? RGH 300597 */ - spin_unlock_irqrestore (&lp->lock, flags); if (lp->cmd_backlog > max_cmd_backlog) { @@ -874,11 +962,14 @@ static int i596_open(struct net_device *dev) { - if (i596_debug > 1) - printk("%s: i596_open() irq %d.\n", dev->name, dev->irq); + int res = 0; + + DEB(DEB_OPEN,printk("%s: i596_open() irq %d.\n", dev->name, dev->irq)); - if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) + if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) { + printk("%s: IRQ %d not free\n", dev->name, dev->irq); return -EAGAIN; + } #ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) { if (request_irq(0x56, &i596_error, 0, "i82596_error", dev)) @@ -892,9 +983,12 @@ MOD_INC_USE_COUNT; /* Initialize the 82596 memory */ - init_i596_mem(dev); + if (init_i596_mem(dev)) { + res = -EAGAIN; + free_irq(dev->irq, dev); + } - return 0; /* Always succeed */ + return res; } static void i596_tx_timeout (struct net_device *dev) @@ -903,21 +997,19 @@ int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ - printk ("%s: transmit timed out, status resetting.\n", dev->name); + DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n", + dev->name)); lp->stats.tx_errors++; /* Try to restart the adaptor */ if (lp->last_restart == lp->stats.tx_packets) { - if (i596_debug > 1) - printk ("Resetting board.\n"); - + DEB(DEB_ERRORS,printk ("Resetting board.\n")); /* Shutdown and restart */ i596_reset (dev, lp, ioaddr); } else { /* Issue a channel attention signal */ - if (i596_debug > 1) - printk ("Kicking board.\n"); + DEB(DEB_ERRORS,printk ("Kicking board.\n")); lp->scb.command = CUC_START | RX_START; CA (dev); lp->last_restart = lp->stats.tx_packets; @@ -933,55 +1025,47 @@ struct i596_private *lp = (struct i596_private *) dev->priv; struct tx_cmd *tx_cmd; struct i596_tbd *tbd; + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + dev->trans_start = jiffies; - if (i596_debug > 2) - printk("%s: 82596 start xmit\n", dev->name); - - if (i596_debug > 3) - printk("%s: i596_start_xmit(%x,%x) called\n", dev->name, - skb->len, (unsigned int)skb->data); + DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name, + skb->len, (unsigned int)skb->data)); netif_stop_queue(dev); - - { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - dev->trans_start = jiffies; - tx_cmd = lp->tx_cmds + lp->next_tx_cmd; - tbd = lp->tbds + lp->next_tx_cmd; + tx_cmd = lp->tx_cmds + lp->next_tx_cmd; + tbd = lp->tbds + lp->next_tx_cmd; + + if (tx_cmd->cmd.command) { + DEB(DEB_ERRORS,printk ("%s: xmit ring full, dropping packet.\n", + dev->name)); + lp->stats.tx_dropped++; - if (tx_cmd->cmd.command) { - printk ("%s: xmit ring full, dropping packet.\n", - dev->name); - lp->stats.tx_dropped++; - - dev_kfree_skb(skb); - } else { - if (++lp->next_tx_cmd == TX_RING_SIZE) - lp->next_tx_cmd = 0; - tx_cmd->tbd = WSWAPtbd(tbd); - tbd->next = (struct i596_tbd *) I596_NULL; - - tx_cmd->cmd.command = CMD_FLEX | CmdTx; - tx_cmd->skb = skb; - - tx_cmd->pad = 0; - tx_cmd->size = 0; - tbd->pad = 0; - tbd->size = EOF | length; + dev_kfree_skb(skb); + } else { + if (++lp->next_tx_cmd == TX_RING_SIZE) + lp->next_tx_cmd = 0; + tx_cmd->tbd = WSWAPtbd(virt_to_bus(tbd)); + tbd->next = I596_NULL; + + tx_cmd->cmd.command = CMD_FLEX | CmdTx; + tx_cmd->skb = skb; + + tx_cmd->pad = 0; + tx_cmd->size = 0; + tbd->pad = 0; + tbd->size = EOF | length; - tbd->data = WSWAPchar(skb->data); + tbd->data = WSWAPchar(virt_to_bus(skb->data)); #ifdef __mc68000__ - cache_push(virt_to_phys(skb->data), length); + cache_push(virt_to_phys(skb->data), length); #endif - if (i596_debug > 3) - print_eth(skb->data); - i596_add_cmd(dev, (struct i596_cmd *) tx_cmd); + DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued")); + i596_add_cmd(dev, &tx_cmd->cmd); - lp->stats.tx_packets++; - lp->stats.tx_bytes += length; - } + lp->stats.tx_packets++; + lp->stats.tx_bytes += length; } netif_start_queue(dev); @@ -989,21 +1073,17 @@ return 0; } -static void print_eth(char *add) +static void print_eth(unsigned char *add, char *str) { int i; - printk("print_eth(%08x)\n", (unsigned int) add); - printk("Dest "); + printk("i596 0x%p, ", add); for (i = 0; i < 6; i++) - printk(" %2.2X", (unsigned char) add[i]); - printk("\n"); - - printk("Source"); + printk(" %02X", add[i + 6]); + printk(" -->"); for (i = 0; i < 6; i++) - printk(" %2.2X", (unsigned char) add[i + 6]); - printk("\n"); - printk("type %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]); + printk(" %02X", add[i]); + printk(" %02X%02X, %s\n", add[12], add[13], str); } int __init i82596_probe(struct net_device *dev) @@ -1011,19 +1091,17 @@ int i; struct i596_private *lp; char eth_addr[6]; + static int probed = 0; + if (probed) + return -ENODEV; + probed++; #ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) { - static int probed = 0; -#ifdef XXX_FIXME if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) { printk("Ethernet probe disabled - chip not present\n"); - return ENODEV; + return -ENODEV; } -#endif - if (probed) - return ENODEV; - probed++; memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */ dev->base_addr = MVME_I596_BASE; dev->irq = (unsigned) MVME16x_IRQ_I596; @@ -1044,48 +1122,59 @@ } #endif #ifdef ENABLE_APRICOT - int checksum = 0; - int ioaddr = 0x300; + { + int checksum = 0; + int ioaddr = 0x300; - /* this is easy the ethernet interface can only be at 0x300 */ - /* first check nothing is already registered here */ + /* this is easy the ethernet interface can only be at 0x300 */ + /* first check nothing is already registered here */ - if (check_region(ioaddr, I596_TOTAL_SIZE)) - return ENODEV; + if (check_region(ioaddr, I596_TOTAL_SIZE)) { + printk("82596: IO address 0x%04x in use\n", ioaddr); + return -ENODEV; + } - for (i = 0; i < 8; i++) { - eth_addr[i] = inb(ioaddr + 8 + i); - checksum += eth_addr[i]; - } + for (i = 0; i < 8; i++) { + eth_addr[i] = inb(ioaddr + 8 + i); + checksum += eth_addr[i]; + } - /* checksum is a multiple of 0x100, got this wrong first time - some machines have 0x100, some 0x200. The DOS driver doesn't - even bother with the checksum */ + /* checksum is a multiple of 0x100, got this wrong first time + some machines have 0x100, some 0x200. The DOS driver doesn't + even bother with the checksum */ - if (checksum % 0x100) - return ENODEV; + if (checksum % 0x100) + return -ENODEV; - /* Some other boards trip the checksum.. but then appear as ether - address 0. Trap these - AC */ + /* Some other boards trip the checksum.. but then appear as + * ether address 0. Trap these - AC */ - if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0) - return ENODEV; + if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0) + return -ENODEV; - request_region(ioaddr, I596_TOTAL_SIZE, "i596"); + request_region(ioaddr, I596_TOTAL_SIZE, "i596"); - dev->base_addr = ioaddr; - dev->irq = 10; + dev->base_addr = ioaddr; + dev->irq = 10; + } +#endif + dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0); + if (!dev->mem_start) { +#ifdef ENABLE_APRICOT + release_region(dev->base_addr, I596_TOTAL_SIZE); #endif + return -ENOMEM; + } + ether_setup(dev); - printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr); + DEB(DEB_PROBE,printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr)); for (i = 0; i < 6; i++) - printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]); + DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i])); - printk(" IRQ %d.\n", dev->irq); + DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq)); - if (i596_debug > 0) - printk(version); + DEB(DEB_PROBE,printk(version)); /* The 82596-specific entries in the device structure. */ dev->open = i596_open; @@ -1095,16 +1184,13 @@ dev->set_multicast_list = set_multicast_list; dev->tx_timeout = i596_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - - dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0); dev->priv = (void *)(dev->mem_start); lp = (struct i596_private *) dev->priv; - if (i596_debug) - printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n", + DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n", dev->name, (unsigned long)lp, - sizeof(struct i596_private), (unsigned long)&lp->scb); + sizeof(struct i596_private), (unsigned long)&lp->scb)); memset((void *) lp, 0, sizeof(struct i596_private)); #ifdef __mc68000__ @@ -1113,8 +1199,8 @@ kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER); #endif lp->scb.command = 0; - lp->scb.cmd = (struct i596_cmd *) I596_NULL; - lp->scb.rfd = (struct i596_rfd *) I596_NULL; + lp->scb.cmd = I596_NULL; + lp->scb.rfd = I596_NULL; lp->lock = SPIN_LOCK_UNLOCKED; return 0; @@ -1125,7 +1211,6 @@ struct net_device *dev = dev_id; struct i596_private *lp; short ioaddr; - int boguscnt = 2000; unsigned short status, ack_cmd = 0; #ifdef ENABLE_BVME6000_NET @@ -1140,145 +1225,116 @@ printk("i596_interrupt(): irq %d for unknown device.\n", irq); return; } - if (i596_debug > 3) - printk("%s: i596_interrupt(): irq %d\n", dev->name, irq); ioaddr = dev->base_addr; lp = (struct i596_private *) dev->priv; - + spin_lock (&lp->lock); - while (lp->scb.command) - if (--boguscnt == 0) { - printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); - break; - } + wait_cmd(dev,lp,100,"i596 interrupt, timeout"); status = lp->scb.status; - if (i596_debug > 4) - printk("%s: i596 interrupt, status %4.4x.\n", dev->name, status); + DEB(DEB_INTS,printk("%s: i596 interrupt, IRQ %d, status %4.4x.\n", + dev->name, irq, status)); ack_cmd = status & 0xf000; if ((status & 0x8000) || (status & 0x2000)) { struct i596_cmd *ptr; - if ((i596_debug > 4) && (status & 0x8000)) - printk("%s: i596 interrupt completed command.\n", dev->name); - if ((i596_debug > 4) && (status & 0x2000)) - printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700); + if ((status & 0x8000)) + DEB(DEB_INTS,printk("%s: i596 interrupt completed command.\n", dev->name)); + if ((status & 0x2000)) + DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700)); - while ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (lp->cmd_head->status & STAT_C)) { + while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) { ptr = lp->cmd_head; - if (i596_debug > 2) - printk("cmd_head->status = %04x, ->command = %04x\n", - lp->cmd_head->status, lp->cmd_head->command); - lp->cmd_head = WSWAPcmd(lp->cmd_head->next); + DEB(DEB_STATUS,printk("cmd_head->status = %04x, ->command = %04x\n", + lp->cmd_head->status, lp->cmd_head->command)); + lp->cmd_head = ptr->v_next; lp->cmd_backlog--; switch ((ptr->command) & 0x7) { case CmdTx: - { - struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; - struct sk_buff *skb = tx_cmd->skb; - - if ((ptr->status) & STAT_OK) { - if (i596_debug > 2) - print_eth(skb->data); - } else { - lp->stats.tx_errors++; - if ((ptr->status) & 0x0020) - lp->stats.collisions++; - if (!((ptr->status) & 0x0040)) - lp->stats.tx_heartbeat_errors++; - if ((ptr->status) & 0x0400) - lp->stats.tx_carrier_errors++; - if ((ptr->status) & 0x0800) - lp->stats.collisions++; - if ((ptr->status) & 0x1000) - lp->stats.tx_aborted_errors++; - } - - dev_kfree_skb(skb); - - ptr->next = (struct i596_cmd *) I596_NULL; - tx_cmd->cmd.command = 0; /* Mark free */ - break; - } - case CmdMulticastList: - { - ptr->next = (struct i596_cmd *) I596_NULL; - break; + { + struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; + struct sk_buff *skb = tx_cmd->skb; + + if ((ptr->status) & STAT_OK) { + DEB(DEB_TXADDR,print_eth(skb->data, "tx-done")); + } else { + lp->stats.tx_errors++; + if ((ptr->status) & 0x0020) + lp->stats.collisions++; + if (!((ptr->status) & 0x0040)) + lp->stats.tx_heartbeat_errors++; + if ((ptr->status) & 0x0400) + lp->stats.tx_carrier_errors++; + if ((ptr->status) & 0x0800) + lp->stats.collisions++; + if ((ptr->status) & 0x1000) + lp->stats.tx_aborted_errors++; } + + dev_kfree_skb_irq(skb); + + tx_cmd->cmd.command = 0; /* Mark free */ + break; + } case CmdTDR: - { - unsigned long status = *((unsigned long *) (ptr + 1)); + { + unsigned short status = ((struct tdr_cmd *)ptr)->status; - if (status & 0x8000) { - if (i596_debug > 3) - printk("%s: link ok.\n", dev->name); - } else { - if (status & 0x4000) - printk("%s: Transceiver problem.\n", dev->name); - if (status & 0x2000) - printk("%s: Termination problem.\n", dev->name); - if (status & 0x1000) - printk("%s: Short circuit.\n", dev->name); - - if (i596_debug > 1) - printk("%s: Time %ld.\n", dev->name, status & 0x07ff); - } - break; + if (status & 0x8000) { + DEB(DEB_ANY,printk("%s: link ok.\n", dev->name)); + } else { + if (status & 0x4000) + printk("%s: Transceiver problem.\n", dev->name); + if (status & 0x2000) + printk("%s: Termination problem.\n", dev->name); + if (status & 0x1000) + printk("%s: Short circuit.\n", dev->name); + + DEB(DEB_TDR,printk("%s: Time %d.\n", dev->name, status & 0x07ff)); } + break; + } case CmdConfigure: - { - ptr->next = (struct i596_cmd *) I596_NULL; - /* Zap command so set_multicast_list() knows it is free */ - ptr->command = 0; - break; - } - default: - ptr->next = (struct i596_cmd *) I596_NULL; + /* Zap command so set_multicast_list() knows it is free */ + ptr->command = 0; + break; } + ptr->v_next = ptr->b_next = I596_NULL; lp->last_cmd = jiffies; } ptr = lp->cmd_head; - while ((ptr != (struct i596_cmd *) I596_NULL) && (ptr != lp->cmd_tail)) { + while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) { ptr->command &= 0x1fff; - ptr = WSWAPcmd(ptr->next); + ptr = ptr->v_next; } - if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && - netif_running(dev)) + if ((lp->cmd_head != I596_NULL)) ack_cmd |= CUC_START; - lp->scb.cmd = WSWAPcmd(lp->cmd_head); + lp->scb.cmd = WSWAPcmd(virt_to_bus(&lp->cmd_head->status)); } if ((status & 0x1000) || (status & 0x4000)) { - if ((i596_debug > 4) && (status & 0x4000)) - printk("%s: i596 interrupt received a frame.\n", dev->name); + if ((status & 0x4000)) + DEB(DEB_INTS,printk("%s: i596 interrupt received a frame.\n", dev->name)); + i596_rx(dev); /* Only RX_START if stopped - RGH 07-07-96 */ if (status & 0x1000) { - if (netif_running(dev)) + if (netif_running(dev)) { + DEB(DEB_ERRORS,printk("%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status)); ack_cmd |= RX_START; - if (i596_debug > 1) - printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x00f0); + lp->stats.rx_errors++; + lp->stats.rx_fifo_errors++; + rebuild_rx_bufs(dev); + } } - i596_rx(dev); } - /* acknowledge the interrupt */ - -/* COMMENTED OUT <<<<< - if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start)) - ack_cmd |= CUC_START; - */ - boguscnt = 1000; - while (lp->scb.command) - if (--boguscnt == 0) { - printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); - break; - } + wait_cmd(dev,lp,100,"i596 interrupt, timeout"); lp->scb.command = ack_cmd; #ifdef ENABLE_MVME16x_NET @@ -1304,49 +1360,33 @@ #endif CA(dev); - if (i596_debug > 4) - printk("%s: exiting interrupt.\n", dev->name); + DEB(DEB_INTS,printk("%s: exiting interrupt.\n", dev->name)); spin_unlock (&lp->lock); - return; } static int i596_close(struct net_device *dev) { struct i596_private *lp = (struct i596_private *) dev->priv; - int boguscnt = 2000; unsigned long flags; netif_stop_queue(dev); - if (i596_debug > 1) - printk("%s: Shutting down ethercard, status was %4.4x.\n", - dev->name, lp->scb.status); + DEB(DEB_INIT,printk("%s: Shutting down ethercard, status was %4.4x.\n", + dev->name, lp->scb.status)); save_flags(flags); cli(); - while (lp->scb.command) - if (--boguscnt == 0) { - printk("%s: close1 timed out with status %4.4x, cmd %4.4x.\n", - dev->name, lp->scb.status, lp->scb.command); - break; - } + wait_cmd(dev,lp,100,"close1 timed out"); lp->scb.command = CUC_ABORT | RX_ABORT; CA(dev); - boguscnt = 2000; - - while (lp->scb.command) - if (--boguscnt == 0) { - printk("%s: close2 timed out with status %4.4x, cmd %4.4x.\n", - dev->name, lp->scb.status, lp->scb.command); - break; - } + wait_cmd(dev,lp,100,"close2 timed out"); restore_flags(flags); - - i596_cleanup_cmd(lp); + DEB(DEB_STRUCT,i596_display_data(dev)); + i596_cleanup_cmd(dev,lp); #ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) { @@ -1388,35 +1428,33 @@ static void set_multicast_list(struct net_device *dev) { struct i596_private *lp = (struct i596_private *) dev->priv; - struct i596_cmd *cmd; int config = 0, cnt; - if (i596_debug > 1) - printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF"); + DEB(DEB_MULTI,printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF")); - if ((dev->flags & IFF_PROMISC) && !(lp->i596_config[8] & 0x01)) { - lp->i596_config[8] |= 0x01; + if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) { + lp->cf_cmd.i596_config[8] |= 0x01; config = 1; } - if (!(dev->flags & IFF_PROMISC) && (lp->i596_config[8] & 0x01)) { - lp->i596_config[8] &= ~0x01; + if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) { + lp->cf_cmd.i596_config[8] &= ~0x01; config = 1; } - if ((dev->flags & IFF_ALLMULTI) && (lp->i596_config[11] & 0x20)) { - lp->i596_config[11] &= ~0x20; + if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) { + lp->cf_cmd.i596_config[11] &= ~0x20; config = 1; } - if (!(dev->flags & IFF_ALLMULTI) && !(lp->i596_config[11] & 0x20)) { - lp->i596_config[11] |= 0x20; + if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) { + lp->cf_cmd.i596_config[11] |= 0x20; config = 1; } if (config) { - if (lp->set_conf.command) + if (lp->cf_cmd.cmd.command) printk("%s: config change request already queued\n", dev->name); else { - lp->set_conf.command = CmdConfigure; - i596_add_cmd(dev, &lp->set_conf); + lp->cf_cmd.cmd.command = CmdConfigure; + i596_add_cmd(dev, &lp->cf_cmd.cmd); } } @@ -1431,20 +1469,19 @@ if (dev->mc_count > 0) { struct dev_mc_list *dmi; unsigned char *cp; + struct mc_cmd *cmd; cmd = &lp->mc_cmd; - cmd->command = CmdMulticastList; - *((unsigned short *) (cmd + 1)) = dev->mc_count * 6; - cp = ((unsigned char *) (cmd + 1)) + 2; - for(dmi=dev->mc_list;cnt && dmi!=NULL;dmi=dmi->next,cnt--) { + cmd->cmd.command = CmdMulticastList; + cmd->mc_cnt = dev->mc_count * 6; + cp = cmd->mc_addrs; + for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) { memcpy(cp, dmi->dmi_addr, 6); if (i596_debug > 1) - printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, *(cp + 0), *(cp + 1), *(cp + 2), *(cp + 3), *(cp + 4), *(cp + 5)); - cp += 6; + DEB(DEB_MULTI,printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5])); } - if (i596_debug > 2) - print_eth(((char *) (cmd + 1)) + 2); - i596_add_cmd(dev, cmd); + i596_add_cmd(dev, &cmd->cmd); } } @@ -1495,7 +1532,7 @@ * XXX which may be invalid (CONFIG_060_WRITETHROUGH) */ - kernel_set_cachemode((u32)(dev_82596.mem_start), 4096, + kernel_set_cachemode((void *)(dev_82596.mem_start), 4096, IOMAP_FULL_CACHING); #endif free_page ((u32)(dev_82596.mem_start)); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.3.99-pre5/linux/drivers/net/8390.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/net/8390.c Wed Apr 12 09:38:53 2000 @@ -181,7 +181,7 @@ * ei_close - shut down network device * @dev: network device to close * - * Opposite of ei_open. Only used when "ifconfig down" is done. + * Opposite of ei_open(). Only used when "ifconfig down" is done. */ int ei_close(struct net_device *dev) { @@ -416,7 +416,7 @@ * the 8390 via the card specific functions and fire them at the networking * stack. We also handle transmit completions and wake the transmit path if * neccessary. We also update the counters and do other housekeeping as - * needed + * needed. */ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) @@ -530,7 +530,7 @@ * is a much better solution as it avoids kernel based Tx timeouts, and * an unnecessary card reset. * - * Called with lock held + * Called with lock held. */ static void ei_tx_err(struct net_device *dev) @@ -573,7 +573,7 @@ * @dev: network device for which tx intr is handled * * We have finished a transmit: check for errors and then trigger the next - * packet to be sent. Called with lock held + * packet to be sent. Called with lock held. */ static void ei_tx_intr(struct net_device *dev) @@ -665,7 +665,7 @@ * @dev: network device with which receive will be run * * We have a good packet(s), get it/them out of the buffers. - * Called with lock held + * Called with lock held. */ static void ei_receive(struct net_device *dev) @@ -801,7 +801,7 @@ * This includes causing "the NIC to defer indefinitely when it is stopped * on a busy network." Ugh. * Called with lock held. Don't call this with the interrupts off or your - * computer will hate you - it takes 10mS or so. + * computer will hate you - it takes 10ms or so. */ static void ei_rx_overrun(struct net_device *dev) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.3.99-pre5/linux/drivers/net/Space.c Wed Apr 12 10:02:34 2000 +++ linux/drivers/net/Space.c Thu Apr 13 17:06:00 2000 @@ -683,6 +683,46 @@ #define NEXT_DEV (&sbni0_dev) #endif +/* S/390 channels */ +#ifdef CONFIG_CTC + extern int ctc_probe(struct net_device *dev); + static struct net_device ctc7_dev = + {"ctc7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, ctc_probe}; + static struct net_device ctc6_dev = + {"ctc6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc7_dev, ctc_probe}; + static struct net_device ctc5_dev = + {"ctc5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc6_dev, ctc_probe}; + static struct net_device ctc4_dev = + {"ctc4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc5_dev, ctc_probe}; + static struct net_device ctc3_dev = + {"ctc3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc4_dev, ctc_probe}; + static struct net_device ctc2_dev = + {"ctc2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc3_dev, ctc_probe}; + static struct net_device ctc1_dev = + {"ctc1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc2_dev, ctc_probe}; + static struct net_device ctc0_dev = + {"ctc0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc1_dev, ctc_probe}; + + static struct net_device escon7_dev = + {"escon7", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc0_dev, ctc_probe}; + static struct net_device escon6_dev = + {"escon6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon7_dev, ctc_probe}; + static struct net_device escon5_dev = + {"escon5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon6_dev, ctc_probe}; + static struct net_device escon4_dev = + {"escon4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon5_dev, ctc_probe}; + static struct net_device escon3_dev = + {"escon3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon4_dev, ctc_probe}; + static struct net_device escon2_dev = + {"escon2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon3_dev, ctc_probe}; + static struct net_device escon1_dev = + {"escon1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon2_dev, ctc_probe}; + static struct net_device escon0_dev = + {"escon0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon1_dev, ctc_probe}; + +#undef NEXT_DEV +#define NEXT_DEV (&escon0_dev) +#endif /* diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.3.99-pre5/linux/drivers/net/acenic.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/net/acenic.c Fri Apr 21 16:08:52 2000 @@ -2949,6 +2949,6 @@ /* * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c" + * compile-command: "gcc -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c" * End: */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c --- v2.3.99-pre5/linux/drivers/net/am79c961a.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/am79c961a.c Tue Apr 25 17:38:33 2000 @@ -33,40 +33,49 @@ #include "am79c961a.h" +static int am79c961_probe1 (struct net_device *dev); +static int am79c961_open (struct net_device *dev); +static int am79c961_sendpacket (struct sk_buff *skb, struct net_device *dev); +static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static void am79c961_rx (struct net_device *dev, struct dev_priv *priv); +static void am79c961_tx (struct net_device *dev, struct dev_priv *priv); +static int am79c961_close (struct net_device *dev); +static struct enet_statistics *am79c961_getstats (struct net_device *dev); +static void am79c961_setmulticastlist (struct net_device *dev); +static void am79c961_timeout(struct net_device *dev); + static unsigned int net_debug = NET_DEBUG; static void am79c961_setmulticastlist (struct net_device *dev); -static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n"; +static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.01\n"; #define FUNC_PROLOGUE \ struct dev_priv *priv = (struct dev_priv *)dev->priv /* --------------------------------------------------------------------------- */ +#ifdef __arm__ static void write_rreg (unsigned long base, unsigned int reg, unsigned short val) { - __asm__(" - strh %1, [%2] @ NET_RAP - strh %0, [%2, #-4] @ NET_RDP + __asm__("str%?h %1, [%2] @ NET_RAP + str%?h %0, [%2, #-4] @ NET_RDP " : : "r" (val), "r" (reg), "r" (0xf0000464)); } static inline void write_ireg (unsigned long base, unsigned int reg, unsigned short val) { - __asm__(" - strh %1, [%2] @ NET_RAP - strh %0, [%2, #8] @ NET_RDP + __asm__("str%?h %1, [%2] @ NET_RAP + str%?h %0, [%2, #8] @ NET_RDP " : : "r" (val), "r" (reg), "r" (0xf0000464)); } #define am_writeword(dev,off,val)\ - __asm__("\ - strh %0, [%1]\ - " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1))); + __asm__("str%?h %0, [%1]" : : \ + "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1))); static inline void am_writebuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, unsigned int length) @@ -74,30 +83,28 @@ offset = 0xe0000000 + (offset << 1); length = (length + 1) & ~1; if ((int)buf & 2) { - __asm__ __volatile__(" - strh %2, [%0], #4 - " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); + __asm__ __volatile__("str%?h %2, [%0], #4" + : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); buf += 2; length -= 2; } while (length > 8) { unsigned int tmp, tmp2; __asm__ __volatile__(" - ldmia %1!, {%2, %3} - strh %2, [%0], #4 - mov %2, %2, lsr #16 - strh %2, [%0], #4 - strh %3, [%0], #4 - mov %3, %3, lsr #16 - strh %3, [%0], #4 + ldm%?ia %1!, {%2, %3} + str%?h %2, [%0], #4 + mov%? %2, %2, lsr #16 + str%?h %2, [%0], #4 + str%?h %3, [%0], #4 + mov%? %3, %3, lsr #16 + str%?h %3, [%0], #4 " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2) : "0" (offset), "1" (buf)); length -= 8; } while (length > 0) { - __asm__ __volatile__(" - strh %2, [%0], #4 - " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); + __asm__ __volatile__("str%?h %2, [%0], #4" + : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); buf += 2; length -= 2; } @@ -107,9 +114,8 @@ read_rreg (unsigned int base_addr, unsigned int reg) { unsigned short v; - __asm__(" - strh %1, [%2] @ NET_RAP - ldrh %0, [%2, #-4] @ NET_IDP + __asm__("str%?h %1, [%2] @ NET_RAP + ldr%?h %0, [%2, #-4] @ NET_IDP " : "=r" (v): "r" (reg), "r" (0xf0000464)); return v; } @@ -120,9 +126,7 @@ unsigned long address = 0xe0000000 + (off << 1); unsigned short val; - __asm__(" - ldrh %0, [%1] - " : "=r" (val): "r" (address)); + __asm__("ldr%?h %0, [%1]" : "=r" (val): "r" (address)); return val; } @@ -134,23 +138,23 @@ if ((int)buf & 2) { unsigned int tmp; __asm__ __volatile__(" - ldrh %2, [%0], #4 - strb %2, [%1], #1 - mov %2, %2, lsr #8 - strb %2, [%1], #1 + ldr%?h %2, [%0], #4 + str%?b %2, [%1], #1 + mov%? %2, %2, lsr #8 + str%?b %2, [%1], #1 " : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf)); length -= 2; } while (length > 8) { unsigned int tmp, tmp2, tmp3; __asm__ __volatile__(" - ldrh %2, [%0], #4 - ldrh %3, [%0], #4 - orr %2, %2, %3, lsl #16 - ldrh %3, [%0], #4 - ldrh %4, [%0], #4 - orr %3, %3, %4, lsl #16 - stmia %1!, {%2, %3} + ldr%?h %2, [%0], #4 + ldr%?h %3, [%0], #4 + orr%? %2, %2, %3, lsl #16 + ldr%?h %3, [%0], #4 + ldr%?h %4, [%0], #4 + orr%? %3, %3, %4, lsl #16 + stm%?ia %1!, {%2, %3} " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3) : "0" (offset), "1" (buf)); length -= 8; @@ -158,14 +162,17 @@ while (length > 0) { unsigned int tmp; __asm__ __volatile__(" - ldrh %2, [%0], #4 - strb %2, [%1], #1 - mov %2, %2, lsr #8 - strb %2, [%1], #1 + ldr%?h %2, [%0], #4 + str%?b %2, [%1], #1 + mov%? %2, %2, lsr #8 + str%?b %2, [%1], #1 " : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf)); length -= 2; } } +#else +#error Not compatable +#endif static int am79c961_ramtest(struct net_device *dev, unsigned int val) @@ -259,7 +266,7 @@ write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); write_rreg (dev->base_addr, CSR0, CSR0_STOP); - write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM); + write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO); write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT); } @@ -304,7 +311,7 @@ /* * The PNP initialisation should have been done by the ether bootp loader. */ - inb ((dev->base_addr + NET_RESET) >> 1); /* reset the device */ + inb((dev->base_addr + NET_RESET) >> 1); /* reset the device */ udelay (5); @@ -343,6 +350,7 @@ dev->hard_start_xmit = am79c961_sendpacket; dev->get_stats = am79c961_getstats; dev->set_multicast_list = am79c961_setmulticastlist; + dev->tx_timeout = am79c961_timeout; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); @@ -382,14 +390,15 @@ memset (&priv->stats, 0, sizeof (priv->stats)); - if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev)) + if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev)) { + MOD_DEC_USE_COUNT; return -EAGAIN; + } am79c961_init_for_open(dev); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); + return 0; } @@ -399,8 +408,7 @@ static int am79c961_close(struct net_device *dev) { - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); am79c961_init(dev); @@ -420,26 +428,116 @@ return &priv->stats; } +static inline u32 update_crc(u32 crc, u8 byte) +{ + int i; + + for (i = 8; i != 0; i--) { + byte ^= crc & 1; + crc >>= 1; + + if (byte & 1) + crc ^= 0xedb88320; + + byte >>= 1; + } + + return crc; +} + +static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash) +{ + if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) { + int i, idx, bit; + u32 crc; + + crc = 0xffffffff; + + for (i = 0; i < ETH_ALEN; i++) + crc = update_crc(crc, dmi->dmi_addr[i]); + + idx = crc >> 30; + bit = (crc >> 26) & 15; + + hash[idx] |= 1 << bit; + } +} + /* * Set or clear promiscuous/multicast mode filter for this adaptor. - * - * We don't attempt any packet filtering. The card may have a SEEQ 8004 - * in which does not have the other ethernet address registers present... */ static void am79c961_setmulticastlist (struct net_device *dev) { unsigned long flags; - int i; + unsigned short multi_hash[4], mode; + int i, stopped; - dev->flags &= ~IFF_ALLMULTI; + mode = MODE_PORT0; - i = MODE_PORT0; - if (dev->flags & IFF_PROMISC) - i |= MODE_PROMISC; + if (dev->flags & IFF_PROMISC) { + mode |= MODE_PROMISC; + } else if (dev->flags & IFF_ALLMULTI) { + memset(multi_hash, 0xff, sizeof(multi_hash)); + } else { + struct dev_mc_list *dmi; - save_flags_cli (flags); - write_rreg (dev->base_addr, MODE, i); - restore_flags (flags); + memset(multi_hash, 0x00, sizeof(multi_hash)); + + for (dmi = dev->mc_list; dmi; dmi = dmi->next) + am79c961_mc_hash(dmi, multi_hash); + } + + save_flags_cli(flags); + + stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP; + + if (!stopped) { + /* + * Put the chip into suspend mode + */ + write_rreg(dev->base_addr, CTRL1, CTRL1_SPND); + + /* + * Spin waiting for chip to report suspend mode + */ + while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) { + restore_flags(flags); + nop(); + save_flags_cli(flags); + } + } + + /* + * Update the multicast hash table + */ + for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++) + write_rreg(dev->base_addr, i + LADRL, multi_hash[i]); + + /* + * Write the mode register + */ + write_rreg(dev->base_addr, MODE, mode); + + if (!stopped) { + /* + * Put the chip back into running mode + */ + write_rreg(dev->base_addr, CTRL1, 0); + } + + restore_flags(flags); +} + +static void am79c961_timeout(struct net_device *dev) +{ + printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n", + dev->name); + + /* + * ought to do some setup of the tx side here + */ + + netif_wake_queue(dev); } /* @@ -449,46 +547,34 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) { struct dev_priv *priv = (struct dev_priv *)dev->priv; + unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned int hdraddr, bufaddr; + unsigned int head; + unsigned long flags; - if (!dev->tbusy) { -again: - if (!test_and_set_bit(0, (void*)&dev->tbusy)) { - unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned int hdraddr, bufaddr; - unsigned long flags; - - hdraddr = priv->txhdr + (priv->txhead << 3); - bufaddr = priv->txbuffer[priv->txhead]; - priv->txhead ++; - if (priv->txhead >= TX_BUFFERS) - priv->txhead = 0; - - am_writebuffer (dev, bufaddr, skb->data, length); - am_writeword (dev, hdraddr + 4, -length); - am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP); - - save_flags_cli (flags); - write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA); - dev->trans_start = jiffies; - restore_flags (flags); - - if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)) - dev->tbusy = 0; - dev_kfree_skb (skb); - return 0; - } else - printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name); - return 1; - } else { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) - return 1; - printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name); - /* Try to restart the adaptor. */ - dev->tbusy = 0; - dev->trans_start = jiffies; - goto again; - } + head = priv->txhead; + hdraddr = priv->txhdr + (head << 3); + bufaddr = priv->txbuffer[head]; + head += 1; + if (head >= TX_BUFFERS) + head = 0; + + am_writebuffer (dev, bufaddr, skb->data, length); + am_writeword (dev, hdraddr + 4, -length); + am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP); + priv->txhead = head; + + save_flags_cli (flags); + write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA); + dev->trans_start = jiffies; + restore_flags (flags); + + if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)) + netif_stop_queue(dev); + + dev_kfree_skb(skb); + + return 0; } static void @@ -503,8 +589,6 @@ printk(KERN_DEBUG "am79c961irq: %d ", irq); #endif - dev->interrupt = 1; - status = read_rreg (dev->base_addr, CSR0); write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA)); @@ -515,8 +599,6 @@ if (status & CSR0_MISS) priv->stats.rx_dropped ++; - dev->interrupt = 0; - #if NET_DEBUG > 1 if(net_debug & DEBUG_INT) printk("done\n"); @@ -613,7 +695,7 @@ am_writeword (dev, hdraddr + 6, 0); if (status2 & TST_RTRY) - priv->stats.collisions += 1; + priv->stats.collisions += 16; if (status2 & TST_LCOL) priv->stats.tx_window_errors ++; if (status2 & TST_LCAR) @@ -625,7 +707,5 @@ priv->stats.tx_packets ++; } while (priv->txtail != priv->txhead); - dev->tbusy = 0; - mark_bh (NET_BH); + netif_wake_queue(dev); } - diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/am79c961a.h linux/drivers/net/am79c961a.h --- v2.3.99-pre5/linux/drivers/net/am79c961a.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/am79c961a.h Tue Apr 25 17:38:33 2000 @@ -45,6 +45,7 @@ #define CSR3_EMBA 0x0008 #define CSR3_DXMT2PD 0x0010 #define CSR3_LAPPEN 0x0020 +#define CSR3_DXSUFLO 0x0040 #define CSR3_IDONM 0x0100 #define CSR3_TINTM 0x0200 #define CSR3_RINTM 0x0400 @@ -53,6 +54,9 @@ #define CSR3_BABLM 0x4000 #define CSR3_MASKALL 0x5F00 +#define CTRL1 5 +#define CTRL1_SPND 0x0001 + #define LADRL 8 #define LADRM1 9 #define LADRM2 10 @@ -97,8 +101,8 @@ #define TMD_ERR 0x4000 #define TMD_OWN 0x8000 -#define TST_RTRY 0x0200 -#define TST_LCAR 0x0400 +#define TST_RTRY 0x0400 +#define TST_LCAR 0x0800 #define TST_LCOL 0x1000 #define TST_UFLO 0x4000 @@ -115,14 +119,5 @@ }; extern int am79c961_probe (struct net_device *dev); -static int am79c961_probe1 (struct net_device *dev); -static int am79c961_open (struct net_device *dev); -static int am79c961_sendpacket (struct sk_buff *skb, struct net_device *dev); -static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs); -static void am79c961_rx (struct net_device *dev, struct dev_priv *priv); -static void am79c961_tx (struct net_device *dev, struct dev_priv *priv); -static int am79c961_close (struct net_device *dev); -static struct enet_statistics *am79c961_getstats (struct net_device *dev); -static void am79c961_setmulticastlist (struct net_device *dev); #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/appletalk/ltpc.c linux/drivers/net/appletalk/ltpc.c --- v2.3.99-pre5/linux/drivers/net/appletalk/ltpc.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/net/appletalk/ltpc.c Wed Apr 12 09:38:53 2000 @@ -1253,17 +1253,15 @@ /* usage message */ printk (KERN_ERR "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n"); + return 0; } - return 1; } else { io = ints[1]; if (ints[0] > 1) { irq = ints[2]; - return 1; } if (ints[0] > 2) { dma = ints[3]; - return 1; } /* ignore any other paramters */ } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c --- v2.3.99-pre5/linux/drivers/net/arcnet/arcnet.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/arcnet/arcnet.c Wed Apr 12 09:38:53 2000 @@ -107,7 +107,7 @@ void __init arcnet_init(void) { - static int arcnet_inited __initdata = 0; + static int arcnet_inited = 0; int count; if (arcnet_inited++) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/arcnet/com90io.c linux/drivers/net/arcnet/com90io.c --- v2.3.99-pre5/linux/drivers/net/arcnet/com90io.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/arcnet/com90io.c Wed Apr 12 09:38:53 2000 @@ -426,7 +426,7 @@ s = get_options(s, 4, ints); if (!ints[0]) - return 1; + return 0; dev = alloc_bootmem(sizeof(struct net_device) + 10); memset(dev, 0, sizeof(struct net_device) + 10); dev->name = (char *) (dev + 1); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.3.99-pre5/linux/drivers/net/cs89x0.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/net/cs89x0.c Fri Apr 14 09:37:10 2000 @@ -48,10 +48,23 @@ : Don't call netif_wake_queue() in net_send_packet() : Fixed an out-of-mem bug in dma_rx() : Updated Documentation/cs89x0.txt + + Andrew Morton : andrewm@uow.edu.au / Kernel 2.3.99-pre1 + : Use skb_reserve to longword align IP header (two places) + : Remove a delay loop from dma_rx() + : Replace '100' with HZ + : Clean up a couple of skb API abuses + : Added 'cs89x0_dma=N' kernel boot option + : Correctly initialise lp->lock in non-module compile + + Andrew Morton : andrewm@uow.edu.au / Kernel 2.3.99-pre4-1 + : MOD_INC/DEC race fix (see + : http://www.uwsg.indiana.edu/hypermail/linux/kernel/0003.3/1532.html) + */ static char *version = -"cs89x0.c: (kernel 2.3.48) Russell Nelson , Andrew Morton \n"; +"cs89x0.c: v2.3.99-pre1-2 Russell Nelson , Andrew Morton \n"; /* ======================= end of configuration ======================= */ @@ -121,7 +134,7 @@ { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; #if DEBUGGING -static unsigned int net_debug = 5; +static unsigned int net_debug = DEBUGGING; #else #define net_debug 0 /* gcc will remove all the debug code for us */ #endif @@ -190,6 +203,21 @@ /* Example routines you must write ;->. */ #define tx_done(dev) 1 +/* + * Permit 'cs89x0_dma=N' in the kernel boot environment + */ +#if !defined(MODULE) && (ALLOW_DMA != 0) +static int g_cs89x0_dma; + +static int __init dma_fn(char *str) +{ + g_cs89x0_dma = simple_strtol(str,NULL,0); + return 1; +} + +__setup("cs89x0_dma=", dma_fn); +#endif /* !defined(MODULE) && (ALLOW_DMA != 0) */ + /* Check for a network adaptor of this type, and return '0' iff one exists. If dev->base_addr == 0, probe all likely locations. @@ -318,7 +346,17 @@ retval = ENOMEM; goto out; } - memset(dev->priv, 0, sizeof(struct net_local)); + lp = (struct net_local *)dev->priv; + memset(lp, 0, sizeof(*lp)); + spin_lock_init(&lp->lock); +#if !defined(MODULE) && (ALLOW_DMA != 0) + if (g_cs89x0_dma) + { + lp->use_dma = 1; + lp->dma = g_cs89x0_dma; + lp->dmasize = 16; /* Could make this an option... */ + } +#endif } lp = (struct net_local *)dev->priv; @@ -612,12 +650,6 @@ int status, length; unsigned char *bp = lp->rx_dma_ptr; - { - int i; - for (i = 0; i < 1000; i++) - ; - } - status = bp[0] + (bp[1]<<8); length = bp[2] + (bp[3]<<8); bp += 4; @@ -632,7 +664,7 @@ } /* Malloc up new buffer. */ - skb = alloc_skb(length, GFP_ATOMIC); + skb = dev_alloc_skb(length + 2); if (skb == NULL) { if (net_debug) /* I don't think we want to do this to a stressed system */ printk("%s: Memory squeeze, dropping packet.\n", dev->name); @@ -645,8 +677,7 @@ lp->rx_dma_ptr = bp; return; } - - skb->len = length; + skb_reserve(skb, 2); /* longword align L3 header */ skb->dev = dev; if (bp + length > lp->end_dma_buff) { @@ -720,7 +751,7 @@ writereg(dev, PP_SelfCTL, selfcontrol); /* Wait for the DC/DC converter to power up - 500ms */ - while (jiffies - timenow < 100) + while (jiffies - timenow < HZ) ; } @@ -914,6 +945,9 @@ struct net_local *lp = (struct net_local *)dev->priv; int result = 0; int i; + int ret; + + MOD_INC_USE_COUNT; if (dev->irq < 2) { /* Allow interrupts to be generated by the chip */ @@ -938,13 +972,15 @@ writereg(dev, PP_BusCTL, 0); /* disable interrupts. */ if (net_debug) printk("cs89x0: can't get an interrupt\n"); - return -EAGAIN; + ret = -EAGAIN; + goto bad_out; } } else { if (((1 << dev->irq) & lp->irq_map) == 0) { printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); - return -EAGAIN; + ret = -EAGAIN; + goto bad_out; } /* FIXME: Cirrus' release had this: */ writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); @@ -956,7 +992,8 @@ if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) { if (net_debug) printk("cs89x0: request_irq(%d) failed\n", dev->irq); - return -EAGAIN; + ret = -EAGAIN; + goto bad_out; } } @@ -1032,7 +1069,8 @@ #endif writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON)); free_irq(dev->irq, dev); - return -EAGAIN; + ret = -EAGAIN; + goto bad_out; } /* set the hardware to the configured choice */ @@ -1125,11 +1163,13 @@ | dma_busctl(dev) #endif ); - MOD_INC_USE_COUNT; netif_start_queue(dev); if (net_debug) printk("cs89x0: net_open() succeeded\n"); return 0; +bad_out: + MOD_DEC_USE_COUNT; + return ret; } static void net_timeout(struct net_device *dev) @@ -1317,7 +1357,7 @@ } /* Malloc up new buffer. */ - skb = alloc_skb(length, GFP_ATOMIC); + skb = dev_alloc_skb(length + 2); if (skb == NULL) { #if 0 /* Again, this seems a cruel thing to do */ printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); @@ -1325,10 +1365,10 @@ lp->stats.rx_dropped++; return; } - skb->len = length; + skb_reserve(skb, 2); /* longword align L3 header */ skb->dev = dev; - insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1); + insw(ioaddr + RX_FRAME_PORT, skb_put(skb, length), length >> 1); if (length & 1) skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.3.99-pre5/linux/drivers/net/de4x5.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/de4x5.c Fri Apr 21 16:08:52 2000 @@ -5923,9 +5923,7 @@ /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c" * - * Delete -D__SMP__ below if you didn't define this in your kernel * Delete -DMODVERSIONS below if you didn't define this in your kernel * * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -DMODVERSIONS -include /linux/include/linux/modversions.h -c de4x5.c" diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.3.99-pre5/linux/drivers/net/eepro.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/eepro.c Wed Apr 12 09:38:53 2000 @@ -1614,6 +1614,8 @@ if (register_netdev(d) == 0) n_eepro++; + else + break; } return n_eepro ? 0 : -ENODEV; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.3.99-pre5/linux/drivers/net/eepro100.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/net/eepro100.c Fri Apr 21 16:08:45 2000 @@ -1285,7 +1285,7 @@ del_timer(&sp->timer); end_bh_atomic(); #else /* LINUX_VERSION_CODE */ -#ifdef __SMP__ +#ifdef CONFIG_SMP del_timer_sync(&sp->timer); #else /* SMP */ del_timer(&sp->timer); @@ -2258,7 +2258,6 @@ /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c --- v2.3.99-pre5/linux/drivers/net/hamradio/baycom_epp.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/hamradio/baycom_epp.c Wed Apr 12 09:38:53 2000 @@ -1509,7 +1509,7 @@ static int __init baycom_epp_setup(char *str) { - static unsigned __initdata nr_dev = 0; + static unsigned __initlocaldata nr_dev = 0; int ints[2]; if (nr_dev >= NR_PORTS) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v2.3.99-pre5/linux/drivers/net/hp100.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/hp100.c Wed Apr 12 09:38:57 2000 @@ -1800,9 +1800,9 @@ donecount); #endif #ifdef LINUX_2_1 - dev_kfree_skb( lp->txrhead->skb ); + dev_kfree_skb_any( lp->txrhead->skb ); #else - dev_kfree_skb( lp->txrhead->skb, FREE_WRITE ); + dev_kfree_skb_any( lp->txrhead->skb, FREE_WRITE ); #endif lp->txrhead->skb=(void *)NULL; lp->txrhead=lp->txrhead->next; @@ -1960,9 +1960,9 @@ hp100_ints_on(); #ifdef LINUX_2_1 - dev_kfree_skb( skb ); + dev_kfree_skb_any( skb ); #else - dev_kfree_skb( skb, FREE_WRITE ); + dev_kfree_skb_any( skb, FREE_WRITE ); #endif #ifdef HP100_DEBUG_TX @@ -2198,9 +2198,9 @@ #endif if(ptr->skb!=NULL) #ifdef LINUX_2_1 - dev_kfree_skb( ptr->skb ); + dev_kfree_skb_any( ptr->skb ); #else - dev_kfree_skb( ptr->skb, FREE_READ ); + dev_kfree_skb_any( ptr->skb, FREE_READ ); #endif lp->stats.rx_errors++; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c --- v2.3.99-pre5/linux/drivers/net/ne2k-pci.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/ne2k-pci.c Fri Apr 21 16:27:21 2000 @@ -188,9 +188,10 @@ return -ENODEV; } - if (pci_enable_device (pdev)) { + i = pci_enable_device (pdev); + if (i) { printk (KERN_ERR "ne2k-pci: cannot enable device\n"); - return -EIO; + return i; } if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) { @@ -292,6 +293,7 @@ /* Set up the rest of the parameters. */ dev->irq = irq; dev->base_addr = ioaddr; + pdev->driver_data = dev; /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/pcmcia/3c575_cb.c linux/drivers/net/pcmcia/3c575_cb.c --- v2.3.99-pre5/linux/drivers/net/pcmcia/3c575_cb.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/pcmcia/3c575_cb.c Wed Dec 31 16:00:00 1969 @@ -1,2159 +0,0 @@ -/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */ -/* - Written 1996-1999 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. - - This driver is for the 3Com "Vortex" and "Boomerang" series ethercards. - Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597 - and the EtherLink XL 3c900 and 3c905 cards. - - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - - Linux Kernel Additions: - - LK1.1.2 (March 19, 2000) - * New PCI interface (jgarzik) - -*/ - -static char *version = -"3c575_cb.c:v0.99L+LK1.1.2 3/19/2000 Donald Becker and others http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; - -/* "Knobs" that adjust features and parameters. */ -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. - Setting to > 1512 effectively disables this feature. */ -static const int rx_copybreak = 200; -/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */ -static const int mtu = 1500; -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 32; - -/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */ -#define vortex_debug debug -#ifdef VORTEX_DEBUG -static int vortex_debug = VORTEX_DEBUG; -#else -static int vortex_debug = 1; -#endif - -/* Some values here only for performance evaluation and path-coverage - debugging. */ -static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; - -/* A few values that may be tweaked. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT ((400*HZ)/1000) - -/* Keep the ring sizes a power of two for efficiency. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 32 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ - -#ifndef __OPTIMIZE__ -#warning You must compile this file with the correct options! -#warning See the last lines of the source file. -#error You must compile this driver with "-O". -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For NR_IRQS only. */ -#include -#include - -/* Kernel compatibility defines, some common to David Hinds' PCMCIA package. - This is only in the support-all-kernels source code. */ - -#define RUN_AT(x) (jiffies + (x)) - -#include - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); -MODULE_PARM(debug, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(max_interrupt_work, "i"); - -/* Operational parameter that usually are not changed. */ - -/* The Vortex size is twice that of the original EtherLinkIII series: the - runtime register window, window 1, is now always mapped in. - The Boomerang size is twice as large as the Vortex -- it has additional - bus master control registers. */ -#define VORTEX_TOTAL_SIZE 0x20 -#define BOOMERANG_TOTAL_SIZE 0x40 - -/* Set iff a MII transceiver on any interface requires mdio preamble. - This only set with the original DP83840 on older 3c905 boards, so the extra - code size of a per-interface flag is not worthwhile. */ -static char mii_preamble_required = 0; - -#define PFX "3c575_cb: " - - - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the 3Com FastEtherLink and FastEtherLink -XL, 3Com's PCI to 10/100baseT adapters. It also works with the 10Mbs -versions of the FastEtherLink cards. The supported product IDs are - 3c590, 3c592, 3c595, 3c597, 3c900, 3c905 - -The related ISA 3c515 is supported with a separate driver, 3c515.c, included -with the kernel source or available from - cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS should be set to assign the -PCI INTA signal to an otherwise unused system IRQ line. - -The EEPROM settings for media type and forced-full-duplex are observed. -The EEPROM media type should be left at the default "autoselect" unless using -10base2 or AUI connections which cannot be reliably detected. - -III. Driver operation - -The 3c59x series use an interface that's very similar to the previous 3c5x9 -series. The primary interface is two programmed-I/O FIFOs, with an -alternate single-contiguous-region bus-master transfer (see next). - -The 3c900 "Boomerang" series uses a full-bus-master interface with separate -lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet, -DEC Tulip and Intel Speedo3. The first chip version retains a compatible -programmed-I/O interface that has been removed in 'B' and subsequent board -revisions. - -One extension that is advertised in a very large font is that the adapters -are capable of being bus masters. On the Vortex chip this capability was -only for a single contiguous region making it far less useful than the full -bus master capability. There is a significant performance impact of taking -an extra interrupt or polling for the completion of each transfer, as well -as difficulty sharing the single transfer engine between the transmit and -receive threads. Using DMA transfers is a win only with large blocks or -with the flawed versions of the Intel Orion motherboard PCI controller. - -The Boomerang chip's full-bus-master interface is useful, and has the -currently-unused advantages over other similar chips that queued transmit -packets may be reordered and receive buffer groups are associated with a -single frame. - -With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme. -Rather than a fixed intermediate receive buffer, this scheme allocates -full-sized skbuffs as receive buffers. The value RX_COPYBREAK is used as -the copying breakpoint: it is chosen to trade-off the memory wasted by -passing the full-sized skbuff to the queue layer for all frames vs. the -copying cost of copying a frame to a correctly-sized skbuff. - -IIIC. Synchronization -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and other software. - -IV. Notes - -Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing development -3c590, 3c595, and 3c900 boards. -The name "Vortex" is the internal 3Com project name for the PCI ASIC, and -the EISA version is called "Demon". According to Terry these names come -from rides at the local amusement park. - -The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes! -This driver only supports ethernet packets because of the skbuff allocation -limit of 4K. -*/ - -/* This table drives the PCI probe routines. It's mostly boilerplate in all - of the drivers, and will likely be provided by some future kernel. -*/ -enum pci_flags_bit { - PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, - PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, -}; - -enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, - HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; - - -enum vortex_chips { - CH_3C590 = 0, - CH_3C595_1, - CH_3C595_2, - CH_3C595_3, - CH_VORTEX, - CH_3C900_1, - CH_3C900_2, - CH_3C900_3, - CH_3C900B_FL, - CH_3C905_1, - CH_3C905_2, - CH_3C905B_1, - CH_3C905B_2, - CH_3C905B_FX, - CH_3C905C, - CH_3C980, - CH_3CSOHO100_TX, - CH_3C555, - CH_3C575_1, - CH_3CCFE575, - CH_3CCFE575CT, - CH_3CCFE656, - CH_3CCFEM656, - CH_3C575_2, - CH_BOOMERANG, -}; - - -/* note: this array directly indexed by above enums, and MUST - * be kept in sync with both the enums above, and the PCI device - * table below - */ -static struct vortex_chip_info { - const char *name; - int flags; - int drv_flags; - int io_size; -} vortex_info_tbl[] = { - {"3c590 Vortex 10Mbps", - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c595 Vortex 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c595 Vortex 100baseT4", - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c595 Vortex 100base-MII", - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3Com Vortex", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, - {"3c900 Boomerang 10baseT", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, - {"3c900 Boomerang 10Mbps Combo", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, - {"3c900 Cyclone 10Mbps Combo", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, - {"3c900B-FL Cyclone 10base-FL", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, - {"3c905 Boomerang 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, - {"3c905 Boomerang 100baseT4", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, - {"3c905B Cyclone 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, - {"3c905B Cyclone 10/100/BNC", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, - {"3c905B-FX Cyclone 100baseFx", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, - {"3c905C Tornado", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, - {"3c980 Cyclone", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, - {"3cSOHO100-TX Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, - {"3c555 Laptop Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, - {"3c575 Boomerang CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, - {"3CCFE575 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, - {"3CCFE575CT Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, - {"3CCFE656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, - {"3CCFEM656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, - {"3c575 series CardBus (unknown version)", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, - {"3Com Boomerang (unknown version)", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, - {0,}, /* 0 terminated list. */ -}; - - -static struct pci_device_id vortex_pci_tbl[] __devinit = { - { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 }, - { 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 }, - { 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 }, - { 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 }, - { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX }, - { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 }, - { 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 }, - { 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 }, - { 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL }, - { 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 }, - { 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 }, - { 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 }, - { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 }, - { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX }, - { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C }, - { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 }, - { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX }, - { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 }, - { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 }, - { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, - { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, - { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 }, - { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 }, - { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_2 }, - { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_BOOMERANG }, - {0,}, /* 0 terminated list. */ -}; -MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); - - -/* Operational definitions. - These are not used by other compilation units and thus are not - exported in a ".h" file. - - First the windows. There are eight register windows, with the command - and status registers available in each. - */ -#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) -#define EL3_CMD 0x0e -#define EL3_STATUS 0x0e - -/* The top five bits written to EL3_CMD are a command, the lower - 11 bits are the parameter, if applicable. - Note that 11 parameters bits was fine for ethernet, but the new chip - can handle FDDI length frames (~4500 octets) and now parameters count - 32-bit 'Dwords' rather than octets. */ - -enum vortex_cmd { - TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11, - RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, - UpStall = 6<<11, UpUnstall = (6<<11)+1, - DownStall = (6<<11)+2, DownUnstall = (6<<11)+3, - RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11, - FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11, - SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11, - SetTxThreshold = 18<<11, SetTxStart = 19<<11, - StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11, - StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11,}; - -/* The SetRxFilter command accepts the following classes: */ -enum RxFilter { - RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 }; - -/* Bits in the general status register. */ -enum vortex_status { - IntLatch = 0x0001, HostError = 0x0002, TxComplete = 0x0004, - TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020, - IntReq = 0x0040, StatsFull = 0x0080, - DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10, - DMAInProgress = 1<<11, /* DMA controller is still busy.*/ - CmdInProgress = 1<<12, /* EL3_CMD is still busy.*/ -}; - -/* Register window 1 offsets, the window used in normal operation. - On the Vortex this window is always mapped at offsets 0x10-0x1f. */ -enum Window1 { - TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14, - RxStatus = 0x18, Timer=0x1A, TxStatus = 0x1B, - TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */ -}; -enum Window0 { - Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */ - Wn0EepromData = 12, /* Window 0: EEPROM results register. */ - IntrStatus=0x0E, /* Valid in all windows. */ -}; -enum Win0_EEPROM_bits { - EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0, - EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */ - EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */ -}; -/* EEPROM locations. */ -enum eeprom_offset { - PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3, - EtherLink3ID=7, IFXcvrIO=8, IRQLine=9, - NodeAddr01=10, NodeAddr23=11, NodeAddr45=12, - DriverTune=13, Checksum=15}; - -enum Window2 { /* Window 2. */ - Wn2_ResetOptions=12, -}; -enum Window3 { /* Window 3: MAC/config bits. */ - Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, -}; -union wn3_config { - int i; - struct w3_config_fields { - unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; - int pad8:8; - unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1; - int pad24:7; - } u; -}; - -enum Window4 { /* Window 4: Xcvr/media bits. */ - Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10, -}; -enum Win4_Media_bits { - Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */ - Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */ - Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */ - Media_LnkBeat = 0x0800, -}; -enum Window7 { /* Window 7: Bus Master control. */ - Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12, -}; -/* Boomerang bus master control registers. */ -enum MasterCtrl { - PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c, - TxFreeThreshold = 0x2f, UpPktStatus = 0x30, UpListPtr = 0x38, -}; - -/* The Rx and Tx descriptor lists. - Caution Alpha hackers: these types are 32 bits! Note also the 8 byte - alignment contraint on tx_ring[] and rx_ring[]. */ -#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */ -struct boom_rx_desc { - u32 next; /* Last entry points to 0. */ - s32 status; - u32 addr; /* Up to 63 addr/len pairs possible. */ - s32 length; /* Set LAST_FRAG to indicate last pair. */ -}; -/* Values for the Rx status entry. */ -enum rx_desc_status { - RxDComplete=0x00008000, RxDError=0x4000, - /* See boomerang_rx() for actual error bits */ - IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27, - IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31, -}; - -struct boom_tx_desc { - u32 next; /* Last entry points to 0. */ - s32 status; /* bits 0:12 length, others see below. */ - u32 addr; - s32 length; -}; - -/* Values for the Tx status entry. */ -enum tx_desc_status { - CRCDisable=0x2000, TxDComplete=0x8000, - AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000, - TxIntrUploaded=0x80000000, /* IRQ when in FIFO, but maybe not sent. */ -}; - -/* Chip features we care about in vp->capabilities, read from the EEPROM. */ -enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 }; - -struct vortex_private { - /* The Rx and Tx rings should be quad-word-aligned. */ - struct boom_rx_desc rx_ring[RX_RING_SIZE]; - struct boom_tx_desc tx_ring[TX_RING_SIZE]; - /* The addresses of transmit- and receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - struct net_device *next_module; /* NULL if PCI device */ - void *priv_addr; - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - struct net_device_stats stats; - struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ - - /* PCI configuration space information. */ - struct pci_dev *pdev; - char *cb_fn_base; /* CardBus function status addr space. */ - int chip_id; - - /* The remainder are related to chip state, mostly media selection. */ - unsigned long in_interrupt; - struct timer_list timer; /* Media selection timer. */ - int options; /* User-settable misc. driver options. */ - unsigned int media_override:4, /* Passed-in media type. */ - default_media:4, /* Read from the EEPROM/Wn3_Config. */ - full_duplex:1, force_fd:1, autoselect:1, - bus_master:1, /* Vortex can only do a fragment bus-m. */ - full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ - hw_csums:1, /* Has hardware checksums. */ - tx_full:1, - open:1, - reap:1; - u16 status_enable; - u16 intr_enable; - u16 available_media; /* From Wn3_Options. */ - u16 capabilities, info1, info2; /* Various, from EEPROM. */ - u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ - u16 deferred; - spinlock_t lock; -}; - -/* The action to take with a media selection timer tick. - Note that we deviate from the 3Com order by checking 10base2 before AUI. - */ -enum xcvr_types { - XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx, - XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10, -}; - -static struct media_table { - char *name; - unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ - mask:8, /* The transceiver-present bit in Wn3_Config.*/ - next:8; /* The media type to try next. */ - int wait; /* Time before we check media status. */ -} media_tbl[] = { - { "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10}, - { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10}, - { "undefined", 0, 0x80, XCVR_10baseT, 10000}, - { "10base2", 0, 0x10, XCVR_AUI, (1*HZ)/10}, - { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10}, - { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10}, - { "MII", 0, 0x41, XCVR_10baseT, 3*HZ }, - { "undefined", 0, 0x01, XCVR_10baseT, 10000}, - { "Autonegotiate", 0, 0x41, XCVR_10baseT, 3*HZ}, - { "MII-External", 0, 0x41, XCVR_10baseT, 3*HZ }, - { "Default", 0, 0xFF, XCVR_10baseT, 10000}, -}; - -static int vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq, - int chip_idx, int card_idx); -static void vortex_up(struct net_device *dev); -static void vortex_down(struct net_device *dev); -static int vortex_open(struct net_device *dev); -static void mdio_sync(long ioaddr, int bits); -static int mdio_read(long ioaddr, int phy_id, int location); -static void mdio_write(long ioaddr, int phy_id, int location, int value); -static void vortex_timer(unsigned long arg); -static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int vortex_rx(struct net_device *dev); -static int boomerang_rx(struct net_device *dev); -static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int vortex_close(struct net_device *dev); -static void update_stats(long ioaddr, struct net_device *dev); -static struct net_device_stats *vortex_get_stats(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void vortex_tx_timeout(struct net_device *dev); -static void acpi_set_WOL(struct net_device *dev); - -/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ -/* Option count limit only -- unlimited interfaces are supported. */ -#define MAX_UNITS 8 -static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; - - -/* A list of all installed Vortex EISA devices, for removing the driver module. */ -static struct net_device *root_vortex_eisa_dev = NULL; - -static int vortex_cards_found = 0; - - - - -static void vortex_suspend (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name); - - if (dev && dev->priv) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; - if (vp->open) { - netif_device_detach(dev); - vortex_down(dev); - } - } -} - - -static void vortex_resume (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name); - - if (dev && dev->priv) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; - if (vp->open) { - vortex_up(dev); - netif_device_attach(dev); - } - } -} - - -/* returns count found (>= 0), or negative on error */ -static int __init vortex_eisa_init (void) -{ - long ioaddr; - int rc; - int orig_cards_found = vortex_cards_found; - - /* Now check all slots of the EISA bus. */ - if (!EISA_bus) - return 0; - - for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { - int device_id; - - if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL) - continue; - - /* Check the standard EISA ID register for an encoded '3Com'. */ - if (inw(ioaddr + 0xC80) != 0x6d50) { - release_region (ioaddr, VORTEX_TOTAL_SIZE); - continue; - } - - /* Check for a product that we support, 3c59{2,7} any rev. */ - device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); - if ((device_id & 0xFF00) != 0x5900) { - release_region (ioaddr, VORTEX_TOTAL_SIZE); - continue; - } - - rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12, - 4, /* XXX is 4 correct eisa idx? */ - vortex_cards_found); - if (rc == 0) - vortex_cards_found++; - else - release_region (ioaddr, VORTEX_TOTAL_SIZE); - } - - return vortex_cards_found - orig_cards_found; -} - - -/* returns count (>= 0), or negative on error */ -static int __devinit vortex_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int rc; - - rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq, - ent->driver_data, vortex_cards_found); - if (rc == 0) - vortex_cards_found++; - - return rc; -} - - -/* NOTE: pdev can be NULL, for the case of an EISA driver */ -static int __devinit vortex_probe1(struct pci_dev *pdev, - long ioaddr, int irq, - int chip_idx, int card_idx) -{ - struct vortex_private *vp; - int option; - unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ - int i; - struct net_device *dev; - static int printed_version = 0; - - if (!printed_version) { - printk (KERN_INFO "%s", version); - printed_version = 1; - } - - dev = init_etherdev(NULL, sizeof(*vp)); - if (!dev) { - printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); - return -ENOMEM; - } - - printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ", - dev->name, - pdev ? "PCI" : "EISA", - vortex_info_tbl[chip_idx].name, - ioaddr); - - /* private struct aligned and zeroed by init_etherdev */ - vp = dev->priv; - vp->priv_addr = vp; - dev->base_addr = ioaddr; - dev->irq = irq; - dev->mtu = mtu; - - /* module list only for EISA devices */ - if (pdev == NULL) { - vp->next_module = root_vortex_eisa_dev; - root_vortex_eisa_dev = dev; - } - - /* PCI-only startup logic */ - if (pdev) { - /* EISA resources already marked, so only PCI needs to do this here */ - if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size, - dev->name)) { - printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n", - dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr); - kfree (dev); - return -EBUSY; - } - - /* wake up and enable device */ - if (pci_enable_device (pdev)) { - printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name); - release_region (ioaddr, vortex_info_tbl[chip_idx].io_size); - kfree (dev); - return -EIO; - } - - /* enable bus-mastering if necessary */ - if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER) - pci_set_master (pdev); - } - - vp->lock = SPIN_LOCK_UNLOCKED; - vp->chip_id = chip_idx; - vp->pdev = pdev; - - /* if we are a PCI driver, we store info in pdev->driver_data - * instead of a module list */ - if (pdev) - pdev->driver_data = dev; - - /* The lower four bits are the media type. */ - if (dev->mem_start) - option = dev->mem_start; - else if (card_idx < MAX_UNITS) - option = options[card_idx]; - else - option = -1; - - if (option >= 0) { - vp->media_override = ((option & 7) == 2) ? 0 : option & 15; - vp->full_duplex = (option & 0x200) ? 1 : 0; - vp->bus_master = (option & 16) ? 1 : 0; - } else { - vp->media_override = 7; - vp->full_duplex = 0; - vp->bus_master = 0; - } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - vp->full_duplex = 1; - - vp->force_fd = vp->full_duplex; - vp->options = option; - - /* Read the station address from the EEPROM. */ - EL3WINDOW(0); - for (i = 0; i < 0x40; i++) { - int timer; -#if 1 /* ifdef CARDBUS */ - outw(0x230 + i, ioaddr + Wn0EepromCmd); -#else - outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); -#endif - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 10; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) - break; - } - eeprom[i] = inw(ioaddr + Wn0EepromData); - } - for (i = 0; i < 0x18; i++) - checksum ^= eeprom[i]; - checksum = (checksum ^ (checksum >> 8)) & 0xff; - if (checksum != 0x00) { /* Grrr, needless incompatible change 3Com. */ - while (i < 0x21) - checksum ^= eeprom[i++]; - checksum = (checksum ^ (checksum >> 8)) & 0xff; - } - if (checksum != 0x00) - printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); - - for (i = 0; i < 3; i++) - ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); - for (i = 0; i < 6; i++) - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); - EL3WINDOW(2); - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - -#ifdef __sparc__ - printk(", IRQ %s\n", __irq_itoa(dev->irq)); -#else - printk(", IRQ %d\n", dev->irq); - /* Tell them about an invalid IRQ. */ - if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS)) - printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n", - dev->irq); -#endif - - if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { - u32 fn_st_addr; /* Cardbus function status space */ - fn_st_addr = pci_resource_start (pdev, 2); - if (fn_st_addr) - vp->cb_fn_base = ioremap(fn_st_addr, 128); - printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p\n", - dev->name, fn_st_addr, vp->cb_fn_base); - } - - /* Extract our information from the EEPROM data. */ - vp->info1 = eeprom[13]; - vp->info2 = eeprom[15]; - vp->capabilities = eeprom[16]; - - if (vp->info1 & 0x8000) - vp->full_duplex = 1; - - { - char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; - union wn3_config config; - EL3WINDOW(3); - vp->available_media = inw(ioaddr + Wn3_Options); - if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */ - vp->available_media = 0x40; - config.i = inl(ioaddr + Wn3_Config); - if (vortex_debug > 1) - printk(KERN_DEBUG " Internal config register is %4.4x, " - "transceivers %#x.\n", config.i, inw(ioaddr + Wn3_Options)); - printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", - 8 << config.u.ram_size, - config.u.ram_width ? "word" : "byte", - ram_split[config.u.ram_split], - config.u.autoselect ? "autoselect/" : "", - config.u.xcvr > XCVR_ExtMII ? "" : - media_tbl[config.u.xcvr].name); - vp->default_media = config.u.xcvr; - vp->autoselect = config.u.autoselect; - } - - if (vp->media_override != 7) { - printk(KERN_INFO " Media override to transceiver type %d (%s).\n", - vp->media_override, media_tbl[vp->media_override].name); - dev->if_port = vp->media_override; - } else - dev->if_port = vp->default_media; - - if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { - int phy, phy_idx = 0; - EL3WINDOW(4); - mii_preamble_required++; - mii_preamble_required++; - mdio_read(ioaddr, 24, 1); - for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) { - int mii_status, phyx = phy & 0x1f; - mii_status = mdio_read(ioaddr, phyx, 1); - if (mii_status && mii_status != 0xffff) { - vp->phys[phy_idx++] = phyx; - printk(KERN_INFO " MII transceiver found at address %d," - " status %4x.\n", phyx, mii_status); - if ((mii_status & 0x0040) == 0) - mii_preamble_required++; - } - } - mii_preamble_required--; - if (phy_idx == 0) { - printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n"); - vp->phys[0] = 24; - } else { - vp->advertising = mdio_read(ioaddr, vp->phys[0], 4); - if (vp->full_duplex) { - /* Only advertise the FD media types. */ - vp->advertising &= ~0x02A0; - mdio_write(ioaddr, vp->phys[0], 4, vp->advertising); - } - } - } - - if (vp->capabilities & CapPwrMgmt) - acpi_set_WOL(dev); - - if (vp->capabilities & CapBusMaster) { - vp->full_bus_master_tx = 1; - printk(KERN_INFO" Enabling bus-master transmits and %s receives.\n", - (vp->info2 & 1) ? "early" : "whole-frame" ); - vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2; - } - - /* The 3c59x-specific entries in the device structure. */ - dev->open = &vortex_open; - dev->hard_start_xmit = &vortex_start_xmit; - dev->stop = &vortex_close; - dev->get_stats = &vortex_get_stats; - dev->do_ioctl = &vortex_ioctl; - dev->set_multicast_list = &set_rx_mode; - dev->tx_timeout = &vortex_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - return 0; -} - -static void wait_for_completion(struct net_device *dev, int cmd) -{ - int i = 2000; - outw(cmd, dev->base_addr + EL3_CMD); - while (--i > 0) - if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) - break; - if (i == 0) - printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n", - dev->name, cmd); -} - -static void -vortex_up(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct vortex_private *vp = (struct vortex_private *)dev->priv; - union wn3_config config; - int i, device_id; - - if (vp->pdev) - device_id = vp->pdev->device; - else - device_id = 0x5900; /* EISA */ - - /* Before initializing select the active media port. */ - EL3WINDOW(3); - config.i = inl(ioaddr + Wn3_Config); - - if (vp->media_override != 7) { - if (vortex_debug > 1) - printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", - dev->name, vp->media_override, - media_tbl[vp->media_override].name); - dev->if_port = vp->media_override; - } else if (vp->autoselect) { - if (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY) - dev->if_port = XCVR_NWAY; - else { - /* Find first available media type, starting with 100baseTx. */ - dev->if_port = XCVR_100baseTx; - while (! (vp->available_media & media_tbl[dev->if_port].mask)) - dev->if_port = media_tbl[dev->if_port].next; - } - } else - dev->if_port = vp->default_media; - - init_timer(&vp->timer); - vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); - vp->timer.data = (unsigned long)dev; - vp->timer.function = &vortex_timer; /* timer handler */ - add_timer(&vp->timer); - - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Initial media type %s.\n", - dev->name, media_tbl[dev->if_port].name); - - vp->full_duplex = vp->force_fd; - config.u.xcvr = dev->if_port; - if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY)) - outl(config.i, ioaddr + Wn3_Config); - - if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { - int mii_reg1, mii_reg5; - EL3WINDOW(4); - /* Read BMSR (reg1) only to clear old status. */ - mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1); - mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); - if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) - ; /* No MII device or no link partner report */ - else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ - || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ - vp->full_duplex = 1; - if (vortex_debug > 1) - printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," - " setting %s-duplex.\n", dev->name, vp->phys[0], - mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half"); - EL3WINDOW(3); - } - - /* Set the full-duplex bit. */ - outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); - - if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n", - dev->name, config.i); - } - - wait_for_completion(dev, TxReset); - wait_for_completion(dev, RxReset); - - outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); - - if (vortex_debug > 1) { - EL3WINDOW(4); - printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n", - dev->name, dev->irq, inw(ioaddr + Wn4_Media)); - } - - /* Set the station address and mask in window 2 each time opened. */ - EL3WINDOW(2); - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - for (; i < 12; i+=2) - outw(0, ioaddr + i); - if (vp->cb_fn_base) { - u_short n = inw(ioaddr + Wn2_ResetOptions); - /* Inverted LED polarity */ - if (device_id != 0x5257) - n |= 0x0010; - /* Inverted polarity of MII power bit */ - if ((device_id == 0x6560) || (device_id == 0x6562) || - (device_id == 0x5257)) - n |= 0x4000; - outw(n, ioaddr + Wn2_ResetOptions); - } - - if (dev->if_port == XCVR_10base2) - /* Start the thinnet transceiver. We should really wait 50ms...*/ - outw(StartCoax, ioaddr + EL3_CMD); - if (dev->if_port != XCVR_NWAY) { - EL3WINDOW(4); - outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | - media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); - } - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i = 0; i < 10; i++) - inb(ioaddr + i); - inw(ioaddr + 10); - inw(ioaddr + 12); - /* New: On the Vortex we must also clear the BadSSD counter. */ - EL3WINDOW(4); - inb(ioaddr + 12); - /* ..and on the Boomerang we enable the extra statistics bits. */ - outw(0x0040, ioaddr + Wn4_NetDiag); - - /* Switch to register set 7 for normal use. */ - EL3WINDOW(7); - - if (vp->full_bus_master_rx) { /* Boomerang bus master. */ - vp->cur_rx = vp->dirty_rx = 0; - /* Initialize the RxEarly register as recommended. */ - outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD); - outl(0x0020, ioaddr + PktStatus); - outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); - } - if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ - dev->hard_start_xmit = &boomerang_start_xmit; - vp->cur_tx = vp->dirty_tx = 0; - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ - /* Clear the Rx, Tx rings. */ - for (i = 0; i < RX_RING_SIZE; i++) - vp->rx_ring[i].status = 0; - for (i = 0; i < TX_RING_SIZE; i++) - vp->tx_skbuff[i] = 0; - outl(0, ioaddr + DownListPtr); - } - /* Set receiver mode: presumably accept b-case and phys addr only. */ - set_rx_mode(dev); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - - vp->in_interrupt = 0; - netif_start_queue (dev); - - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete| - (vp->full_bus_master_tx ? DownComplete : TxAvailable) | - (vp->full_bus_master_rx ? UpComplete : RxComplete) | - (vp->bus_master ? DMADone : 0); - vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete | - StatsFull | HostError | TxComplete | IntReq - | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete; - outw(vp->status_enable, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(vp->intr_enable, ioaddr + EL3_CMD); - if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ - writel(0x8000, vp->cb_fn_base + 4); -} - -static int -vortex_open(struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - int i; - -#ifdef CARDBUS - if (vp->reap) - return -ENODEV; -#endif - /* Use the now-standard shared IRQ implementation. */ - if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) { - return -EAGAIN; - } - - if (vp->full_bus_master_rx) { /* Boomerang bus master. */ - if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name); - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1])); - vp->rx_ring[i].status = 0; /* Clear complete bit. */ - vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG); - skb = dev_alloc_skb(PKT_BUF_SZ); - vp->rx_skbuff[i] = skb; - if (skb == NULL) - break; /* Bad news! */ - skb->dev = dev; /* Mark as being used by this device. */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail)); - } - /* Wrap the ring. */ - vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0])); - } - if (vp->full_bus_master_tx) - dev->hard_start_xmit = &boomerang_start_xmit; - - vortex_up(dev); - vp->open = 1; - MOD_INC_USE_COUNT; - - return 0; -} - -static void vortex_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - int ok = 0; - int media_status, mii_status, old_window; - - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", - dev->name, media_tbl[dev->if_port].name); - - disable_irq(dev->irq); - old_window = inw(ioaddr + EL3_CMD) >> 13; - EL3WINDOW(4); - media_status = inw(ioaddr + Wn4_Media); - switch (dev->if_port) { - case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx: - if (media_status & Media_LnkBeat) { - ok = 1; - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); - } else if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); - break; - case XCVR_MII: case XCVR_NWAY: - mii_status = mdio_read(ioaddr, vp->phys[0], 1); - ok = 1; - if (debug > 1) - printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", - dev->name, mii_status); - if (mii_status & 0x0004) { - int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); - if (! vp->force_fd && mii_reg5 != 0xffff) { - int duplex = (mii_reg5&0x0100) || - (mii_reg5 & 0x01C0) == 0x0040; - if (vp->full_duplex != duplex) { - vp->full_duplex = duplex; - printk(KERN_INFO "%s: Setting %s-duplex based on MII " - "#%d link partner capability of %4.4x.\n", - dev->name, vp->full_duplex ? "full" : "half", - vp->phys[0], mii_reg5); - /* Set the full-duplex bit. */ - EL3WINDOW(3); - outb((vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), - ioaddr + Wn3_MAC_Ctrl); - } - next_tick = 60*HZ; - } - } - break; - default: /* Other media types handled by Tx timeouts. */ - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); - ok = 1; - } - if ( ! ok) { - union wn3_config config; - - do { - dev->if_port = media_tbl[dev->if_port].next; - } while ( ! (vp->available_media & media_tbl[dev->if_port].mask)); - if (dev->if_port == XCVR_Default) { /* Go back to default. */ - dev->if_port = vp->default_media; - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media selection failing, using default " - "%s port.\n", - dev->name, media_tbl[dev->if_port].name); - } else { - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media selection failed, now trying " - "%s port.\n", - dev->name, media_tbl[dev->if_port].name); - next_tick = media_tbl[dev->if_port].wait; - } - outw((media_status & ~(Media_10TP|Media_SQE)) | - media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); - - EL3WINDOW(3); - config.i = inl(ioaddr + Wn3_Config); - config.u.xcvr = dev->if_port; - outl(config.i, ioaddr + Wn3_Config); - - outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax, - ioaddr + EL3_CMD); - } - EL3WINDOW(old_window); - enable_irq(dev->irq); - - if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", - dev->name, media_tbl[dev->if_port].name); - - vp->timer.expires = RUN_AT(next_tick); - add_timer(&vp->timer); - if (vp->deferred) - outw(FakeIntr, ioaddr + EL3_CMD); - return; -} - -static void vortex_tx_timeout(struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - - printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", - dev->name, inb(ioaddr + TxStatus), - inw(ioaddr + EL3_STATUS)); - /* Slight code bloat to be user friendly. */ - if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) - printk(KERN_ERR "%s: Transmitter encountered 16 collisions --" - " network cable problem?\n", dev->name); - if (inw(ioaddr + EL3_STATUS) & IntLatch) { - printk(KERN_ERR "%s: Interrupt posted but not delivered --" - " IRQ blocked by another device?\n", dev->name); - /* Bad idea here.. but we might as well handle a few events. */ - vortex_interrupt(dev->irq, dev, 0); - } - -#if ! defined(final_version) - if (vp->full_bus_master_tx) { - int i; - printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d " - "current %d.\n", - vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx); - printk(KERN_DEBUG " Transmit list %8.8x vs. %p.\n", - inl(ioaddr + DownListPtr), - &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); - for (i = 0; i < TX_RING_SIZE; i++) { - printk(KERN_DEBUG " %d: @%p length %8.8x status %8.8x\n", i, - &vp->tx_ring[i], - le32_to_cpu(vp->tx_ring[i].length), - le32_to_cpu(vp->tx_ring[i].status)); - } - } -#endif - wait_for_completion(dev, TxReset); - - vp->stats.tx_errors++; - if (vp->full_bus_master_tx) { - if (vortex_debug > 0) - printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", - dev->name); - if (vp->cur_tx - vp->dirty_tx > 0 && inl(ioaddr + DownListPtr) == 0) - outl(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]), - ioaddr + DownListPtr); - if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) { - vp->tx_full = 0; - netif_start_queue (dev); - } - if (vp->tx_full) - netif_stop_queue (dev); - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); - outw(DownUnstall, ioaddr + EL3_CMD); - } else - vp->stats.tx_dropped++; - - /* Issue Tx Enable */ - outw(TxEnable, ioaddr + EL3_CMD); - dev->trans_start = jiffies; - - /* Switch to register set 7 for normal use. */ - EL3WINDOW(7); -} - -/* - * Handle uncommon interrupt sources. This is a separate routine to minimize - * the cache impact. - */ -static void -vortex_error(struct net_device *dev, int status) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - int do_tx_reset = 0; - - if (status & TxComplete) { /* Really "TxError" for us. */ - unsigned char tx_status = inb(ioaddr + TxStatus); - /* Presumably a tx-timeout. We must merely re-enable. */ - if (vortex_debug > 2 - || (tx_status != 0x88 && vortex_debug > 0)) - printk(KERN_DEBUG"%s: Transmit error, Tx status register %2.2x.\n", - dev->name, tx_status); - if (tx_status & 0x14) vp->stats.tx_fifo_errors++; - if (tx_status & 0x38) vp->stats.tx_aborted_errors++; - outb(0, ioaddr + TxStatus); - if (tx_status & 0x30) - do_tx_reset = 1; - else /* Merely re-enable the transmitter. */ - outw(TxEnable, ioaddr + EL3_CMD); - } - if (status & RxEarly) { /* Rx early is unused. */ - vortex_rx(dev); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); - } - if (status & StatsFull) { /* Empty statistics. */ - static int DoneDidThat = 0; - if (vortex_debug > 4) - printk(KERN_DEBUG "%s: Updating stats.\n", dev->name); - update_stats(ioaddr, dev); - /* HACK: Disable statistics as an interrupt source. */ - /* This occurs when we have the wrong media type! */ - if (DoneDidThat == 0 && - inw(ioaddr + EL3_STATUS) & StatsFull) { - printk(KERN_WARNING "%s: Updating statistics failed, disabling " - "stats as an interrupt source.\n", dev->name); - EL3WINDOW(5); - outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD); - EL3WINDOW(7); - DoneDidThat++; - } - } - if (status & IntReq) { /* Restore all interrupt sources. */ - outw(vp->status_enable, ioaddr + EL3_CMD); - outw(vp->intr_enable, ioaddr + EL3_CMD); - } - if (status & HostError) { - u16 fifo_diag; - EL3WINDOW(4); - fifo_diag = inw(ioaddr + Wn4_FIFODiag); - printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n", - dev->name, fifo_diag); - /* Adapter failure requires Tx/Rx reset and reinit. */ - if (vp->full_bus_master_tx) { - /* In this case, blow the card away */ - vortex_down(dev); - wait_for_completion(dev, TotalReset | 0xff); - vortex_up(dev); - } else if (fifo_diag & 0x0400) - do_tx_reset = 1; - if (fifo_diag & 0x3000) { - wait_for_completion(dev, RxReset); - /* Set the Rx filter to the current state. */ - set_rx_mode(dev); - outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ - outw(AckIntr | HostError, ioaddr + EL3_CMD); - } - } - if (do_tx_reset) { - wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - } - -} - -static int -vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - - netif_stop_queue (dev); - - /* Put out the doubleword header... */ - outl(skb->len, ioaddr + TX_FIFO); - if (vp->bus_master) { - /* Set the bus-master controller to transfer the packet. */ - outl(virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr); - outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); - vp->tx_skb = skb; - outw(StartDMADown, ioaddr + EL3_CMD); - /* dev->tbusy will be cleared at the DMADone interrupt. */ - } else { - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb (skb); - if (inw(ioaddr + TxFree) > 1536) { - netif_start_queue (dev); - } else - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); - } - - dev->trans_start = jiffies; - - /* Clear the Tx status stack. */ - { - int tx_status; - int i = 32; - - while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { - if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ - if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n", - dev->name, tx_status); - if (tx_status & 0x04) vp->stats.tx_fifo_errors++; - if (tx_status & 0x38) vp->stats.tx_aborted_errors++; - if (tx_status & 0x30) { - wait_for_completion(dev, TxReset); - } - outw(TxEnable, ioaddr + EL3_CMD); - } - outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ - } - } - return 0; -} - -static int -boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - - netif_stop_queue (dev); - if (1) { - /* Calculate the next Tx descriptor entry. */ - int entry = vp->cur_tx % TX_RING_SIZE; - struct boom_tx_desc *prev_entry = - &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; - unsigned long flags; - - if (vortex_debug > 3) - printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", - dev->name, vp->cur_tx); - if (vp->tx_full) { - if (vortex_debug >0) - printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n", - dev->name); - return 1; - } - vp->tx_skbuff[entry] = skb; - vp->tx_ring[entry].next = 0; - vp->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data)); - vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); - vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); - - spin_lock_irqsave(&vp->lock, flags); - /* Wait for the stall to complete. */ - wait_for_completion(dev, DownStall); - prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry])); - if (inl(ioaddr + DownListPtr) == 0) { - outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr); - queued_packet++; - } - outw(DownUnstall, ioaddr + EL3_CMD); - spin_unlock_irqrestore(&vp->lock, flags); - - vp->cur_tx++; - if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) { - vp->tx_full = 1; - netif_stop_queue (dev); - } else { /* Clear previous interrupt enable. */ -#if defined(tx_interrupt_mitigation) - prev_entry->status &= cpu_to_le32(~TxIntrUploaded); -#endif - netif_start_queue (dev); - } - dev->trans_start = jiffies; - return 0; - } -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = dev_id; - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr; - int latency, status; - int work_done = max_interrupt_work; - - spin_lock (&vp->lock); - - ioaddr = dev->base_addr; - latency = inb(ioaddr + Timer); - status = inw(ioaddr + EL3_STATUS); - if (status & IntReq) { - status |= vp->deferred; - vp->deferred = 0; - } - - if (status == 0xffff) - goto handler_exit; - if (vortex_debug > 4) - printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", - dev->name, status, latency); - do { - if (vortex_debug > 5) - printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", - dev->name, status); - if (status & RxComplete) - vortex_rx(dev); - if (status & UpComplete) { - outw(AckIntr | UpComplete, ioaddr + EL3_CMD); - boomerang_rx(dev); - } - - if (status & TxAvailable) { - if (vortex_debug > 5) - printk(KERN_DEBUG " TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue (dev); - } - - if (status & DownComplete) { - unsigned int dirty_tx = vp->dirty_tx; - - outw(AckIntr | DownComplete, ioaddr + EL3_CMD); - while (vp->cur_tx - dirty_tx > 0) { - int entry = dirty_tx % TX_RING_SIZE; - if (inl(ioaddr + DownListPtr) == - virt_to_bus(&vp->tx_ring[entry])) - break; /* It still hasn't been processed. */ - if (vp->tx_skbuff[entry]) { - dev_kfree_skb_irq(vp->tx_skbuff[entry]); - vp->tx_skbuff[entry] = 0; - } - /* vp->stats.tx_packets++; Counted below. */ - dirty_tx++; - } - vp->dirty_tx = dirty_tx; - if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { - vp->tx_full = 0; - netif_wake_queue (dev); - } - } - if (vp->tx_full) - netif_stop_queue (dev); - if (status & DMADone) { - if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { - outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */ - if (inw(ioaddr + TxFree) > 1536) { - netif_wake_queue (dev); - } else { /* Interrupt when FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); - netif_stop_queue (dev); - } - } - } - /* Check for all uncommon interrupts at once. */ - if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { - if (status == 0xffff) - break; - vortex_error(dev, status); - } - - if (--work_done < 0) { - printk(KERN_WARNING "%s: Too much work in interrupt, status " - "%4.4x.\n", dev->name, status); - /* Disable all pending interrupts. */ - do { - vp->deferred |= status; - outw(SetStatusEnb | (~vp->deferred & vp->status_enable), - ioaddr + EL3_CMD); - outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); - } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch); - /* The timer will reenable interrupts. */ - del_timer(&vp->timer); - vp->timer.expires = RUN_AT(1); - add_timer(&vp->timer); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ - writel(0x8000, vp->cb_fn_base + 4); - - } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); - - if (vortex_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", - dev->name, status); -handler_exit: - spin_unlock (&vp->lock); -} - -static int vortex_rx(struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - int i; - short rx_status; - - if (vortex_debug > 5) - printk(KERN_DEBUG" In rx_packet(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); - while ((rx_status = inw(ioaddr + RxStatus)) > 0) { - if (rx_status & 0x4000) { /* Error, update stats. */ - unsigned char rx_error = inb(ioaddr + RxErrors); - if (vortex_debug > 2) - printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error); - vp->stats.rx_errors++; - if (rx_error & 0x01) vp->stats.rx_over_errors++; - if (rx_error & 0x02) vp->stats.rx_length_errors++; - if (rx_error & 0x04) vp->stats.rx_frame_errors++; - if (rx_error & 0x08) vp->stats.rx_crc_errors++; - if (rx_error & 0x10) vp->stats.rx_length_errors++; - } else { - /* The packet length: up to 4.5K!. */ - int pkt_len = rx_status & 0x1fff; - struct sk_buff *skb; - - skb = dev_alloc_skb(pkt_len + 5); - if (vortex_debug > 4) - printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - if (skb != NULL) { - skb->dev = dev; - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - /* 'skb_put()' points to the start of sk_buff data area. */ - if (vp->bus_master && - ! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) { - outl(virt_to_bus(skb_put(skb, pkt_len)), - ioaddr + Wn7_MasterAddr); - outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); - outw(StartDMAUp, ioaddr + EL3_CMD); - while (inw(ioaddr + Wn7_MasterStatus) & 0x8000) - ; - } else { - insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len), - (pkt_len + 3) >> 2); - } - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - vp->stats.rx_packets++; - /* Wait a limited time to go to next packet. */ - for (i = 200; i >= 0; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - continue; - } else if (vortex_debug) - printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of " - "size %d.\n", dev->name, pkt_len); - } - vp->stats.rx_dropped++; - wait_for_completion(dev, RxDiscard); - } - - return 0; -} - -static int -boomerang_rx(struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - int entry = vp->cur_rx % RX_RING_SIZE; - long ioaddr = dev->base_addr; - int rx_status; - int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx; - - if (vortex_debug > 5) - printk(KERN_DEBUG " In boomerang_rx(), status %4.4x, rx_status " - "%4.4x.\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); - while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){ - if (--rx_work_limit < 0) - break; - if (rx_status & RxDError) { /* Error, update stats. */ - unsigned char rx_error = rx_status >> 16; - if (vortex_debug > 2) - printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error); - vp->stats.rx_errors++; - if (rx_error & 0x01) vp->stats.rx_over_errors++; - if (rx_error & 0x02) vp->stats.rx_length_errors++; - if (rx_error & 0x04) vp->stats.rx_frame_errors++; - if (rx_error & 0x08) vp->stats.rx_crc_errors++; - if (rx_error & 0x10) vp->stats.rx_length_errors++; - } else { - /* The packet length: up to 4.5K!. */ - int pkt_len = rx_status & 0x1fff; - struct sk_buff *skb; - - if (vortex_debug > 4) - printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); - - /* Check if the packet is long enough to just accept without - copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { - skb->dev = dev; - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - /* 'skb_put()' points to the start of sk_buff data area. */ - memcpy(skb_put(skb, pkt_len), - bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)), - pkt_len); - rx_copy++; - } else { - void *temp; - /* Pass up the skbuff already on the Rx ring. */ - skb = vp->rx_skbuff[entry]; - vp->rx_skbuff[entry] = NULL; - temp = skb_put(skb, pkt_len); - /* Remove this checking code for final release. */ - if (bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)) != temp) - printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match" - " in boomerang_rx: %p vs. %p.\n", dev->name, - bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)), - temp); - rx_nocopy++; - } - skb->protocol = eth_type_trans(skb, dev); - { /* Use hardware checksum info. */ - int csum_bits = rx_status & 0xee000000; - if (csum_bits && - (csum_bits == (IPChksumValid | TCPChksumValid) || - csum_bits == (IPChksumValid | UDPChksumValid))) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - rx_csumhits++; - } - } - netif_rx(skb); - dev->last_rx = jiffies; - vp->stats.rx_packets++; - } - entry = (++vp->cur_rx) % RX_RING_SIZE; - } - /* Refill the Rx ring buffers. */ - for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) { - struct sk_buff *skb; - entry = vp->dirty_rx % RX_RING_SIZE; - if (vp->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(PKT_BUF_SZ); - if (skb == NULL) - break; /* Bad news! */ - skb->dev = dev; /* Mark as being used by this device. */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail)); - vp->rx_skbuff[entry] = skb; - } - vp->rx_ring[entry].status = 0; /* Clear complete bit. */ - outw(UpUnstall, ioaddr + EL3_CMD); - } - return 0; -} - -static void -vortex_down(struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - - netif_stop_queue (dev); - - del_timer(&vp->timer); - - /* Turn off statistics ASAP. We update vp->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); - - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - - if (dev->if_port == XCVR_10base2) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); - - outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); - - update_stats(ioaddr, dev); - if (vp->full_bus_master_rx) - outl(0, ioaddr + UpListPtr); - if (vp->full_bus_master_tx) - outl(0, ioaddr + DownListPtr); - - if (vp->capabilities & CapPwrMgmt) - acpi_set_WOL(dev); -} - -static int -vortex_close(struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - int i; - - if (netif_device_present(dev)) - vortex_down(dev); - - if (vortex_debug > 1) { - printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n", - dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); - printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d" - " tx_queued %d Rx pre-checksummed %d.\n", - dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits); - } - - free_irq(dev->irq, dev); - - if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ - for (i = 0; i < RX_RING_SIZE; i++) - if (vp->rx_skbuff[i]) { - dev_kfree_skb(vp->rx_skbuff[i]); - vp->rx_skbuff[i] = 0; - } - } - if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ - for (i = 0; i < TX_RING_SIZE; i++) - if (vp->tx_skbuff[i]) { - dev_kfree_skb(vp->tx_skbuff[i]); - vp->tx_skbuff[i] = 0; - } - } - - MOD_DEC_USE_COUNT; - vp->open = 0; - return 0; -} - -static struct net_device_stats *vortex_get_stats(struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - unsigned long flags; - - if (netif_device_present(dev)) { - spin_lock_irqsave (&vp->lock, flags); - update_stats(dev->base_addr, dev); - spin_unlock_irqrestore (&vp->lock, flags); - } - return &vp->stats; -} - -/* Update statistics. - Unlike with the EL3 we need not worry about interrupts changing - the window setting from underneath us, but we must still guard - against a race condition with a StatsUpdate interrupt updating the - table. This is done by checking that the ASM (!) code generated uses - atomic updates with '+='. - */ -static void update_stats(long ioaddr, struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - int old_window = inw(ioaddr + EL3_CMD); - - if (old_window == 0xffff) /* Chip suspended or ejected. */ - return; - /* Unlike the 3c5x9 we need not turn off stats updates while reading. */ - /* Switch to the stats window, and read everything. */ - EL3WINDOW(6); - vp->stats.tx_carrier_errors += inb(ioaddr + 0); - vp->stats.tx_heartbeat_errors += inb(ioaddr + 1); - /* Multiple collisions. */ inb(ioaddr + 2); - vp->stats.collisions += inb(ioaddr + 3); - vp->stats.tx_window_errors += inb(ioaddr + 4); - vp->stats.rx_fifo_errors += inb(ioaddr + 5); - vp->stats.tx_packets += inb(ioaddr + 6); - vp->stats.tx_packets += (inb(ioaddr + 9)&0x30) << 4; - /* Rx packets */ inb(ioaddr + 7); /* Must read to clear */ - /* Tx deferrals */ inb(ioaddr + 8); - /* Don't bother with register 9, an extension of registers 6&7. - If we do use the 6&7 values the atomic update assumption above - is invalid. */ - vp->stats.rx_bytes += inw(ioaddr + 10); - vp->stats.tx_bytes += inw(ioaddr + 12); - /* New: On the Vortex we must also clear the BadSSD counter. */ - EL3WINDOW(4); - inb(ioaddr + 12); - - { - u8 up = inb(ioaddr + 13); - vp->stats.rx_bytes += (up & 0x0f) << 16; - vp->stats.tx_bytes += (up & 0xf0) << 12; - } - - /* We change back to window 7 (not 1) with the Vortex. */ - EL3WINDOW(old_window >> 13); - return; -} - -static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; - int phy = vp->phys[0] & 0x1f; - - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = phy; - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - EL3WINDOW(4); - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); - return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - EL3WINDOW(4); - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); - return 0; - default: - return -EOPNOTSUPP; - } -} - -/* Pre-Cyclone chips have no documented multicast filter, so the only - multicast setting is to receive all multicast frames. At least - the chip has a very clean way to set the mode, unlike many others. */ -static void set_rx_mode(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - int new_mode; - - if (dev->flags & IFF_PROMISC) { - if (vortex_debug > 0) - printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name); - new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm; - } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { - new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast; - } else - new_mode = SetRxFilter | RxStation | RxBroadcast; - - outw(new_mode, ioaddr + EL3_CMD); -} - -/* MII transceiver control section. - Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - for details. */ - -/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues. */ -#define mdio_delay() inl(mdio_addr) - -#define MDIO_SHIFT_CLK 0x01 -#define MDIO_DIR_WRITE 0x04 -#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE) -#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE) -#define MDIO_DATA_READ 0x02 -#define MDIO_ENB_IN 0x00 - -/* Generate the preamble required for initial synchronization and - a few older transceivers. */ -static void mdio_sync(long ioaddr, int bits) -{ - long mdio_addr = ioaddr + Wn4_PhysicalMgmt; - - /* Establish sync by sending at least 32 logic ones. */ - while (-- bits >= 0) { - outw(MDIO_DATA_WRITE1, mdio_addr); - mdio_delay(); - outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } -} - -static int mdio_read(long ioaddr, int phy_id, int location) -{ - int i; - int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; - unsigned int retval = 0; - long mdio_addr = ioaddr + Wn4_PhysicalMgmt; - - if (mii_preamble_required) - mdio_sync(ioaddr, 32); - - /* Shift the read command bits out. */ - for (i = 14; i >= 0; i--) { - int dataval = (read_cmd&(1< 0; i--) { - outw(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); - outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff; -} - -static void mdio_write(long ioaddr, int phy_id, int location, int value) -{ - int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; - long mdio_addr = ioaddr + Wn4_PhysicalMgmt; - int i; - - if (mii_preamble_required) - mdio_sync(ioaddr, 32); - - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = (write_cmd&(1<= 0; i--) { - outw(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - - return; -} - -/* ACPI: Advanced Configuration and Power Interface. */ -/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */ -static void acpi_set_WOL(struct net_device *dev) -{ - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - - /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ - EL3WINDOW(7); - outw(2, ioaddr + 0x0c); - /* The RxFilter must accept the WOL frames. */ - outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); - outw(RxEnable, ioaddr + EL3_CMD); - /* Change the power state to D3; RxEnable doesn't take effect. */ - pci_write_config_word(vp->pdev, 0xe0, 0x8103); -} - - -static void __devexit vortex_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - struct vortex_private *vp; - - if (!dev) - return; - - vp = (void *)(dev->priv); - - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - unregister_netdev(dev); - outw(TotalReset, dev->base_addr + EL3_CMD); - release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size); - kfree(dev); -} - - -static struct pci_driver vortex_driver = { - name: "3c575_cb", - probe: vortex_init_one, - remove: vortex_remove_one, - suspend: vortex_suspend, - resume: vortex_resume, - id_table: vortex_pci_tbl, -}; - - -static int vortex_have_pci = 0; -static int vortex_have_eisa = 0; - - -static int __init vortex_init (void) -{ - int rc; - - MOD_INC_USE_COUNT; - - rc = pci_module_init (&vortex_driver); - if (rc < 0) - goto out; - if (rc > 0) - vortex_have_pci = 1; - - rc = vortex_eisa_init (); - if (rc < 0) - goto out; - if (rc > 0) - vortex_have_eisa = 1; - -out: - MOD_DEC_USE_COUNT; - return rc; -} - - -static void __exit vortex_eisa_cleanup (void) -{ - struct net_device *dev, *tmp; - struct vortex_private *vp; - long ioaddr; - - dev = root_vortex_eisa_dev; - - while (dev) { - vp = dev->priv; - ioaddr = dev->base_addr; - - unregister_netdev (dev); - outw (TotalReset, ioaddr + EL3_CMD); - release_region (ioaddr, VORTEX_TOTAL_SIZE); - - tmp = dev; - dev = vp->next_module; - - kfree (tmp); - } -} - - -static void __exit vortex_cleanup (void) -{ - if (vortex_have_pci) - pci_unregister_driver (&vortex_driver); - if (vortex_have_eisa) - vortex_eisa_cleanup (); -} - - -module_init(vortex_init); -module_exit(vortex_cleanup); - - - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c" - * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in --- v2.3.99-pre5/linux/drivers/net/pcmcia/Config.in Tue Apr 11 15:09:17 2000 +++ linux/drivers/net/pcmcia/Config.in Mon Apr 24 15:17:06 2000 @@ -18,7 +18,7 @@ dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA if [ "$CONFIG_CARDBUS" = "y" ]; then - dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m + comment ' 3Com 3c575 moved to Ethernet 10/100 menu' tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP fi diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile --- v2.3.99-pre5/linux/drivers/net/pcmcia/Makefile Tue Apr 11 15:09:17 2000 +++ linux/drivers/net/pcmcia/Makefile Mon Apr 24 15:17:06 2000 @@ -36,7 +36,6 @@ obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o # Cardbus client drivers -obj-$(CONFIG_PCMCIA_3C575) += 3c575_cb.o obj-$(CONFIG_PCMCIA_XIRTULIP) += xircom_tulip_cb.o obj-$(CONFIG_PCMCIA_IBMTR) += ibmtr_cs.o diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c --- v2.3.99-pre5/linux/drivers/net/pcmcia/ray_cs.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/pcmcia/ray_cs.c Wed Apr 12 09:16:31 2000 @@ -1494,16 +1494,19 @@ dev_link_t *link; ray_dev_t *local = (ray_dev_t *)dev->priv; + MOD_INC_USE_COUNT; + DEBUG(1, "ray_open('%s')\n", dev->name); for (link = dev_list; link; link = link->next) if (link->priv == dev) break; - if (!DEV_OK(link)) + if (!DEV_OK(link)) { + MOD_DEC_USE_COUNT; return -ENODEV; + } if (link->open == 0) local->num_multi = 0; link->open++; - MOD_INC_USE_COUNT; if (sniffer) netif_stop_queue(dev); else netif_start_queue(dev); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c --- v2.3.99-pre5/linux/drivers/net/pcmcia/xircom_tulip_cb.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/pcmcia/xircom_tulip_cb.c Fri Apr 21 16:08:52 2000 @@ -3132,7 +3132,7 @@ return 0; } -static __exit void tulip_exit(void) +static void __exit tulip_exit(void) { pci_unregister_driver(&tulip_ops); } @@ -3143,7 +3143,6 @@ /* * Local variables: - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/" * c-indent-level: 4 diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.3.99-pre5/linux/drivers/net/plip.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/plip.c Wed Apr 12 09:38:57 2000 @@ -687,11 +687,12 @@ return ERROR; } /* Malloc up new buffer. */ - rcv->skb = dev_alloc_skb(rcv->length.h); + rcv->skb = dev_alloc_skb(rcv->length.h + 2); if (rcv->skb == NULL) { printk(KERN_ERR "%s: Memory squeeze.\n", dev->name); return ERROR; } + skb_reserve(rcv->skb, 2); /* Align IP on 16 byte boundaries */ skb_put(rcv->skb,rcv->length.h); rcv->skb->dev = dev; rcv->state = PLIP_PK_DATA; @@ -989,7 +990,7 @@ switch (nl->connection) { case PLIP_CN_CLOSING: - netif_start_queue (dev); + netif_wake_queue (dev); case PLIP_CN_NONE: case PLIP_CN_SEND: dev->last_rx = jiffies; @@ -1035,7 +1036,7 @@ if (skb->len > dev->mtu + dev->hard_header_len) { printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len); netif_start_queue (dev); - return 0; + return 1; } if (net_debug > 2) @@ -1054,7 +1055,6 @@ mark_bh(IMMEDIATE_BH); spin_unlock_irq(&nl->lock); - netif_start_queue (dev); return 0; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c --- v2.3.99-pre5/linux/drivers/net/ppp_async.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/net/ppp_async.c Fri Apr 21 13:31:10 2000 @@ -290,6 +290,7 @@ return err; } +/* No kernel lock - fine */ static unsigned int ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c --- v2.3.99-pre5/linux/drivers/net/ppp_generic.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/net/ppp_generic.c Fri Apr 21 16:19:45 2000 @@ -19,7 +19,7 @@ * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20000406== + * ==FILEVERSION 20000417== */ #include @@ -206,7 +206,7 @@ size_t count); static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg); -static void ppp_xmit_process(struct ppp *ppp, int wakeup); +static void ppp_xmit_process(struct ppp *ppp); static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); static void ppp_push(struct ppp *ppp); static void ppp_channel_push(struct channel *pch); @@ -427,7 +427,7 @@ switch (pf->kind) { case INTERFACE: - ppp_xmit_process(PF_TO_PPP(pf), 0); + ppp_xmit_process(PF_TO_PPP(pf)); break; case CHANNEL: ppp_channel_push(PF_TO_CHANNEL(pf)); @@ -440,6 +440,7 @@ return ret; } +/* No kernel lock - fine */ static unsigned int ppp_poll(struct file *file, poll_table *wait) { struct ppp_file *pf = (struct ppp_file *) file->private_data; @@ -774,7 +775,7 @@ netif_stop_queue(dev); skb_queue_tail(&ppp->file.xq, skb); - ppp_xmit_process(ppp, 0); + ppp_xmit_process(ppp); return 0; outf: @@ -860,13 +861,12 @@ * that can now be done. */ static void -ppp_xmit_process(struct ppp *ppp, int wakeup) +ppp_xmit_process(struct ppp *ppp) { struct sk_buff *skb; ppp_xmit_lock(ppp); - if (wakeup) - ppp_push(ppp); + ppp_push(ppp); while (ppp->xmit_pending == 0 && (skb = skb_dequeue(&ppp->file.xq)) != 0) ppp_send_frame(ppp, skb); @@ -1018,14 +1018,12 @@ spin_lock_bh(&pch->downl); if (pch->chan) { if (pch->chan->ops->start_xmit(pch->chan, skb)) - skb = 0; + ppp->xmit_pending = 0; } else { /* channel got unregistered */ kfree_skb(skb); - skb = 0; - } - if (skb_queue_len(&pch->file.xq) == 0 && skb == 0) ppp->xmit_pending = 0; + } spin_unlock_bh(&pch->downl); return; } @@ -1196,6 +1194,7 @@ ppp_channel_push(struct channel *pch) { struct sk_buff *skb; + struct ppp *ppp; spin_lock_bh(&pch->downl); if (pch->chan != 0) { @@ -1212,6 +1211,14 @@ skb_queue_purge(&pch->file.xq); } spin_unlock_bh(&pch->downl); + /* see if there is anything from the attached unit to be sent */ + if (skb_queue_len(&pch->file.xq) == 0) { + read_lock_bh(&pch->upl); + ppp = pch->ppp; + if (ppp != 0) + ppp_xmit_process(ppp); + read_unlock_bh(&pch->upl); + } } /* @@ -1792,18 +1799,10 @@ ppp_output_wakeup(struct ppp_channel *chan) { struct channel *pch = chan->ppp; - struct ppp *ppp; if (pch == 0) return; ppp_channel_push(pch); - if (skb_queue_len(&pch->file.xq) == 0) { - read_lock_bh(&pch->upl); - ppp = pch->ppp; - if (ppp != 0) - ppp_xmit_process(ppp, 1); - read_unlock_bh(&pch->upl); - } } /* @@ -1830,6 +1829,7 @@ return ppp_file_write(&pch->file, buf, count); } +/* No kernel lock - fine */ unsigned int ppp_channel_poll(struct ppp_channel *chan, struct file *file, poll_table *wait) { @@ -2376,6 +2376,7 @@ { struct ppp *ppp; int err = -EINVAL; + int dead; write_lock_bh(&pch->upl); ppp = pch->ppp; @@ -2385,12 +2386,12 @@ ppp_lock(ppp); list_del(&pch->clist); --ppp->n_channels; - if (ppp->dev == 0 && ppp->n_channels == 0) + dead = ppp->dev == 0 && ppp->n_channels == 0; + ppp_unlock(ppp); + if (dead) /* Last disconnect from a ppp unit that is already dead: free it. */ kfree(ppp); - else - ppp_unlock(ppp); err = 0; } write_unlock_bh(&pch->upl); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/ppp_synctty.c linux/drivers/net/ppp_synctty.c --- v2.3.99-pre5/linux/drivers/net/ppp_synctty.c Tue Apr 11 15:09:17 2000 +++ linux/drivers/net/ppp_synctty.c Fri Apr 21 13:32:06 2000 @@ -329,6 +329,7 @@ return err; } +/* No kernel lock - fine */ static unsigned int ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c --- v2.3.99-pre5/linux/drivers/net/rrunner.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/rrunner.c Fri Apr 21 16:08:45 2000 @@ -25,6 +25,7 @@ #define RX_DMA_SKBUFF 1 #define PKT_COPY_THRESHOLD 512 +#include #include #include #include @@ -166,7 +167,7 @@ rrpriv = (struct rr_private *)dev->priv; memset(rrpriv, 0, sizeof(*rrpriv)); -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_lock_init(&rrpriv->lock); #endif sprintf(rrpriv->name, "RoadRunner serial HIPPI"); @@ -1650,6 +1651,6 @@ /* * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" + * compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" * End: */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/rtl8129.c linux/drivers/net/rtl8129.c --- v2.3.99-pre5/linux/drivers/net/rtl8129.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/rtl8129.c Fri Apr 21 16:08:52 2000 @@ -1460,7 +1460,6 @@ /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/setup.c linux/drivers/net/setup.c --- v2.3.99-pre5/linux/drivers/net/setup.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/setup.c Fri Apr 21 16:08:45 2000 @@ -28,6 +28,7 @@ extern int sdla_setup(void); extern int sdla_c_setup(void); extern int comx_init(void); +extern int lmc_setup(void); extern int abyss_probe(void); extern int madgemc_probe(void); @@ -81,6 +82,9 @@ * SLHC if present needs attaching so other people see it * even if not opened. */ +#if defined(CONFIG_LANMEDIA) + {lmc_setup, 0}, +#endif #ifdef CONFIG_INET #if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.3.99-pre5/linux/drivers/net/shaper.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/shaper.c Wed Apr 26 12:13:17 2000 @@ -64,6 +64,9 @@ * Device statistics (tx_pakets, tx_bytes, * tx_drops: queue_over_time and collisions: max_queue_exceded) * 1999/06/18 Jordi Murgo + * + * Use skb->cb for private data. + * 2000/03 Andi Kleen */ #include @@ -85,6 +88,15 @@ #include #include +struct shaper_cb { + __u32 shapelatency; /* Latency on frame */ + __u32 shapeclock; /* Time it should go out */ + __u32 shapelen; /* Frame length in clocks */ + __u32 shapestamp; /* Stamp for shaper */ + __u16 shapepend; /* Pending */ +}; +#define SHAPERCB(skb) ((struct shaper_cb *) ((skb)->cb)) + int sh_debug; /* Debug flag */ #define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n" @@ -149,7 +161,7 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb) { struct sk_buff *ptr; - + /* * Get ready to work on this shaper. Lock may fail if its * an interrupt and locked. @@ -163,25 +175,25 @@ * Set up our packet details */ - skb->shapelatency=0; - skb->shapeclock=shaper->recovery; - if(time_before(skb->shapeclock, jiffies)) - skb->shapeclock=jiffies; + SHAPERCB(skb)->shapelatency=0; + SHAPERCB(skb)->shapeclock=shaper->recovery; + if(time_before(SHAPERCB(skb)->shapeclock, jiffies)) + SHAPERCB(skb)->shapeclock=jiffies; skb->priority=0; /* short term bug fix */ - skb->shapestamp=jiffies; + SHAPERCB(skb)->shapestamp=jiffies; /* * Time slots for this packet. */ - skb->shapelen= shaper_clocks(shaper,skb); + SHAPERCB(skb)->shapelen= shaper_clocks(shaper,skb); #ifdef SHAPER_COMPLEX /* and broken.. */ while(ptr && ptr!=(struct sk_buff *)&shaper->sendq) { if(ptr->pripri - && jiffies - ptr->shapeclock < SHAPER_MAXSLIP) + && jiffies - SHAPERCB(ptr)->shapeclock < SHAPER_MAXSLIP) { struct sk_buff *tmp=ptr->prev; @@ -190,14 +202,14 @@ * of the new frame. */ - ptr->shapeclock+=skb->shapelen; - ptr->shapelatency+=skb->shapelen; + SHAPERCB(ptr)->shapeclock+=SHAPERCB(skb)->shapelen; + SHAPERCB(ptr)->shapelatency+=SHAPERCB(skb)->shapelen; /* * The packet may have slipped so far back it * fell off. */ - if(ptr->shapelatency > SHAPER_LATENCY) + if(SHAPERCB(ptr)->shapelatency > SHAPER_LATENCY) { skb_unlink(ptr); dev_kfree_skb(ptr); @@ -218,7 +230,7 @@ * this loop. */ for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && tmp!=ptr; tmp=tmp->next) - skb->shapeclock+=tmp->shapelen; + SHAPERCB(skb)->shapeclock+=tmp->shapelen; skb_append(ptr,skb); } #else @@ -230,11 +242,11 @@ */ for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && tmp!=(struct sk_buff *)&shaper->sendq; tmp=tmp->next) - skb->shapeclock+=tmp->shapelen; + SHAPERCB(skb)->shapeclock+=SHAPERCB(tmp)->shapelen; /* * Queue over time. Spill packet. */ - if(skb->shapeclock-jiffies > SHAPER_LATENCY) { + if(SHAPERCB(skb)->shapeclock-jiffies > SHAPER_LATENCY) { dev_kfree_skb(skb); shaper->stats.tx_dropped++; } else @@ -325,22 +337,23 @@ */ if(sh_debug) - printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies); - if(time_before_eq(skb->shapeclock - jiffies, SHAPER_BURST)) + printk("Clock = %d, jiffies = %ld\n", SHAPERCB(skb)->shapeclock, jiffies); + if(time_before_eq(SHAPERCB(skb)->shapeclock - jiffies, SHAPER_BURST)) { /* * Pull the frame and get interrupts back on. */ skb_unlink(skb); - if (shaper->recovery < skb->shapeclock + skb->shapelen) - shaper->recovery = skb->shapeclock + skb->shapelen; + if (shaper->recovery < + SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen) + shaper->recovery = SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen; /* * Pass on to the physical target device via * our low level packet thrower. */ - skb->shapepend=0; + SHAPERCB(skb)->shapepend=0; shaper_queue_xmit(shaper, skb); /* Fire */ } else @@ -352,7 +365,7 @@ */ if(skb!=NULL) - mod_timer(&shaper->timer, skb->shapeclock); + mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock); clear_bit(0, &shaper->locked); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/starfire.c linux/drivers/net/starfire.c --- v2.3.99-pre5/linux/drivers/net/starfire.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/starfire.c Fri Apr 21 16:08:45 2000 @@ -1375,7 +1375,6 @@ /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c starfire.c" * c-indent-level: 4 * c-basic-offset: 4 diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c --- v2.3.99-pre5/linux/drivers/net/tulip/21142.c Mon Mar 27 08:08:26 2000 +++ linux/drivers/net/tulip/21142.c Fri Apr 14 10:09:00 2000 @@ -88,8 +88,10 @@ next_tick = 3*HZ; } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); + /* mod_timer synchronizes us with potential add_timer calls + * from interrupts. + */ + mod_timer(&tp->timer, RUN_AT(next_tick)); } @@ -108,7 +110,10 @@ dev->name, csr14); outl(0x0001, ioaddr + CSR13); outl(csr14, ioaddr + CSR14); - tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); + if (tp->chip_id == PNIC2) + tp->csr6 = 0x01a80000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); + else + tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); tulip_outl_CSR6(tp, tp->csr6); if (tp->mtable && tp->mtable->csr15dir) { outl(tp->mtable->csr15dir, ioaddr + CSR15); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/tulip/timer.c linux/drivers/net/tulip/timer.c --- v2.3.99-pre5/linux/drivers/net/tulip/timer.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/net/tulip/timer.c Fri Apr 14 10:09:00 2000 @@ -171,8 +171,10 @@ } break; } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); + /* mod_timer synchronizes us with potential add_timer calls + * from interrupts. + */ + mod_timer(&tp->timer, RUN_AT(next_tick)); } @@ -188,8 +190,7 @@ inl(ioaddr + CSR12)); } if (next_tick) { - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); + mod_timer(&tp->timer, RUN_AT(next_tick)); } } @@ -205,7 +206,9 @@ printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability " "%4.4x.\n", dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8)); - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); + /* mod_timer synchronizes us with potential add_timer calls + * from interrupts. + */ + mod_timer(&tp->timer, RUN_AT(next_tick)); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h --- v2.3.99-pre5/linux/drivers/net/tulip/tulip.h Mon Mar 27 08:08:27 2000 +++ linux/drivers/net/tulip/tulip.h Wed Apr 12 09:16:31 2000 @@ -19,6 +19,22 @@ #include #include + + +/* undefine, or define to various debugging levels (>4 == obscene levels) */ +#undef TULIP_DEBUG + + +#ifdef TULIP_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + + + + struct tulip_chip_table { char *chip_name; int io_size; @@ -148,6 +164,38 @@ csr13_mask_10bt = (csr13_eng | csr13_cac | csr13_srl), }; +enum t21143_csr6_bits { + csr6_sc = (1<<31), + csr6_ra = (1<<30), + csr6_ign_dest_msb = (1<<26), + csr6_mbo = (1<<25), + csr6_scr = (1<<24), + csr6_pcs = (1<<23), + csr6_ttm = (1<<22), + csr6_sf = (1<<21), + csr6_hbd = (1<<19), + csr6_ps = (1<<18), + csr6_ca = (1<<17), + csr6_st = (1<<13), + csr6_fc = (1<<12), + csr6_om_int_loop = (1<<10), + csr6_om_ext_loop = (1<<11), + csr6_fd = (1<<9), + csr6_pm = (1<<7), + csr6_pr = (1<<6), + csr6_sb = (1<<5), + csr6_if = (1<<4), + csr6_pb = (1<<3), + csr6_ho = (1<<2), + csr6_sr = (1<<1), + csr6_hp = (1<<0), + + csr6_mask_capture = (csr6_sc | csr6_ca), + csr6_mask_defstate = (csr6_mask_capture | csr6_mbo), + csr6_mask_fullcap = (csr6_mask_defstate | csr6_hbd | + csr6_ps | (3<<14) | csr6_fd), +}; + /* Keep the ring sizes a power of two for efficiency. Making the Tx ring too large decreases the effectiveness of channel @@ -247,6 +295,7 @@ struct sk_buff *skb; dma_addr_t mapping; }; + struct tulip_private { const char *product_name; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.3.99-pre5/linux/drivers/net/tulip/tulip_core.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/net/tulip/tulip_core.c Fri Apr 14 10:09:00 2000 @@ -19,7 +19,7 @@ */ -static const char version[] = "Linux Tulip driver version 0.9.4.2 (Mar 21, 2000)\n"; +static const char version[] = "Linux Tulip driver version 0.9.4.3 (Apr 14, 2000)\n"; #include #include "tulip.h" diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.3.99-pre5/linux/drivers/net/via-rhine.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/net/via-rhine.c Fri Apr 21 16:08:45 2000 @@ -32,10 +32,15 @@ - Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions LK1.1.3: - - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c code) - update "Theory of Operation" with softnet/locking changes + - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c + code) update "Theory of Operation" with + softnet/locking changes - Dave Miller: PCI DMA and endian fixups - Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation + + LK1.1.4: + - Urban Widmark: fix gcc 2.95.2 problem and + remove writel's to fixed address 0x7c */ /* A few user-configurable values. These may be modified when a driver @@ -105,7 +110,7 @@ #include static const char *versionA __devinitdata = -"via-rhine.c:v1.03a-LK1.1.3 3/23/2000 Written by Donald Becker\n"; +"via-rhine.c:v1.03a-LK1.1.4 3/28/2000 Written by Donald Becker\n"; static const char *versionB __devinitdata = " http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n"; @@ -774,6 +779,7 @@ { struct netdev_private *np = (struct netdev_private *)dev->priv; int i; + dma_addr_t next = np->rx_ring_dma; np->cur_rx = np->cur_tx = 0; np->dirty_rx = np->dirty_tx = 0; @@ -784,8 +790,8 @@ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].rx_status = 0; np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz); - np->rx_ring[i].next_desc = - cpu_to_le32(np->rx_ring_dma + sizeof(struct rx_desc)*(i+1)); + next += sizeof(struct rx_desc); + np->rx_ring[i].next_desc = cpu_to_le32(next); np->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ @@ -806,13 +812,15 @@ np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]); np->rx_ring[i].rx_status = cpu_to_le32(DescOwn); } + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + next = np->tx_ring_dma; for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = 0; np->tx_ring[i].tx_status = 0; np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); - np->tx_ring[i].next_desc = - cpu_to_le32(np->tx_ring_dma + sizeof(struct tx_desc)*(i+1)); + next += sizeof(struct tx_desc); + np->tx_ring[i].next_desc = cpu_to_le32(next); np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL); } np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma); @@ -1097,7 +1105,6 @@ if (intr_status & IntrStatsMax) { np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs); np->stats.rx_missed_errors += readw(ioaddr + RxMissed); - writel(0, RxMissed); } if (intr_status & IntrTxAbort) { /* Stats counted in Tx-done handler, just restart Tx. */ @@ -1129,7 +1136,6 @@ non-critical. */ np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs); np->stats.rx_missed_errors += readw(ioaddr + RxMissed); - writel(0, RxMissed); return &np->stats; } @@ -1313,7 +1319,6 @@ /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in --- v2.3.99-pre5/linux/drivers/net/wan/Config.in Mon Mar 27 08:08:27 2000 +++ linux/drivers/net/wan/Config.in Fri Apr 21 16:08:45 2000 @@ -21,6 +21,12 @@ # tristate 'MultiGate (COMX) synchronous serial boards support' CONFIG_COMX + + # + # Lan Media's board. Currently 1000, 1200, 5200, 5245 + # + tristate 'LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA + if [ "$CONFIG_COMX" != "n" ]; then dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile --- v2.3.99-pre5/linux/drivers/net/wan/Makefile Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/wan/Makefile Fri Apr 21 16:08:45 2000 @@ -12,7 +12,7 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) lmc L_TARGET := wan.a L_OBJS := @@ -118,6 +118,19 @@ M_OBJS += cosa.o endif endif + +ifeq ($(CONFIG_LANMEDIA),y) + SUB_DIRS += lmc + MOD_IN_SUB_DIRS += lmc + L_OBJS += lmc/lmc.o + CONFIG_SYNCPPP_BUILTIN = y +else + ifeq ($(CONFIG_LANMEDIA),m) + CONFIG_SYNCPPP_MODULE = y + MOD_IN_SUB_DIRS += lmc + endif +endif + # If anything built-in uses syncppp, then build it into the kernel also. # If not, but a module uses it, build as a module. diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/comx.c linux/drivers/net/wan/comx.c --- v2.3.99-pre5/linux/drivers/net/wan/comx.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/wan/comx.c Wed Apr 12 09:38:57 2000 @@ -91,8 +91,6 @@ static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode, int size, struct proc_dir_entry *dir); -static void comx_fill_inode(struct inode *inode, int fill); - static struct dentry_operations comx_dentry_operations = { NULL, /* revalidate */ NULL, /* d_hash */ @@ -101,13 +99,7 @@ }; -struct proc_dir_entry comx_root_dir = { - 0, 4, "comx", - S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, 2, 0, 0, - 0, &comx_root_inode_ops, - NULL, comx_fill_inode, - NULL, &proc_root, NULL -}; +static struct proc_dir_entry * comx_root_dir; struct comx_debugflags_struct comx_debugflags[] = { { "comx_rx", DEBUG_COMX_RX }, @@ -121,14 +113,6 @@ { NULL, 0 } }; -static void comx_fill_inode(struct inode *inode, int fill) -{ - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - int comx_debug(struct net_device *dev, char *fmt, ...) { @@ -853,14 +837,13 @@ struct net_device *dev; struct comx_channel *ch; - if (dir->i_ino != comx_root_dir.low_ino) return -ENOTDIR; + if (dir->i_ino != comx_root_dir->low_ino) return -ENOTDIR; if ((new_dir = create_proc_entry(dentry->d_name.name, mode | S_IFDIR, - &comx_root_dir)) == NULL) { + comx_root_dir)) == NULL) { return -EIO; } - new_dir->proc_iops = &proc_dir_inode_operations; // ez egy normalis /proc konyvtar new_dir->nlink = 2; new_dir->data = NULL; // ide jon majd a struct dev @@ -930,7 +913,7 @@ int ret; /* Egyelore miert ne ? */ - if (dir->i_ino != comx_root_dir.low_ino) return -ENOTDIR; + if (dir->i_ino != comx_root_dir->low_ino) return -ENOTDIR; if (dev->flags & IFF_UP) { printk(KERN_ERR "%s: down interface before removing it\n", dev->name); @@ -968,8 +951,7 @@ remove_proc_entry(FILENAME_STATUS, entry); remove_proc_entry(FILENAME_HARDWARE, entry); remove_proc_entry(FILENAME_PROTOCOL, entry); - remove_proc_entry(dentry->d_name.name, &comx_root_dir); -// proc_unregister(&comx_root_dir, dentry->d_inode->i_ino); + remove_proc_entry(dentry->d_name.name, comx_root_dir); MOD_DEC_USE_COUNT; return 0; @@ -1133,23 +1115,15 @@ { struct proc_dir_entry *new_file; - memcpy(&comx_root_inode_ops, &proc_dir_inode_operations, - sizeof(struct inode_operations)); comx_root_inode_ops.lookup = &comx_lookup; comx_root_inode_ops.mkdir = &comx_mkdir; comx_root_inode_ops.rmdir = &comx_rmdir; - memcpy(&comx_normal_inode_ops, &proc_net_inode_operations, - sizeof(struct inode_operations)); - comx_normal_inode_ops.default_file_ops = &comx_normal_file_ops; comx_normal_inode_ops.lookup = &comx_lookup; memcpy(&comx_debug_inode_ops, &comx_normal_inode_ops, sizeof(struct inode_operations)); - comx_debug_inode_ops.default_file_ops = &comx_debug_file_ops; - memcpy(&comx_normal_file_ops, proc_net_inode_operations.default_file_ops, - sizeof(struct file_operations)); comx_normal_file_ops.open = &comx_file_open; comx_normal_file_ops.release = &comx_file_release; @@ -1158,22 +1132,25 @@ comx_debug_file_ops.llseek = &comx_debug_lseek; comx_debug_file_ops.read = &comx_debug_read; - if (proc_register(&proc_root, &comx_root_dir) < 0) return -ENOMEM; - + comx_root_dir = create_proc_entry("comx", + S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, &proc_root); + if (!comx_root_dir) + return -ENOMEM; + comx_root_dir->proc_iops = &comx_root_inode_ops; if ((new_file = create_proc_entry(FILENAME_HARDWARELIST, - S_IFREG | 0444, &comx_root_dir)) == NULL) { + S_IFREG | 0444, comx_root_dir)) == NULL) { return -ENOMEM; } - new_file->ops = &comx_normal_inode_ops; + new_file->proc_iops = &comx_normal_inode_ops; new_file->data = new_file; new_file->read_proc = &comx_root_read_proc; new_file->write_proc = NULL; new_file->nlink = 1; if ((new_file = create_proc_entry(FILENAME_PROTOCOLLIST, - S_IFREG | 0444, &comx_root_dir)) == NULL) { + S_IFREG | 0444, comx_root_dir)) == NULL) { return -ENOMEM; } @@ -1217,9 +1194,9 @@ #ifdef MODULE void cleanup_module(void) { - remove_proc_entry(FILENAME_HARDWARELIST, &comx_root_dir); - remove_proc_entry(FILENAME_PROTOCOLLIST, &comx_root_dir); - proc_unregister(&proc_root, comx_root_dir.low_ino); + remove_proc_entry(FILENAME_HARDWARELIST, comx_root_dir); + remove_proc_entry(FILENAME_PROTOCOLLIST, comx_root_dir); + remove_proc_entry(comx_root_dir->name, &proc_root); } #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/comx.h linux/drivers/net/wan/comx.h --- v2.3.99-pre5/linux/drivers/net/wan/comx.h Tue Mar 14 19:10:40 2000 +++ linux/drivers/net/wan/comx.h Wed Apr 12 09:38:57 2000 @@ -220,7 +220,7 @@ #define SEEK_END 2 #endif -extern struct proc_dir_entry comx_root_dir; +extern struct proc_dir_entry * comx_root_dir; extern int comx_register_hardware(struct comx_hardware *comx_hw); extern int comx_unregister_hardware(char *name); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c --- v2.3.99-pre5/linux/drivers/net/wan/cosa.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/net/wan/cosa.c Fri Apr 21 16:37:56 2000 @@ -79,6 +79,7 @@ /* ---------- Headers, macros, data structures ---------- */ +#include #include #include #include @@ -374,7 +375,7 @@ int i; printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak \n"); -#ifdef __SMP__ +#ifdef CONFIG_SMP printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); #endif if (cosa_major > 0) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/Makefile linux/drivers/net/wan/lmc/Makefile --- v2.3.99-pre5/linux/drivers/net/wan/lmc/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/Makefile Fri Apr 21 16:08:45 2000 @@ -0,0 +1,39 @@ +# File: drivers/lmc/Makefile +# +# Makefile for the Lan Media 21140 based WAN cards +# Specifically the 1000,1200,5200,5245 +# + +ifeq ($(CONFIG_LANMEDIA),y) + O_TARGET := lmc.o + O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o +else + ifeq ($(CONFIG_LANMEDIA),m) + MOD_LIST_NAME := NET_MODULES + M_OBJS := lmc.o + O_TARGET := lmc.o + O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o + endif +endif + +# +# Base debugging and event log (doubles lmc.o size) +# +# DBGDEF = \ +# -DDEBUG + +# +# Like above except every packet gets echoed to KERN_DEBUG +# in hex +# +# DBDEF = \ +# -DDEBUG \ +# -DLMC_PACKET_LOG + +EXTRA_CFLAGS += -I. $(DBGDEF) + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s + diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc.h linux/drivers/net/wan/lmc/lmc.h --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,32 @@ +#ifndef _LMC_H_ +#define _LMC_H_ + +#include "lmc_var.h" + +/* + * prototypes for everyone + */ +int lmc_probe(struct net_device * dev); +unsigned lmc_mii_readreg(lmc_softc_t * const sc, unsigned + devaddr, unsigned regno); +void lmc_mii_writereg(lmc_softc_t * const sc, unsigned devaddr, + unsigned regno, unsigned data); +void lmc_led_on(lmc_softc_t * const, u_int32_t); +void lmc_led_off(lmc_softc_t * const, u_int32_t); +unsigned lmc_mii_readreg(lmc_softc_t * const, unsigned, unsigned); +void lmc_mii_writereg(lmc_softc_t * const, unsigned, unsigned, unsigned); +void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits); +void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits); + +int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + +extern lmc_media_t lmc_ds3_media; +extern lmc_media_t lmc_ssi_media; +extern lmc_media_t lmc_t1_media; +extern lmc_media_t lmc_hssi_media; + +#ifdef _DBG_EVENTLOG +static void lmcEventLog( u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3 ); +#endif + +#endif \ No newline at end of file diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_debug.c linux/drivers/net/wan/lmc/lmc_debug.c --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_debug.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_debug.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,87 @@ + +#include +#include +#include +#include +#include +#include "lmc_ver.h" +#include "lmc_debug.h" + +/* + * Prints out len, max to 80 octets using printk, 20 per line + */ +void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) +{ +#ifdef DEBUG +#ifdef LMC_PACKET_LOG + int iNewLine = 1; + char str[80], *pstr; + + sprintf(str, KERN_DEBUG "lmc: %s: ", type); + pstr = str+strlen(str); + + if(iLen > 240){ + printk(KERN_DEBUG "lmc: Printing 240 chars... out of: %d\n", iLen); + iLen = 240; + } + else{ + printk(KERN_DEBUG "lmc: Printing %d chars\n", iLen); + } + + while(iLen > 0) + { + sprintf(pstr, "%02x ", *ucData); + pstr+=3; + ucData++; + if( !(iNewLine % 20)) + { + sprintf(pstr, "\n"); + printk(str); + sprintf(str, KERN_DEBUG "lmc: %s: ", type); + pstr=str+strlen(str); + } + iNewLine++; + iLen--; + } + sprintf(pstr, "\n"); + printk(str); +#endif +#endif +} + +#ifdef DEBUG +u_int32_t lmcEventLogIndex = 0; +u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS]; +#endif + +void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3) +{ +#ifdef DEBUG + lmcEventLogBuf[lmcEventLogIndex++] = EventNum; + lmcEventLogBuf[lmcEventLogIndex++] = arg2; + lmcEventLogBuf[lmcEventLogIndex++] = arg3; + lmcEventLogBuf[lmcEventLogIndex++] = jiffies; + + lmcEventLogIndex &= (LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS) - 1; +#endif +} + +inline void lmc_trace(struct net_device *dev, char *msg){ +#ifdef LMC_TRACE + unsigned long j = jiffies + 3; /* Wait for 50 ms */ + + if(in_interrupt()){ + printk("%s: * %s\n", dev->name, msg); +// while(jiffies < j+10) +// ; + } + else { + printk("%s: %s\n", dev->name, msg); + while(jiffies < j) + schedule(); + } +#endif +} + + +/* --------------------------- end if_lmc_linux.c ------------------------ */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_debug.h linux/drivers/net/wan/lmc/lmc_debug.h --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_debug.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_debug.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,52 @@ +#ifndef _LMC_DEBUG_H_ +#define _LMC_DEBUG_H_ + +#ifdef DEBUG +#ifdef LMC_PACKET_LOG +#define LMC_CONSOLE_LOG(x,y,z) lmcConsoleLog((x), (y), (z)) +#else +#define LMC_CONSOLE_LOG(x,y,z) +#endif +#else +#define LMC_CONSOLE_LOG(x,y,z) +#endif + + + +/* Debug --- Event log definitions --- */ +/* EVENTLOGSIZE*EVENTLOGARGS needs to be a power of 2 */ +#define LMC_EVENTLOGSIZE 1024 /* number of events in eventlog */ +#define LMC_EVENTLOGARGS 4 /* number of args for each event */ + +/* event indicators */ +#define LMC_EVENT_XMT 1 +#define LMC_EVENT_XMTEND 2 +#define LMC_EVENT_XMTINT 3 +#define LMC_EVENT_RCVINT 4 +#define LMC_EVENT_RCVEND 5 +#define LMC_EVENT_INT 6 +#define LMC_EVENT_XMTINTTMO 7 +#define LMC_EVENT_XMTPRCTMO 8 +#define LMC_EVENT_INTEND 9 +#define LMC_EVENT_RESET1 10 +#define LMC_EVENT_RESET2 11 +#define LMC_EVENT_FORCEDRESET 12 +#define LMC_EVENT_WATCHDOG 13 +#define LMC_EVENT_BADPKTSURGE 14 +#define LMC_EVENT_TBUSY0 15 +#define LMC_EVENT_TBUSY1 16 + + +#ifdef DEBUG +extern u_int32_t lmcEventLogIndex; +extern u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS]; +#define LMC_EVENT_LOG(x, y, z) lmcEventLog((x), (y), (z)) +#else +#define LMC_EVENT_LOG(x,y,z) +#endif /* end ifdef _DBG_EVENTLOG */ + +void lmcConsoleLog(char *type, unsigned char *ucData, int iLen); +void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3); +inline void lmc_trace(struct net_device *dev, char *msg); + +#endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_ioctl.h linux/drivers/net/wan/lmc/lmc_ioctl.h --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_ioctl.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_ioctl.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,257 @@ +#ifndef _LMC_IOCTL_H_ +#define _LMC_IOCTL_H_ +/* $Id: lmc_ioctl.h,v 1.15 2000/04/06 12:16:43 asj Exp $ */ + + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + */ + +#define LMCIOCGINFO SIOCDEVPRIVATE+3 /* get current state */ +#define LMCIOCSINFO SIOCDEVPRIVATE+4 /* set state to user values */ +#define LMCIOCGETLMCSTATS SIOCDEVPRIVATE+5 +#define LMCIOCCLEARLMCSTATS SIOCDEVPRIVATE+6 +#define LMCIOCDUMPEVENTLOG SIOCDEVPRIVATE+7 +#define LMCIOCGETXINFO SIOCDEVPRIVATE+8 +#define LMCIOCSETCIRCUIT SIOCDEVPRIVATE+9 +#define LMCIOCUNUSEDATM SIOCDEVPRIVATE+10 +#define LMCIOCRESET SIOCDEVPRIVATE+11 +#define LMCIOCT1CONTROL SIOCDEVPRIVATE+12 +#define LMCIOCIFTYPE SIOCDEVPRIVATE+13 +#define LMCIOCXILINX SIOCDEVPRIVATE+14 + +#define LMC_CARDTYPE_UNKNOWN -1 +#define LMC_CARDTYPE_HSSI 1 /* probed card is a HSSI card */ +#define LMC_CARDTYPE_DS3 2 /* probed card is a DS3 card */ +#define LMC_CARDTYPE_SSI 3 /* probed card is a SSI card */ +#define LMC_CARDTYPE_T1 4 /* probed card is a T1 card */ + +#define LMC_CTL_CARDTYPE_LMC5200 0 /* HSSI */ +#define LMC_CTL_CARDTYPE_LMC5245 1 /* DS3 */ +#define LMC_CTL_CARDTYPE_LMC1000 2 /* SSI, V.35 */ +#define LMC_CTL_CARDTYPE_LMC1200 3 /* DS1 */ + +#define LMC_CTL_OFF 0 /* generic OFF value */ +#define LMC_CTL_ON 1 /* generic ON value */ + +#define LMC_CTL_CLOCK_SOURCE_EXT 0 /* clock off line */ +#define LMC_CTL_CLOCK_SOURCE_INT 1 /* internal clock */ + +#define LMC_CTL_CRC_LENGTH_16 16 +#define LMC_CTL_CRC_LENGTH_32 32 +#define LMC_CTL_CRC_BYTESIZE_2 2 +#define LMC_CTL_CRC_BYTESIZE_4 4 + + +#define LMC_CTL_CABLE_LENGTH_LT_100FT 0 /* DS3 cable < 100 feet */ +#define LMC_CTL_CABLE_LENGTH_GT_100FT 1 /* DS3 cable >= 100 feet */ + +#define LMC_CTL_CIRCUIT_TYPE_E1 0 +#define LMC_CTL_CIRCUIT_TYPE_T1 1 + +/* + * IFTYPE defines + */ +#define LMC_PPP 1 /* use sppp interface */ +#define LMC_NET 2 /* use direct net interface */ +#define LMC_RAW 3 /* use direct net interface */ + +/* + * These are not in the least IOCTL related, but I want them common. + */ +/* + * assignments for the GPIO register on the DEC chip (common) + */ +#define LMC_GEP_INIT 0x01 /* 0: */ +#define LMC_GEP_RESET 0x02 /* 1: */ +#define LMC_GEP_MODE 0x10 /* 4: */ +#define LMC_GEP_DP 0x20 /* 5: */ +#define LMC_GEP_DATA 0x40 /* 6: serial out */ +#define LMC_GEP_CLK 0x80 /* 7: serial clock */ + +/* + * HSSI GPIO assignments + */ +#define LMC_GEP_HSSI_ST 0x04 /* 2: receive timing sense (deprecated) */ +#define LMC_GEP_HSSI_CLOCK 0x08 /* 3: clock source */ + +/* + * T1 GPIO assignments + */ +#define LMC_GEP_SSI_GENERATOR 0x04 /* 2: enable prog freq gen serial i/f */ +#define LMC_GEP_SSI_TXCLOCK 0x08 /* 3: provide clock on TXCLOCK output */ + +/* + * Common MII16 bits + */ +#define LMC_MII16_LED0 0x0080 +#define LMC_MII16_LED1 0x0100 +#define LMC_MII16_LED2 0x0200 +#define LMC_MII16_LED3 0x0400 /* Error, and the red one */ +#define LMC_MII16_LED_ALL 0x0780 /* LED bit mask */ +#define LMC_MII16_FIFO_RESET 0x0800 + +/* + * definitions for HSSI + */ +#define LMC_MII16_HSSI_TA 0x0001 +#define LMC_MII16_HSSI_CA 0x0002 +#define LMC_MII16_HSSI_LA 0x0004 +#define LMC_MII16_HSSI_LB 0x0008 +#define LMC_MII16_HSSI_LC 0x0010 +#define LMC_MII16_HSSI_TM 0x0020 +#define LMC_MII16_HSSI_CRC 0x0040 + +/* + * assignments for the MII register 16 (DS3) + */ +#define LMC_MII16_DS3_ZERO 0x0001 +#define LMC_MII16_DS3_TRLBK 0x0002 +#define LMC_MII16_DS3_LNLBK 0x0004 +#define LMC_MII16_DS3_RAIS 0x0008 +#define LMC_MII16_DS3_TAIS 0x0010 +#define LMC_MII16_DS3_BIST 0x0020 +#define LMC_MII16_DS3_DLOS 0x0040 +#define LMC_MII16_DS3_CRC 0x1000 +#define LMC_MII16_DS3_SCRAM 0x2000 +#define LMC_MII16_DS3_SCRAM_LARS 0x4000 + +/* Note: 2 pairs of LEDs where swapped by mistake + * in Xilinx code for DS3 & DS1 adapters */ +#define LMC_DS3_LED0 0x0100 /* bit 08 yellow */ +#define LMC_DS3_LED1 0x0080 /* bit 07 blue */ +#define LMC_DS3_LED2 0x0400 /* bit 10 green */ +#define LMC_DS3_LED3 0x0200 /* bit 09 red */ + +/* + * framer register 0 and 7 (7 is latched and reset on read) + */ +#define LMC_FRAMER_REG0_DLOS 0x80 /* digital loss of service */ +#define LMC_FRAMER_REG0_OOFS 0x40 /* out of frame sync */ +#define LMC_FRAMER_REG0_AIS 0x20 /* alarm indication signal */ +#define LMC_FRAMER_REG0_CIS 0x10 /* channel idle */ +#define LMC_FRAMER_REG0_LOC 0x08 /* loss of clock */ + +/* + * Framer register 9 contains the blue alarm signal + */ +#define LMC_FRAMER_REG9_RBLUE 0x02 /* Blue alarm failure */ + +/* + * Framer register 0x10 contains xbit error + */ +#define LMC_FRAMER_REG10_XBIT 0x01 /* X bit error alarm failure */ + +/* + * And SSI, LMC1000 + */ +#define LMC_MII16_SSI_DTR 0x0001 /* DTR output RW */ +#define LMC_MII16_SSI_DSR 0x0002 /* DSR input RO */ +#define LMC_MII16_SSI_RTS 0x0004 /* RTS output RW */ +#define LMC_MII16_SSI_CTS 0x0008 /* CTS input RO */ +#define LMC_MII16_SSI_DCD 0x0010 /* DCD input RO */ +#define LMC_MII16_SSI_RI 0x0020 /* RI input RO */ +#define LMC_MII16_SSI_CRC 0x1000 /* CRC select - RW */ + +/* + * bits 0x0080 through 0x0800 are generic, and described + * above with LMC_MII16_LED[0123] _LED_ALL, and _FIFO_RESET + */ +#define LMC_MII16_SSI_LL 0x1000 /* LL output RW */ +#define LMC_MII16_SSI_RL 0x2000 /* RL output RW */ +#define LMC_MII16_SSI_TM 0x4000 /* TM input RO */ +#define LMC_MII16_SSI_LOOP 0x8000 /* loopback enable RW */ + +/* + * Some of the MII16 bits are mirrored in the MII17 register as well, + * but let's keep thing seperate for now, and get only the cable from + * the MII17. + */ +#define LMC_MII17_SSI_CABLE_MASK 0x0038 /* mask to extract the cable type */ +#define LMC_MII17_SSI_CABLE_SHIFT 3 /* shift to extract the cable type */ + +/* + * And T1, LMC1200 + */ +#define LMC_MII16_T1_UNUSED1 0x0003 +#define LMC_MII16_T1_XOE 0x0004 +#define LMC_MII16_T1_RST 0x0008 /* T1 chip reset - RW */ +#define LMC_MII16_T1_Z 0x0010 /* output impedance T1=1, E1=0 output - RW */ +#define LMC_MII16_T1_INTR 0x0020 /* interrupt from 8370 - RO */ +#define LMC_MII16_T1_ONESEC 0x0040 /* one second square wave - ro */ + +#define LMC_MII16_T1_LED0 0x0100 +#define LMC_MII16_T1_LED1 0x0080 +#define LMC_MII16_T1_LED2 0x0400 +#define LMC_MII16_T1_LED3 0x0200 +#define LMC_MII16_T1_FIFO_RESET 0x0800 + +#define LMC_MII16_T1_CRC 0x1000 /* CRC select - RW */ +#define LMC_MII16_T1_UNUSED2 0xe000 + + +/* 8370 framer registers */ + +#define T1FRAMER_ALARM1_STATUS 0x47 +#define T1FRAMER_ALARM2_STATUS 0x48 +#define T1FRAMER_FERR_LSB 0x50 +#define T1FRAMER_FERR_MSB 0x51 /* framing bit error counter */ +#define T1FRAMER_LCV_LSB 0x54 +#define T1FRAMER_LCV_MSB 0x55 /* line code violation counter */ +#define T1FRAMER_AERR 0x5A + +/* mask for the above AERR register */ +#define T1FRAMER_LOF_MASK (0x0f0) /* receive loss of frame */ +#define T1FRAMER_COFA_MASK (0x0c0) /* change of frame alignment */ +#define T1FRAMER_SEF_MASK (0x03) /* severely errored frame */ + +/* 8370 framer register ALM1 (0x47) values + * used to determine link status + */ + +#define T1F_SIGFRZ 0x01 /* signaling freeze */ +#define T1F_RLOF 0x02 /* receive loss of frame alignment */ +#define T1F_RLOS 0x04 /* receive loss of signal */ +#define T1F_RALOS 0x08 /* receive analog loss of signal or RCKI loss of clock */ +#define T1F_RAIS 0x10 /* receive alarm indication signal */ +#define T1F_UNUSED 0x20 +#define T1F_RYEL 0x40 /* receive yellow alarm */ +#define T1F_RMYEL 0x80 /* receive multiframe yellow alarm */ + +#define LMC_T1F_WRITE 0 +#define LMC_T1F_READ 1 + +typedef struct lmc_st1f_control { + int command; + int address; + int value; + char *data; +} lmc_t1f_control; + +enum lmc_xilinx_c { + lmc_xilinx_reset = 1, + lmc_xilinx_load_prom = 2, + lmc_xilinx_load = 3 +}; + +struct lmc_xilinx_control { + enum lmc_xilinx_c command; + int len; + char *data; +}; + +/* ------------------ end T1 defs ------------------- */ + +#define LMC_MII_LedMask 0x0780 +#define LMC_MII_LedBitPos 7 + +#endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_main.c linux/drivers/net/wan/lmc/lmc_main.c --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_main.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_main.c Tue Apr 25 17:52:01 2000 @@ -0,0 +1,2486 @@ + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * With Help By: + * David Boggs + * Ron Crane + * Allan Cox + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + * + * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards. + * + * To control link specific options lmcctl is required. + * It can be obtained from ftp.lanmedia.com. + * + * Linux driver notes: + * Linux uses the device struct lmc_private to pass private information + * arround. + * + * The initialization portion of this driver (the lmc_reset() and the + * lmc_dec_reset() functions, as well as the led controls and the + * lmc_initcsrs() functions. + * + * The watchdog function runs every second and checks to see if + * we still have link, and that the timing source is what we expected + * it to be. If link is lost, the interface is marked down, and + * we no longer can transmit. + * + */ + +/* $Id: lmc_main.c,v 1.36 2000/04/11 05:25:25 asj Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < 0x20155 +#include +#endif + +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +#include +#include +#include +#include "../syncppp.h" +#include + +#if LINUX_VERSION_CODE >= 0x20200 +#include +//#include +#else /* 2.0 kernel */ +#define ARPHRD_HDLC 513 +#endif + +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#define DRIVER_MAJOR_VERSION 1 +#define DRIVER_MINOR_VERSION 34 +#define DRIVER_SUB_VERSION 0 + +#define DRIVER_VERSION ((DRIVER_MAJOR_VERSION << 8) + DRIVER_MINOR_VERSION) + +#include "lmc_ver.h" +#include "lmc.h" +#include "lmc_var.h" +#include "lmc_ioctl.h" +#include "lmc_debug.h" +#include "lmc_proto.h" + + +static int Lmc_Count = 0; +static struct net_device *Lmc_root_dev = NULL; +static u8 cards_found = 0; + +static int lmc_first_load = 0; + +int LMC_PKT_BUF_SZ = 1542; + +#ifdef MODULE +static struct pci_device_id lmc_pci_tbl[] __devinitdata = { + { 0x1011, 0x009, 0x1379, PCI_ANY_ID, 0, 0, 0}, + { 0 }, +}; + +MODULE_DEVICE_TABLE(pci, lmc_pci_tbl); +#endif + + +int lmc_probe_fake(struct net_device *dev); +static struct net_device *lmc_probe1(struct net_device *dev, unsigned long ioaddr, unsigned int irq, + int chip_id, int subdevice, int board_idx); +static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int lmc_rx (struct net_device *dev); +static int lmc_open(struct net_device *dev); +static int lmc_close(struct net_device *dev); +static struct enet_statistics *lmc_get_stats(struct net_device *dev); +static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int lmc_set_config(struct net_device *dev, struct ifmap *map); +static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size); +static void lmc_softreset(lmc_softc_t * const); +static void lmc_running_reset(struct net_device *dev); +static int lmc_ifdown(struct net_device * const); +static void lmc_watchdog(unsigned long data); +static int lmc_init(struct net_device * const); +static void lmc_reset(lmc_softc_t * const sc); +static void lmc_dec_reset(lmc_softc_t * const sc); +#if LINUX_VERSION_CODE >= 0x20363 +static void lmc_driver_timeout(struct net_device *dev); +int lmc_setup(void); +#endif + + +/* + * linux reserves 16 device specific IOCTLs. We call them + * LMCIOC* to control various bits of our world. + */ +int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ +{ + lmc_softc_t *sc; + lmc_ctl_t ctl; + int ret; + u_int16_t regVal; + unsigned long flags; + + struct sppp *sp; + + ret = -EOPNOTSUPP; + + sc = dev->priv; + + lmc_trace(dev, "lmc_ioctl in"); + + /* + * Most functions mess with the structure + * Disable interupts while we do the polling + */ + spin_lock_irqsave(&sc->lmc_lock, flags); + + switch (cmd) { + /* + * Return current driver state. Since we keep this up + * To date internally, just copy this out to the user. + */ + case LMCIOCGINFO: /*fold01*/ + LMC_COPY_TO_USER(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t)); + ret = 0; + break; + + case LMCIOCSINFO: /*fold01*/ + sp = &((struct ppp_device *) dev)->sppp; + if (!suser ()) { + ret = -EPERM; + break; + } + + if(dev->flags & IFF_UP){ + ret = -EBUSY; + break; + } + + LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)); + + sc->lmc_media->set_status (sc, &ctl); + + if(ctl.crc_length != sc->ictl.crc_length) { + sc->lmc_media->set_crc_length(sc, ctl.crc_length); + if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16) + sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE; + else + sc->TxDescriptControlInit &= ~LMC_TDES_ADD_CRC_DISABLE; + } + + if (ctl.keepalive_onoff == LMC_CTL_OFF) + sp->pp_flags &= ~PP_KEEPALIVE; /* Turn off */ + else + sp->pp_flags |= PP_KEEPALIVE; /* Turn on */ + + ret = 0; + break; + + case LMCIOCIFTYPE: /*fold01*/ + { + u_int16_t old_type = sc->if_type; + u_int16_t new_type; + + if (!suser ()) { + ret = -EPERM; + break; + } + + LMC_COPY_FROM_USER(&new_type, ifr->ifr_data, sizeof(u_int16_t)); + + + if (new_type == old_type) + { + ret = 0 ; + break; /* no change */ + } + + lmc_proto_close(sc); + lmc_proto_detach(sc); + + sc->if_type = new_type; +// lmc_proto_init(sc); + lmc_proto_attach(sc); + lmc_proto_open(sc); + + ret = 0 ; + break ; + } + + case LMCIOCGETXINFO: /*fold01*/ + sc->lmc_xinfo.Magic0 = 0xBEEFCAFE; + + sc->lmc_xinfo.PciCardType = sc->lmc_cardtype; + sc->lmc_xinfo.PciSlotNumber = 0; + sc->lmc_xinfo.DriverMajorVersion = DRIVER_MAJOR_VERSION; + sc->lmc_xinfo.DriverMinorVersion = DRIVER_MINOR_VERSION; + sc->lmc_xinfo.DriverSubVersion = DRIVER_SUB_VERSION; + sc->lmc_xinfo.XilinxRevisionNumber = + lmc_mii_readreg (sc, 0, 3) & 0xf; + sc->lmc_xinfo.MaxFrameSize = LMC_PKT_BUF_SZ; + sc->lmc_xinfo.link_status = sc->lmc_media->get_link_status (sc); + sc->lmc_xinfo.mii_reg16 = lmc_mii_readreg (sc, 0, 16); + + sc->lmc_xinfo.Magic1 = 0xDEADBEEF; + + LMC_COPY_TO_USER(ifr->ifr_data, &sc->lmc_xinfo, + sizeof (struct lmc_xinfo)); + ret = 0; + + break; + + case LMCIOCGETLMCSTATS: /*fold01*/ + if (sc->lmc_cardtype == LMC_CARDTYPE_T1){ + lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_LSB); + sc->stats.framingBitErrorCount += + lmc_mii_readreg (sc, 0, 18) & 0xff; + lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_MSB); + sc->stats.framingBitErrorCount += + (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8; + lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_LSB); + sc->stats.lineCodeViolationCount += + lmc_mii_readreg (sc, 0, 18) & 0xff; + lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_MSB); + sc->stats.lineCodeViolationCount += + (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8; + lmc_mii_writereg (sc, 0, 17, T1FRAMER_AERR); + regVal = lmc_mii_readreg (sc, 0, 18) & 0xff; + + sc->stats.lossOfFrameCount += + (regVal & T1FRAMER_LOF_MASK) >> 4; + sc->stats.changeOfFrameAlignmentCount += + (regVal & T1FRAMER_COFA_MASK) >> 2; + sc->stats.severelyErroredFrameCount += + regVal & T1FRAMER_SEF_MASK; + } + + LMC_COPY_TO_USER(ifr->ifr_data, &sc->stats, + sizeof (struct lmc_statistics)); + + ret = 0; + break; + + case LMCIOCCLEARLMCSTATS: /*fold01*/ + if (!suser ()){ + ret = -EPERM; + break; + } + + memset (&sc->stats, 0, sizeof (struct lmc_statistics)); + sc->stats.check = STATCHECK; + sc->stats.version_size = (DRIVER_VERSION << 16) + + sizeof (struct lmc_statistics); + sc->stats.lmc_cardtype = sc->lmc_cardtype; + ret = 0; + break; + + case LMCIOCSETCIRCUIT: /*fold01*/ + if (!suser ()){ + ret = -EPERM; + break; + } + + if(dev->flags & IFF_UP){ + ret = -EBUSY; + break; + } + + LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)); + sc->lmc_media->set_circuit_type(sc, ctl.circuit_type); + sc->ictl.circuit_type = ctl.circuit_type; + ret = 0; + + break; + + case LMCIOCRESET: /*fold01*/ + if (!suser ()){ + ret = -EPERM; + break; + } + + /* Reset driver and bring back to current state */ + printk (" REG16 before reset +%04x\n", lmc_mii_readreg (sc, 0, 16)); + lmc_running_reset (dev); + printk (" REG16 after reset +%04x\n", lmc_mii_readreg (sc, 0, 16)); + + LMC_EVENT_LOG(LMC_EVENT_FORCEDRESET, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16)); + + ret = 0; + break; + +#ifdef DEBUG + case LMCIOCDUMPEVENTLOG: + LMC_COPY_TO_USER(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32)); + LMC_COPY_TO_USER(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf)); + + ret = 0; + break; +#endif /* end ifdef _DBG_EVENTLOG */ + case LMCIOCT1CONTROL: /*fold01*/ + if (sc->lmc_cardtype != LMC_CARDTYPE_T1){ + ret = -EOPNOTSUPP; + break; + } + break; + case LMCIOCXILINX: /*fold01*/ + { + struct lmc_xilinx_control xc; /*fold02*/ + + if (!suser ()){ + ret = -EPERM; + break; + } + + /* + * Stop the xwitter whlie we restart the hardware + */ + LMC_XMITTER_BUSY(dev); + + LMC_COPY_FROM_USER(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control)); + switch(xc.command){ + case lmc_xilinx_reset: /*fold02*/ + { + u16 mii; + mii = lmc_mii_readreg (sc, 0, 16); + + /* + * Make all of them 0 and make input + */ + lmc_gpio_mkinput(sc, 0xff); + + /* + * make the reset output + */ + lmc_gpio_mkoutput(sc, LMC_GEP_RESET); + + /* + * RESET low to force configuration. This also forces + * the transmitter clock to be internal, but we expect to reset + * that later anyway. + */ + + sc->lmc_gpio &= ~LMC_GEP_RESET; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + + /* + * hold for more than 10 microseconds + */ + udelay(50); + + sc->lmc_gpio |= LMC_GEP_RESET; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + + /* + * stop driving Xilinx-related signals + */ + lmc_gpio_mkinput(sc, 0xff); + + /* Reset the frammer hardware */ + sc->lmc_media->set_link_status (sc, 1); + sc->lmc_media->set_status (sc, NULL); +// lmc_softreset(sc); + + { + int i; + for(i = 0; i < 5; i++){ + lmc_led_on(sc, LMC_DS3_LED0); + mdelay(100); + lmc_led_off(sc, LMC_DS3_LED0); + lmc_led_on(sc, LMC_DS3_LED1); + mdelay(100); + lmc_led_off(sc, LMC_DS3_LED1); + lmc_led_on(sc, LMC_DS3_LED3); + mdelay(100); + lmc_led_off(sc, LMC_DS3_LED3); + lmc_led_on(sc, LMC_DS3_LED2); + mdelay(100); + lmc_led_off(sc, LMC_DS3_LED2); + } + } + + + + ret = 0x0; + + } + + break; + case lmc_xilinx_load_prom: /*fold02*/ + { + u16 mii; + int timeout = 500000; + mii = lmc_mii_readreg (sc, 0, 16); + + /* + * Make all of them 0 and make input + */ + lmc_gpio_mkinput(sc, 0xff); + + /* + * make the reset output + */ + lmc_gpio_mkoutput(sc, LMC_GEP_DP | LMC_GEP_RESET); + + /* + * RESET low to force configuration. This also forces + * the transmitter clock to be internal, but we expect to reset + * that later anyway. + */ + + sc->lmc_gpio &= ~(LMC_GEP_RESET | LMC_GEP_DP); + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + + /* + * hold for more than 10 microseconds + */ + udelay(50); + + sc->lmc_gpio |= LMC_GEP_DP | LMC_GEP_RESET; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + /* + * busy wait for the chip to reset + */ + while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 && + (timeout-- > 0)) + ; + + + /* + * stop driving Xilinx-related signals + */ + lmc_gpio_mkinput(sc, 0xff); + + ret = 0x0; + + + break; + + } + + case lmc_xilinx_load: /*fold02*/ + { + char *data; + int pos; + int timeout = 500000; + + if(xc.data == 0x0){ + ret = -EINVAL; + break; + } + + data = kmalloc(xc.len, GFP_KERNEL); + if(data == 0x0){ + printk(KERN_WARNING "%s: Failed to allocate memory for copy\n", dev->name); + ret = -ENOMEM; + break; + } + + LMC_COPY_FROM_USER(data, xc.data, xc.len); + + printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data); + + lmc_gpio_mkinput(sc, 0xff); + + /* + * Clear the Xilinx and start prgramming from the DEC + */ + + /* + * Set ouput as: + * Reset: 0 (active) + * DP: 0 (active) + * Mode: 1 + * + */ + sc->lmc_gpio = 0x00; + sc->lmc_gpio &= ~LMC_GEP_DP; + sc->lmc_gpio &= ~LMC_GEP_RESET; + sc->lmc_gpio |= LMC_GEP_MODE; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + lmc_gpio_mkoutput(sc, LMC_GEP_MODE | LMC_GEP_DP | LMC_GEP_RESET); + + /* + * Wait at least 10 us 20 to be safe + */ + udelay(50); + + /* + * Clear reset and activate programing lines + * Reset: Input + * DP: Input + * Clock: Output + * Data: Output + * Mode: Output + */ + lmc_gpio_mkinput(sc, LMC_GEP_DP | LMC_GEP_RESET); + + /* + * Set LOAD, DATA, Clock to 1 + */ + sc->lmc_gpio = 0x00; + sc->lmc_gpio |= LMC_GEP_MODE; + sc->lmc_gpio |= LMC_GEP_DATA; + sc->lmc_gpio |= LMC_GEP_CLK; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + lmc_gpio_mkoutput(sc, LMC_GEP_DATA | LMC_GEP_CLK | LMC_GEP_MODE ); + + /* + * busy wait for the chip to reset + */ + while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 && + (timeout-- > 0)) + ; + + printk(KERN_DEBUG "%s: Waited %d for the Xilinx to clear it's memory\n", dev->name, 500000-timeout); + + for(pos = 0; pos < xc.len; pos++){ + switch(data[pos]){ + case 0: + sc->lmc_gpio &= ~LMC_GEP_DATA; /* Data is 0 */ + break; + case 1: + sc->lmc_gpio |= LMC_GEP_DATA; /* Data is 1 */ + break; + default: + printk(KERN_WARNING "%s Bad data in xilinx programing data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]); + sc->lmc_gpio |= LMC_GEP_DATA; /* Assume it's 1 */ + } + sc->lmc_gpio &= ~LMC_GEP_CLK; /* Clock to zero */ + sc->lmc_gpio |= LMC_GEP_MODE; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + udelay(1); + + sc->lmc_gpio |= LMC_GEP_CLK; /* Put the clack back to one */ + sc->lmc_gpio |= LMC_GEP_MODE; + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + udelay(1); + } + if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0){ + printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (corrupted data)\n", dev->name); + } + else if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0){ + printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (done)\n", dev->name); + } + else { + printk(KERN_DEBUG "%s: Done reprograming Xilinx, %d bits, good luck!\n", dev->name, pos); + } + + lmc_gpio_mkinput(sc, 0xff); + + sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + + sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + + kfree(data); + + ret = 0; + + break; + } + default: /*fold02*/ + ret = -EBADE; + break; + } + + LMC_XMITTER_FREE(dev); + sc->lmc_txfull = 0; + + } + break; + default: /*fold01*/ + /* If we don't know what to do, give the protocol a shot. */ + ret = lmc_proto_ioctl (sc, ifr, cmd); + break; + } + + spin_unlock_irqrestore(&sc->lmc_lock, flags); /*fold01*/ + + lmc_trace(dev, "lmc_ioctl out"); + + return ret; +} + + +/* the watchdog process that cruises around */ +static void lmc_watchdog (unsigned long data) /*fold00*/ +{ + struct net_device *dev = (struct net_device *) data; + lmc_softc_t *sc; + int link_status; + u_int32_t ticks; + LMC_SPIN_FLAGS; + + sc = dev->priv; + + lmc_trace(dev, "lmc_watchdog in"); + + spin_lock_irqsave(&sc->lmc_lock, flags); + + if(sc->check != 0xBEAFCAFE){ + printk("LMC: Corrupt net_device stuct, breaking out\n"); + return; + } + + + /* Make sure the tx jabber and rx watchdog are off, + * and the transmit and recieve processes are running. + */ + + LMC_CSR_WRITE (sc, csr_15, 0x00000011); + sc->lmc_cmdmode |= TULIP_CMD_TXRUN | TULIP_CMD_RXRUN; + LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode); + + if (sc->lmc_ok == 0) + goto kick_timer; + + LMC_EVENT_LOG(LMC_EVENT_WATCHDOG, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16)); + + /* --- begin time out check ----------------------------------- + * check for a transmit interrupt timeout + * Has the packet xmt vs xmt serviced threshold been exceeded */ + if (sc->lmc_taint_tx == sc->lastlmc_taint_tx && + sc->stats.tx_packets > sc->lasttx_packets && + sc->tx_TimeoutInd == 0) + { + + /* wait for the watchdog to come around again */ + sc->tx_TimeoutInd = 1; + } + else if (sc->lmc_taint_tx == sc->lastlmc_taint_tx && + sc->stats.tx_packets > sc->lasttx_packets && + sc->tx_TimeoutInd) + { + + LMC_EVENT_LOG(LMC_EVENT_XMTINTTMO, LMC_CSR_READ (sc, csr_status), 0); + + sc->tx_TimeoutDisplay = 1; + sc->stats.tx_TimeoutCnt++; + + /* DEC chip is stuck, hit it with a RESET!!!! */ + lmc_running_reset (dev); + + + /* look at receive & transmit process state to make sure they are running */ + LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); + + /* look at: DSR - 02 for Reg 16 + * CTS - 08 + * DCD - 10 + * RI - 20 + * for Reg 17 + */ + LMC_EVENT_LOG(LMC_EVENT_RESET2, lmc_mii_readreg (sc, 0, 16), lmc_mii_readreg (sc, 0, 17)); + + /* reset the transmit timeout detection flag */ + sc->tx_TimeoutInd = 0; + sc->lastlmc_taint_tx = sc->lmc_taint_tx; + sc->lasttx_packets = sc->stats.tx_packets; + } + else + { + sc->tx_TimeoutInd = 0; + sc->lastlmc_taint_tx = sc->lmc_taint_tx; + sc->lasttx_packets = sc->stats.tx_packets; + } + + /* --- end time out check ----------------------------------- */ + + + link_status = sc->lmc_media->get_link_status (sc); + + /* + * hardware level link lost, but the interface is marked as up. + * Mark it as down. + */ + if ((link_status == 0) && (sc->last_link_status != 0)) { + printk(KERN_WARNING "%s: hardware/physical link down\n", dev->name); + sc->last_link_status = 0; + /* lmc_reset (sc); Why reset??? The link can go down ok */ + + /* Inform the world that link has been lost */ + dev->flags &= ~IFF_RUNNING; + } + + /* + * hardware link is up, but the interface is marked as down. + * Bring it back up again. + */ + if (link_status != 0 && sc->last_link_status == 0) { + printk(KERN_WARNING "%s: hardware/physical link up\n", dev->name); + sc->last_link_status = 1; + /* lmc_reset (sc); Again why reset??? */ + + /* Inform the world that link protocol is back up. */ + dev->flags |= IFF_RUNNING; + + /* Now we have to tell the syncppp that we had an outage + * and that it should deal. Calling sppp_reopen here + * should do the trick, but we may have to call sppp_close + * when the link goes down, and call sppp_open here. + * Subject to more testing. + * --bbraun + */ + + lmc_proto_reopen(sc); + + } + + /* Call media specific watchdog functions */ + sc->lmc_media->watchdog(sc); + + /* + * Poke the transmitter to make sure it + * never stops, even if we run out of mem + */ + LMC_CSR_WRITE(sc, csr_rxpoll, 0); + + /* + * Check for code that failed + * and try and fix it as appropriate + */ + if(sc->failed_ring == 1){ + /* + * Failed to setup the recv/xmit rin + * Try again + */ + sc->failed_ring = 0; + lmc_softreset(sc); + } + if(sc->failed_recv_alloc == 1){ + /* + * We failed to alloc mem in the + * interupt halder, go through the rings + * and rebuild them + */ + sc->failed_recv_alloc = 0; + lmc_softreset(sc); + } + + + /* + * remember the timer value + */ +kick_timer: + + ticks = LMC_CSR_READ (sc, csr_gp_timer); + LMC_CSR_WRITE (sc, csr_gp_timer, 0xffffffffUL); + sc->ictl.ticks = 0x0000ffff - (ticks & 0x0000ffff); + + /* + * restart this timer. + */ + sc->timer.expires = jiffies + (HZ); + add_timer (&sc->timer); + + spin_unlock_irqrestore(&sc->lmc_lock, flags); + + lmc_trace(dev, "lmc_watchdog out"); + +} + +static int lmc_init(struct net_device * const dev) /*fold00*/ +{ + lmc_trace(dev, "lmc_init in"); + lmc_trace(dev, "lmc_init out"); + + return 0; +} + +/* This initializes each card from lmc_probe() */ +static struct net_device *lmc_probe1 (struct net_device *dev, unsigned long ioaddr, unsigned int irq, /*fold00*/ + int chip_id, int subdevice, int board_idx) +{ + lmc_softc_t *sc = NULL; + u_int16_t AdapModelNum; + + /* + * Allocate our own device structure + */ + +#if LINUX_VERSION_CODE < 0x20363 + dev = kmalloc (sizeof (struct ppp_device)+8, GFP_KERNEL); +#else + dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL); +#endif + if (dev == NULL){ + printk (KERN_ERR "lmc: kmalloc for device failed\n"); + return NULL; + } + memset (dev, 0, sizeof (struct net_device)); + +#ifndef GCOM + /* + * Switch to common hdlc%d naming. We name by type not by vendor + */ +#if LINUX_VERSION_CODE < 0x20363 + dev->name = ((char *) (dev)) + sizeof (struct ppp_device); +#else + dev->name = ((char *) (dev)) + sizeof (struct net_device); +#endif + + dev_alloc_name(dev, "hdlc%d"); +#else + /* + * GCOM uses LMC vendor name so that clients can know which card + * to attach to. + */ + dev->name = ((char *) (dev)) + sizeof (struct ppp_device); + dev_alloc_name(dev, "lmc%d"); +#endif + + lmc_trace(dev, "lmc_probe1 in"); + + Lmc_Count++; + + if(lmc_first_load == 0){ + printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n",DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION); + lmc_first_load = 1; + } + + /* + * Allocate space for the private data structure + */ + + sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL); + if (sc == NULL) { + printk (KERN_WARNING "%s: Cannot allocate memory for device state\n", + dev->name); + return (NULL); + } + memset (sc, 0, sizeof (lmc_softc_t)); + dev->priv = sc; + sc->lmc_device = dev; + sc->name = dev->name; + + /* Initialize the sppp layer */ + /* An ioctl can cause a subsequent detach for raw frame interface */ + sc->if_type = LMC_PPP; + sc->check = 0xBEAFCAFE; + dev->base_addr = ioaddr; + dev->irq = irq; + /* + * This will get the protocol layer ready and do any 1 time init's + * Must have a valid sc and dev structure + */ + lmc_proto_init(sc); + + lmc_proto_attach(sc); + + /* Just fill in the entries for the device */ + + dev->init = lmc_init; + dev->type = ARPHRD_HDLC; + dev->hard_start_xmit = lmc_start_xmit; + dev->open = lmc_open; + dev->stop = lmc_close; + dev->get_stats = lmc_get_stats; + dev->do_ioctl = lmc_ioctl; + dev->set_config = lmc_set_config; +#if LINUX_VERSION_CODE >= 0x20363 + dev->tx_timeout = lmc_driver_timeout; + dev->watchdog_timeo = (HZ); /* 1 second */ +#endif + + /* + * Why were we changing this??? + dev->tx_queue_len = 100; + */ + + /* Init the spin lock so can call it latter */ + + spin_lock_init(&sc->lmc_lock); + + LMC_SETUP_20_DEV; + + printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq); + + if (register_netdev (dev) != 0) { + printk (KERN_ERR "%s: register_netdev failed.\n", dev->name); + lmc_proto_detach(sc); + kfree (dev->priv); + kfree (dev); + return NULL; + } + + /* + * Request the region of registers we need, so that + * later on, no one else will take our card away from + * us. + */ + request_region (ioaddr, LMC_REG_RANGE, dev->name); + + sc->lmc_cardtype = LMC_CARDTYPE_UNKNOWN; + sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT; + + switch (subdevice) { + case PCI_PRODUCT_LMC_HSSI: + printk ("%s: LMC HSSI\n", dev->name); + sc->lmc_cardtype = LMC_CARDTYPE_HSSI; + sc->lmc_media = &lmc_hssi_media; + break; + case PCI_PRODUCT_LMC_DS3: + printk ("%s: LMC DS3\n", dev->name); + sc->lmc_cardtype = LMC_CARDTYPE_DS3; + sc->lmc_media = &lmc_ds3_media; + break; + case PCI_PRODUCT_LMC_SSI: + printk ("%s: LMC SSI\n", dev->name); + sc->lmc_cardtype = LMC_CARDTYPE_SSI; + sc->lmc_media = &lmc_ssi_media; + break; + case PCI_PRODUCT_LMC_T1: + printk ("%s: LMC T1\n", dev->name); + sc->lmc_cardtype = LMC_CARDTYPE_T1; + sc->lmc_media = &lmc_t1_media; + break; + default: + printk (KERN_WARNING "%s: LMC UNKOWN CARD!\n", dev->name); + break; + } + + lmc_initcsrs (sc, dev->base_addr, 8); + + lmc_gpio_mkinput (sc, 0xff); + sc->lmc_gpio = 0; /* drive no signals yet */ + + sc->lmc_media->defaults (sc); + + sc->lmc_media->set_link_status (sc, LMC_LINK_UP); + + /* verify that the PCI Sub System ID matches the Adapter Model number + * from the MII register + */ + AdapModelNum = (lmc_mii_readreg (sc, 0, 3) & 0x3f0) >> 4; + + if ((AdapModelNum == LMC_ADAP_T1 + && subdevice == PCI_PRODUCT_LMC_T1) || /* detect LMC1200 */ + (AdapModelNum == LMC_ADAP_SSI + && subdevice == PCI_PRODUCT_LMC_SSI) || /* detect LMC1000 */ + (AdapModelNum == LMC_ADAP_DS3 + && subdevice == PCI_PRODUCT_LMC_DS3) || /* detect LMC5245 */ + (AdapModelNum == LMC_ADAP_HSSI + && subdevice == PCI_PRODUCT_LMC_HSSI)) + { /* detect LMC5200 */ + + } + else { + printk ("%s: Model number (%d) miscompare for PCI Subsystem ID = 0x%04x\n", + dev->name, AdapModelNum, subdevice); +// return (NULL); + } + /* + * reset clock + */ + LMC_CSR_WRITE (sc, csr_gp_timer, 0xFFFFFFFFUL); + + sc->board_idx = board_idx; + + memset (&sc->stats, 0, sizeof (struct lmc_statistics)); + + sc->stats.check = STATCHECK; + sc->stats.version_size = (DRIVER_VERSION << 16) + + sizeof (struct lmc_statistics); + sc->stats.lmc_cardtype = sc->lmc_cardtype; + + sc->lmc_ok = 0; + sc->last_link_status = 0; + + lmc_trace(dev, "lmc_probe1 out"); + + return dev; +} + + +/* This is the entry point. This is what is called immediatly. */ +/* This goes out and finds the card */ + +int lmc_probe_fake(struct net_device *dev) /*fold00*/ +{ + lmc_probe(NULL); + /* Return 1 to unloaded bogus device */ + return 1; +} + +int lmc_probe (struct net_device *dev) /*fold00*/ +{ + int pci_index = 0; +#if LINUX_VERSION_CODE >= 0x20155 + unsigned long pci_ioaddr; + unsigned short pci_command; + unsigned int pci_irq_line; +#else + unsigned char pci_irq_line; + u32 pci_ioaddr; +#endif + u16 vendor, subvendor, device, subdevice; + u32 foundaddr = 0; + unsigned char pci_bus, pci_device_fn; + u8 intcf = 0; + + /* The card is only available on PCI, so if we don't have a + * PCI bus, we are in trouble. + */ + + if (!LMC_PCI_PRESENT()) { +/* printk ("%s: We really want a pci bios!\n", dev->name);*/ + return -1; + } + /* Loop basically until we don't find anymore. */ + while (pci_index < 0xff){ + /* The tulip is considered an ethernet class of card... */ + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, + pci_index, &pci_bus, + &pci_device_fn) != PCIBIOS_SUCCESSFUL) { + /* No card found on this pass */ + break; + } + /* Read the info we need to determine if this is + * our card or not + */ +#if LINUX_VERSION_CODE >= 0x20155 + vendor = pci_find_slot (pci_bus, pci_device_fn)->vendor; + device = pci_find_slot (pci_bus, pci_device_fn)->device; + pci_irq_line = pci_find_slot (pci_bus, pci_device_fn)->irq; +#if LINUX_VERSION_CODE < 0x20363 + pci_ioaddr = pci_find_slot (pci_bus, pci_device_fn)->base_address[0]; +#else + pci_ioaddr = pci_resource_start (pci_find_slot (pci_bus, pci_device_fn), 0); +#endif + pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn), + PCI_SUBSYSTEM_VENDOR_ID, &subvendor); + pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn), + PCI_SUBSYSTEM_ID, &subdevice); + /* + * SPARC PCI Bios doesn't set the BUS Master bit, unlike intel + * Without it we won't do much packet work + * Do this to everyone + */ + pci_read_config_word(pci_find_slot (pci_bus, pci_device_fn), PCI_COMMAND, + &pci_command); + pci_command |= PCI_COMMAND_MASTER; + pci_write_config_word(pci_find_slot (pci_bus, pci_device_fn), PCI_COMMAND, + pci_command); +#else + pcibios_read_config_word (pci_bus, pci_device_fn, + PCI_VENDOR_ID, &vendor); + pcibios_read_config_word (pci_bus, pci_device_fn, + PCI_DEVICE_ID, &device); + pcibios_read_config_byte (pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + pcibios_read_config_word (pci_bus, pci_device_fn, + PCI_SUBSYSTEM_VENDOR_ID, &subvendor); + pcibios_read_config_word (pci_bus, pci_device_fn, + PCI_SUBSYSTEM_ID, &subdevice); +#endif + + /* Align the io address on the 32 bit boundry just in case */ + pci_ioaddr &= ~3; + + /* + * Make sure it's the correct card. CHECK SUBVENDOR ID! + * There are lots of tulip's out there. + * Also check the region of registers we will soon be + * poking, to make sure no one else has reserved them. + * This prevents taking someone else's device. + * + * Check either the subvendor or the subdevice, some systems reverse + * the setting in the bois, seems to be version and arch dependant? + * Fix the two variables + * + */ + if (!(check_region (pci_ioaddr, LMC_REG_RANGE)) && + (vendor == CORRECT_VENDOR_ID) && + (device == CORRECT_DEV_ID) && + ((subvendor == PCI_VENDOR_LMC) || (subdevice == PCI_VENDOR_LMC))){ + struct net_device *cur, *prev = NULL; + + /* Fix the error, exchange the two values */ + if(subdevice == PCI_VENDOR_LMC){ + subdevice = subvendor; + subvendor = PCI_VENDOR_LMC ; + } + + /* Make the call to actually setup this card */ + dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line, + device, subdevice, cards_found); + if (dev == NULL) { + printk ("lmc_probe: lmc_probe1 failed\n"); + goto lmc_probe_next_card; + } + /* insert the device into the chain of lmc devices */ + for (cur = Lmc_root_dev; + cur != NULL; + cur = ((lmc_softc_t *) cur->priv)->next_module) { + prev = cur; + } + + if (prev == NULL) + Lmc_root_dev = dev; + else + ((lmc_softc_t *) prev->priv)->next_module = dev; + + ((lmc_softc_t *) dev->priv)->next_module = NULL; + /* end insert */ + + foundaddr = dev->base_addr; + + cards_found++; + intcf++; + } + lmc_probe_next_card: + pci_index++; + } + + if (cards_found < 1) + return -1; + +#if LINUX_VERSION_CODE >= 0x20200 + return foundaddr; +#else + return 0; +#endif +} + +/* After this is called, packets can be sent. + * Does not initialize the addresses + */ +static int lmc_open (struct net_device *dev) /*fold00*/ +{ + lmc_softc_t *sc = dev->priv; + + lmc_trace(dev, "lmc_open in"); + + lmc_led_on(sc, LMC_DS3_LED0); + + lmc_dec_reset (sc); + lmc_reset (sc); + + LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); + LMC_EVENT_LOG(LMC_EVENT_RESET2, + lmc_mii_readreg (sc, 0, 16), + lmc_mii_readreg (sc, 0, 17)); + + + if (sc->lmc_ok){ + lmc_trace(dev, "lmc_open lmc_ok out"); + return (0); + } + + lmc_softreset (sc); + + /* Since we have to use PCI bus, this should work on x86,alpha,ppc */ + if (request_irq (dev->irq, &lmc_interrupt, SA_SHIRQ, dev->name, dev)){ + printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq); + lmc_trace(dev, "lmc_open irq failed out"); + return -EAGAIN; + } + sc->got_irq = 1; + + /* Assert Terminal Active */ + sc->lmc_miireg16 |= LMC_MII16_LED_ALL; + sc->lmc_media->set_link_status (sc, LMC_LINK_UP); + + /* + * reset to last state. + */ + sc->lmc_media->set_status (sc, NULL); + + /* setup default bits to be used in tulip_desc_t transmit descriptor + * -baz */ + sc->TxDescriptControlInit = ( + LMC_TDES_INTERRUPT_ON_COMPLETION + | LMC_TDES_FIRST_SEGMENT + | LMC_TDES_LAST_SEGMENT + | LMC_TDES_SECOND_ADDR_CHAINED + | LMC_TDES_DISABLE_PADDING + ); + + if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16) { + /* disable 32 bit CRC generated by ASIC */ + sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE; + } + sc->lmc_media->set_crc_length(sc, sc->ictl.crc_length); + /* Acknoledge the Terminal Active and light LEDs */ + + /* dev->flags |= IFF_UP; */ + + lmc_proto_open(sc); + + dev->do_ioctl = lmc_ioctl; + + + LMC_XMITTER_INIT(dev); + +#if LINUX_VERSION_CODE < 0x20363 + dev->start = 1; +#endif + + sc->stats.tx_tbusy0++ ; + + MOD_INC_USE_COUNT; + + /* + * select what interrupts we want to get + */ + sc->lmc_intrmask = 0; + /* Should be using the default interrupt mask defined in the .h file. */ + sc->lmc_intrmask |= (TULIP_STS_NORMALINTR + | TULIP_STS_RXINTR + | TULIP_STS_TXINTR + | TULIP_STS_ABNRMLINTR + | TULIP_STS_SYSERROR + | TULIP_STS_TXSTOPPED + | TULIP_STS_TXUNDERFLOW + | TULIP_STS_RXSTOPPED + | TULIP_STS_RXNOBUF + ); + LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask); + + sc->lmc_cmdmode |= TULIP_CMD_TXRUN; + sc->lmc_cmdmode |= TULIP_CMD_RXRUN; + LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode); + + sc->lmc_ok = 1; /* Run watchdog */ + + /* + * Set the if up now - pfb + */ + + sc->last_link_status = 1; + + /* + * Setup a timer for the watchdog on probe, and start it running. + * Since lmc_ok == 0, it will be a NOP for now. + */ + init_timer (&sc->timer); + sc->timer.expires = jiffies + HZ; + sc->timer.data = (unsigned long) dev; + sc->timer.function = &lmc_watchdog; + add_timer (&sc->timer); + + lmc_trace(dev, "lmc_open out"); + + return (0); +} + +/* Total reset to compensate for the AdTran DSU doing bad things + * under heavy load + */ + +static void lmc_running_reset (struct net_device *dev) /*fold00*/ +{ + + lmc_softc_t *sc = (lmc_softc_t *) dev->priv; + + lmc_trace(dev, "lmc_runnig_reset in"); + + /* stop interrupts */ + /* Clear the interrupt mask */ + LMC_CSR_WRITE (sc, csr_intr, 0x00000000); + + lmc_dec_reset (sc); + lmc_reset (sc); + lmc_softreset (sc); + /* sc->lmc_miireg16 |= LMC_MII16_LED_ALL; */ + sc->lmc_media->set_link_status (sc, 1); + sc->lmc_media->set_status (sc, NULL); + + //dev->flags |= IFF_RUNNING; + + LMC_XMITTER_FREE(dev); + + sc->lmc_txfull = 0; + sc->stats.tx_tbusy0++ ; + + sc->lmc_intrmask = TULIP_DEFAULT_INTR_MASK; + LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask); + + sc->lmc_cmdmode |= (TULIP_CMD_TXRUN | TULIP_CMD_RXRUN); + LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode); + + lmc_trace(dev, "lmc_runnin_reset_out"); +} + + +/* This is what is called when you ifconfig down a device. + * This disables the timer for the watchdog and keepalives, + * and disables the irq for dev. + */ +static int lmc_close (struct net_device *dev) /*fold00*/ +{ + /* not calling release_region() as we should */ + lmc_softc_t *sc; + + lmc_trace(dev, "lmc_close in"); + + sc = dev->priv; + sc->lmc_ok = 0; + sc->lmc_media->set_link_status (sc, 0); + del_timer (&sc->timer); + lmc_proto_close(sc); + lmc_ifdown (dev); + + lmc_trace(dev, "lmc_close out"); + + return 0; +} + +/* Ends the transfer of packets */ +/* When the interface goes down, this is called */ +static int lmc_ifdown (struct net_device *dev) /*fold00*/ +{ + lmc_softc_t *sc = dev->priv; + u32 csr6; + int i; + + lmc_trace(dev, "lmc_ifdown in"); + + /* Don't let anything else go on right now */ + // dev->start = 0; + LMC_XMITTER_BUSY(dev); + sc->stats.tx_tbusy1++ ; + + /* stop interrupts */ + /* Clear the interrupt mask */ + LMC_CSR_WRITE (sc, csr_intr, 0x00000000); + + /* Stop Tx and Rx on the chip */ + csr6 = LMC_CSR_READ (sc, csr_command); + csr6 &= ~LMC_DEC_ST; /* Turn off the Transmission bit */ + csr6 &= ~LMC_DEC_SR; /* Turn off the Recieve bit */ + LMC_CSR_WRITE (sc, csr_command, csr6); + + dev->flags &= ~IFF_RUNNING; + + sc->stats.rx_missed_errors += + LMC_CSR_READ (sc, csr_missed_frames) & 0xffff; + + /* release the interrupt */ + if(sc->got_irq == 1){ + free_irq (dev->irq, dev); + sc->got_irq = 0; + } + + /* free skbuffs in the Rx queue */ + for (i = 0; i < LMC_RXDESCS; i++) + { + struct sk_buff *skb = sc->lmc_rxq[i]; + sc->lmc_rxq[i] = 0; + sc->lmc_rxring[i].status = 0; + sc->lmc_rxring[i].length = 0; + sc->lmc_rxring[i].buffer1 = 0xDEADBEEF; + if (skb != NULL) + { + LMC_SKB_FREE(skb, 1); + LMC_DEV_KFREE_SKB (skb); + } + sc->lmc_rxq[i] = NULL; + } + + for (i = 0; i < LMC_TXDESCS; i++) + { + if (sc->lmc_txq[i] != NULL) + LMC_DEV_KFREE_SKB (sc->lmc_txq[i]); + sc->lmc_txq[i] = NULL; + } + + lmc_led_off (sc, LMC_MII16_LED_ALL); + + LMC_XMITTER_FREE(dev); + sc->stats.tx_tbusy0++ ; + + lmc_trace(dev, "lmc_ifdown out"); + + MOD_DEC_USE_COUNT; + return 0; +} + +/* Interrupt handling routine. This will take an incoming packet, or clean + * up after a trasmit. + */ +static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/ +{ + struct net_device *dev = (struct net_device *) dev_instance; + lmc_softc_t *sc; + u32 csr; + int i; + s32 stat; + unsigned int badtx; + u32 firstcsr; + int max_work = LMC_RXDESCS; + + lmc_trace(dev, "lmc_interrupt in"); + + sc = dev->priv; + + spin_lock(&sc->lmc_lock); + + /* + * Read the csr to find what interupts we have (if any) + */ + csr = LMC_CSR_READ (sc, csr_status); + + /* + * Make sure this is our interrupt + */ + if ( ! (csr & sc->lmc_intrmask)) { + goto lmc_int_fail_out; + } + + firstcsr = csr; + + /* always go through this loop at least once */ + while (csr & sc->lmc_intrmask) { + /* + * Clear interupt bits, we handle all case below + */ + LMC_CSR_WRITE (sc, csr_status, csr); + + /* + * One of + * - Transmit process timed out CSR5<1> + * - Transmit jabber timeout CSR5<3> + * - Transmit underflow CSR5<5> + * - Transmit Receiver buffer unavailable CSR5<7> + * - Receive process stopped CSR5<8> + * - Receive watchdog timeout CSR5<9> + * - Early transmit interrupt CSR5<10> + * + * Is this really right? Should we do a running reset for jabber? + * (being a WAN card and all) + */ + if (csr & TULIP_STS_ABNRMLINTR){ + lmc_running_reset (dev); + break; + } + + if (csr & TULIP_STS_RXINTR){ + lmc_trace(dev, "rx interupt"); + lmc_rx (dev); + + } + if (csr & (TULIP_STS_TXINTR | TULIP_STS_TXNOBUF | TULIP_STS_TXSTOPPED)) { + + int n_compl = 0 ; + /* reset the transmit timeout detection flag -baz */ + sc->stats.tx_NoCompleteCnt = 0; + + badtx = sc->lmc_taint_tx; + i = badtx % LMC_TXDESCS; + + while ((badtx < sc->lmc_next_tx)) { + stat = sc->lmc_txring[i].status; + + LMC_EVENT_LOG (LMC_EVENT_XMTINT, stat, + sc->lmc_txring[i].length); + /* + * If bit 31 is 1 the tulip owns it break out of the loop + */ + if (stat & 0x80000000) + break; + + n_compl++ ; /* i.e., have an empty slot in ring */ + /* + * If we have no skbuff or have cleared it + * Already continue to the next buffer + */ + if (sc->lmc_txq[i] == NULL) + continue; + + /* + * Check the total error summary to look for any errors + */ + if (stat & 0x8000) { + sc->stats.tx_errors++; + if (stat & 0x4104) + sc->stats.tx_aborted_errors++; + if (stat & 0x0C00) + sc->stats.tx_carrier_errors++; + if (stat & 0x0200) + sc->stats.tx_window_errors++; + if (stat & 0x0002) + sc->stats.tx_fifo_errors++; + } + else { + +#if LINUX_VERSION_CODE >= 0x20200 + sc->stats.tx_bytes += sc->lmc_txring[i].length & 0x7ff; +#endif + + sc->stats.tx_packets++; + } + + // LMC_DEV_KFREE_SKB (sc->lmc_txq[i]); + dev_kfree_skb_irq(sc->lmc_txq[i]); + sc->lmc_txq[i] = 0; + + badtx++; + i = badtx % LMC_TXDESCS; + } + + if (sc->lmc_next_tx - badtx > LMC_TXDESCS) + { + printk ("%s: out of sync pointer\n", dev->name); + badtx += LMC_TXDESCS; + } + LMC_EVENT_LOG(LMC_EVENT_TBUSY0, n_compl, 0); + sc->lmc_txfull = 0; + LMC_XMITTER_FREE(dev); + sc->stats.tx_tbusy0++ ; +#if LINUX_VERSION_CODE < 0x20363 + mark_bh (NET_BH); /* Tell Linux to give me more packets */ +#endif + + +#ifdef DEBUG + sc->stats.dirtyTx = badtx; + sc->stats.lmc_next_tx = sc->lmc_next_tx; + sc->stats.lmc_txfull = sc->lmc_txfull; +#if LINUX_VERSION_CODE < 0x20363 + sc->stats.tbusy = dev->tbusy; +#endif +#endif + sc->lmc_taint_tx = badtx; + + /* + * Why was there a break here??? + */ + } /* end handle transmit interrupt */ + + if (csr & TULIP_STS_SYSERROR) { + u32 error; + printk (KERN_WARNING "%s: system bus error csr: %#8.8x\n", dev->name, csr); + error = csr>>23 & 0x7; + switch(error){ + case 0x000: + printk(KERN_WARNING "%s: Parity Fault (bad)\n", dev->name); + break; + case 0x001: + printk(KERN_WARNING "%s: Master Abort (naughty)\n", dev->name); + break; + case 0x010: + printk(KERN_WARNING "%s: Target Abort (not so naughty)\n", dev->name); + break; + default: + printk(KERN_WARNING "%s: This bus error code was supposed to be reserved!\n", dev->name); + } + lmc_dec_reset (sc); + lmc_reset (sc); + LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); + LMC_EVENT_LOG(LMC_EVENT_RESET2, + lmc_mii_readreg (sc, 0, 16), + lmc_mii_readreg (sc, 0, 17)); + + } + + + if(max_work-- <= 0) + break; + + /* + * Get current csr status to make sure + * we've cleared all interupts + */ + csr = LMC_CSR_READ (sc, csr_status); + } /* end interrupt loop */ + LMC_EVENT_LOG(LMC_EVENT_INT, firstcsr, csr); + +lmc_int_fail_out: + + spin_unlock(&sc->lmc_lock); + + lmc_trace(dev, "lmc_interrupt out"); + + return; +} + +static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/ +{ + lmc_softc_t *sc; + u32 flag; + int entry; + int ret = 0; + LMC_SPIN_FLAGS; + + lmc_trace(dev, "lmc_start_xmit in"); + + sc = dev->priv; + + spin_lock_irqsave(&sc->lmc_lock, flags); + + /* + * If the transmitter is busy + * this must be the 5 second polling + * from the kernel which called us. + * Poke the chip and try to get it running + * + */ +#if LINUX_VERSION_CODE < 0x20363 + if(dev->tbusy != 0){ + u32 csr6; + + printk("%s: Xmitter busy|\n", dev->name); + + sc->stats.tx_tbusy_calls++ ; + if (jiffies - dev->trans_start < TX_TIMEOUT) { + ret = 1; + goto lmc_start_xmit_bug_out; + } + + /* + * Chip seems to have locked up + * Reset it + * This whips out all our decriptor + * table and starts from scartch + */ + + LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO, + LMC_CSR_READ (sc, csr_status), + sc->stats.tx_ProcTimeout); + + lmc_running_reset (dev); + + LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); + LMC_EVENT_LOG(LMC_EVENT_RESET2, + lmc_mii_readreg (sc, 0, 16), + lmc_mii_readreg (sc, 0, 17)); + + /* restart the tx processes */ + csr6 = LMC_CSR_READ (sc, csr_command); + LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002); + LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002); + + /* immediate transmit */ + LMC_CSR_WRITE (sc, csr_txpoll, 0); + + sc->stats.tx_errors++; + sc->stats.tx_ProcTimeout++; /* -baz */ + + dev->trans_start = jiffies; + + ret = 1; + goto lmc_start_xmit_bug_out; + } +#endif + /* normal path, tbusy known to be zero */ + + entry = sc->lmc_next_tx % LMC_TXDESCS; + + sc->lmc_txq[entry] = skb; + sc->lmc_txring[entry].buffer1 = virt_to_bus (skb->data); + + LMC_CONSOLE_LOG("xmit", skb->data, skb->len); + +#ifndef GCOM + /* If the queue is less than half full, don't interrupt */ + if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS / 2) + { + /* Do not interrupt on completion of this packet */ + flag = 0x60000000; + LMC_XMITTER_FREE(dev); + } + else if (sc->lmc_next_tx - sc->lmc_taint_tx == LMC_TXDESCS / 2) + { + /* This generates an interrupt on completion of this packet */ + flag = 0xe0000000; + LMC_XMITTER_FREE(dev); + } + else if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS - 1) + { + /* Do not interrupt on completion of this packet */ + flag = 0x60000000; + LMC_XMITTER_FREE(dev); + } + else + { + /* This generates an interrupt on completion of this packet */ + flag = 0xe0000000; + sc->lmc_txfull = 1; + LMC_XMITTER_BUSY(dev); + } +#else + flag = LMC_TDES_INTERRUPT_ON_COMPLETION; + + if (sc->lmc_next_tx - sc->lmc_taint_tx >= LMC_TXDESCS - 1) + { /* ring full, go busy */ + sc->lmc_txfull = 1; + LMC_XMITTER_BUSY(dev); + sc->stats.tx_tbusy1++ ; + LMC_EVENT_LOG(LMC_EVENT_TBUSY1, entry, 0); + } +#endif + + + if (entry == LMC_TXDESCS - 1) /* last descriptor in ring */ + flag |= LMC_TDES_END_OF_RING; /* flag as such for Tulip */ + + /* don't pad small packets either */ + flag = sc->lmc_txring[entry].length = (skb->len) | flag | + sc->TxDescriptControlInit; + + /* set the transmit timeout flag to be checked in + * the watchdog timer handler. -baz + */ + + sc->stats.tx_NoCompleteCnt++; + sc->lmc_next_tx++; + + /* give ownership to the chip */ + LMC_EVENT_LOG(LMC_EVENT_XMT, flag, entry); + sc->lmc_txring[entry].status = 0x80000000; + + /* send now! */ + LMC_CSR_WRITE (sc, csr_txpoll, 0); + + dev->trans_start = jiffies; + +#if LINUX_VERSION_CODE < 0x20363 +lmc_start_xmit_bug_out: +#endif + + spin_unlock_irqrestore(&sc->lmc_lock, flags); + + lmc_trace(dev, "lmc_start_xmit_out"); + return ret; +} + + +static int lmc_rx (struct net_device *dev) /*fold00*/ +{ + lmc_softc_t *sc; + int i; + int rx_work_limit = LMC_RXDESCS; + unsigned int next_rx; + int rxIntLoopCnt; /* debug -baz */ + int localLengthErrCnt = 0; + long stat; + struct sk_buff *skb, *nsb; + u16 len; + + lmc_trace(dev, "lmc_rx in"); + + sc = dev->priv; + + lmc_led_on(sc, LMC_DS3_LED3); + + rxIntLoopCnt = 0; /* debug -baz */ + + i = sc->lmc_next_rx % LMC_RXDESCS; + next_rx = sc->lmc_next_rx; + + while (((stat = sc->lmc_rxring[i].status) & LMC_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4) + { + rxIntLoopCnt++; /* debug -baz */ + len = ((stat & LMC_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER); + if ((stat & 0x0300) != 0x0300) { /* Check first segment and last segment */ + if ((stat & 0x0000ffff) != 0x7fff) { + /* Oversized frame */ + sc->stats.rx_length_errors++; + goto skip_packet; + } + } + + if(stat & 0x00000008){ /* Catch a dribbling bit error */ + sc->stats.rx_errors++; + sc->stats.rx_frame_errors++; + goto skip_packet; + } + + + if(stat & 0x00000004){ /* Catch a CRC error by the Xilinx */ + sc->stats.rx_errors++; + sc->stats.rx_crc_errors++; + goto skip_packet; + } + + + if (len > LMC_PKT_BUF_SZ){ + sc->stats.rx_length_errors++; + localLengthErrCnt++; + goto skip_packet; + } + + if (len < sc->lmc_crcSize + 2) { + sc->stats.rx_length_errors++; + sc->stats.rx_SmallPktCnt++; + localLengthErrCnt++; + goto skip_packet; + } + + if(stat & 0x00004000){ + printk(KERN_WARNING "%s: Receiver descriptor error, receiver out of sync?\n", dev->name); + } + + len -= sc->lmc_crcSize; + + skb = sc->lmc_rxq[i]; + + /* + * We ran out of memory at some point + * just allocate an skb buff and continue. + */ + + if(skb == 0x0){ + nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2); + if (nsb) { + LMC_SKB_FREE(nsb, 1); + sc->lmc_rxq[i] = nsb; + nsb->dev = dev; + sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail); + } + sc->failed_recv_alloc = 1; + goto skip_packet; + } + + dev->last_rx = jiffies; + sc->stats.rx_packets++; + + LMC_CONSOLE_LOG("recv", skb->data, len); + + /* + * I'm not sure of the sanity of this + * Packets could be arriving at a constant + * 44.210mbits/sec and we're going to copy + * them into a new buffer?? + */ + + if(len > (LMC_MTU - (LMC_MTU>>2))){ /* len > LMC_MTU * 0.75 */ + /* + * If it's a large packet don't copy it just hand it up + */ + give_it_anyways: + + sc->lmc_rxq[i] = 0x0; + sc->lmc_rxring[i].buffer1 = 0x0; + + skb_put (skb, len); + skb->protocol = lmc_proto_type(sc, skb); + skb->protocol = htons(ETH_P_WAN_PPP); + skb->mac.raw = skb->data; +// skb->nh.raw = skb->data; + skb->dev = dev; + lmc_proto_netif(sc, skb); + + /* + * This skb will be destroyed by the upper layers, make a new one + */ + nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2); + if (nsb) { + LMC_SKB_FREE(nsb, 1); + sc->lmc_rxq[i] = nsb; + nsb->dev = dev; + sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail); + /* Transfered to 21140 below */ + } + else { + /* + * We've run out of memory, stop trying to allocate + * memory and exit the interupt handler + * + * The chip may run out of receivers and stop + * in which care we'll try to allocate the buffer + * again. (once a second) + */ + sc->stats.rx_BuffAllocErr++; + LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, len); + sc->failed_recv_alloc = 1; + goto skip_out_of_mem; + } + } + else { + nsb = dev_alloc_skb(len); + if(!nsb) { + goto give_it_anyways; + } + memcpy(skb_put(nsb, len), skb->data, len); + + nsb->protocol = lmc_proto_type(sc, skb); + nsb->mac.raw = nsb->data; +// nsb->nh.raw = nsb->data; + nsb->dev = dev; + lmc_proto_netif(sc, nsb); + } + + skip_packet: + LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, len); + sc->lmc_rxring[i].status = DESC_OWNED_BY_DC21X4; + + sc->lmc_next_rx++; + i = sc->lmc_next_rx % LMC_RXDESCS; + rx_work_limit--; + if (rx_work_limit < 0) + break; + } + + /* detect condition for LMC1000 where DSU cable attaches and fills + * descriptors with bogus packets + * + if (localLengthErrCnt > LMC_RXDESCS - 3) { + sc->stats.rx_BadPktSurgeCnt++; + LMC_EVENT_LOG(LMC_EVENT_BADPKTSURGE, + localLengthErrCnt, + sc->stats.rx_BadPktSurgeCnt); + } */ + + /* save max count of receive descriptors serviced */ + if (rxIntLoopCnt > sc->stats.rxIntLoopCnt) { + sc->stats.rxIntLoopCnt = rxIntLoopCnt; /* debug -baz */ + } + +#ifdef DEBUG + if (rxIntLoopCnt == 0) + { + for (i = 0; i < LMC_RXDESCS; i++) + { + if ((sc->lmc_rxring[i].status & LMC_RDES_OWN_BIT) + != DESC_OWNED_BY_DC21X4) + { + rxIntLoopCnt++; + } + } + LMC_EVENT_LOG(LMC_EVENT_RCVEND, rxIntLoopCnt, 0); + } +#endif + + + lmc_led_off(sc, LMC_DS3_LED3); + +skip_out_of_mem: + + lmc_trace(dev, "lmc_rx out"); + + return 0; +} + +static struct enet_statistics *lmc_get_stats (struct net_device *dev) /*fold00*/ +{ + lmc_softc_t *sc; + LMC_SPIN_FLAGS; + + lmc_trace(dev, "lmc_get_stats in"); + + sc = dev->priv; + + spin_lock_irqsave(&sc->lmc_lock, flags); + + sc->stats.rx_missed_errors += LMC_CSR_READ (sc, csr_missed_frames) & 0xffff; + + spin_unlock_irqrestore(&sc->lmc_lock, flags); + + lmc_trace(dev, "lmc_get_stats out"); + + return (struct enet_statistics *) &sc->stats; +} + +#ifdef MODULE + +int init_module (void) /*fold00*/ +{ + printk ("lmc: module loaded\n"); + + /* Have lmc_probe search for all the cards, and allocate devices */ + if (lmc_probe (NULL) < 0) + return -EIO; + + return 0; +} + +void cleanup_module (void) /*fold00*/ +{ + struct net_device *dev, *next; + lmc_softc_t *sc; + + /* we have no pointer to our devices, since they are all dynamically + * allocated. So, here we loop through all the network devices + * looking for ours. When found, dispose of them properly. + */ + + for (dev = Lmc_root_dev; + dev != NULL; + dev = next ) + { + + next = ((lmc_softc_t *) dev->priv)->next_module; /* get it now before we deallocate it */ + printk ("%s: removing...\n", dev->name); + + /* close the syncppp stuff, and release irq. Close is run on unreg net */ + lmc_close (dev); + sc = dev->priv; + if (sc != NULL) + lmc_proto_detach(sc); + + /* Remove the device from the linked list */ + unregister_netdev (dev); + + /* Let go of the io region */; + release_region (dev->base_addr, LMC_REG_RANGE); + + /* free our allocated structures. */ + kfree (dev->priv); + dev->priv = NULL; + + kfree ((struct ppp_device *) dev); + dev = NULL; + } + + + Lmc_root_dev = NULL; + printk ("lmc module unloaded\n"); +} +#endif + +unsigned lmc_mii_readreg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno) /*fold00*/ +{ + int i; + int command = (0xf6 << 10) | (devaddr << 5) | regno; + int retval = 0; + + lmc_trace(sc->lmc_device, "lmc_mii_readreg in"); + + LMC_MII_SYNC (sc); + + lmc_trace(sc->lmc_device, "lmc_mii_readreg: done sync"); + + for (i = 15; i >= 0; i--) + { + int dataval = (command & (1 << i)) ? 0x20000 : 0; + + LMC_CSR_WRITE (sc, csr_9, dataval); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + LMC_CSR_WRITE (sc, csr_9, dataval | 0x10000); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + } + + lmc_trace(sc->lmc_device, "lmc_mii_readreg: done1"); + + for (i = 19; i > 0; i--) + { + LMC_CSR_WRITE (sc, csr_9, 0x40000); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + retval = (retval << 1) | ((LMC_CSR_READ (sc, csr_9) & 0x80000) ? 1 : 0); + LMC_CSR_WRITE (sc, csr_9, 0x40000 | 0x10000); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + } + + lmc_trace(sc->lmc_device, "lmc_mii_readreg out"); + + return (retval >> 1) & 0xffff; +} + +void lmc_mii_writereg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data) /*fold00*/ +{ + int i = 32; + int command = (0x5002 << 16) | (devaddr << 23) | (regno << 18) | data; + + lmc_trace(sc->lmc_device, "lmc_mii_writereg in"); + + LMC_MII_SYNC (sc); + + i = 31; + while (i >= 0) + { + int datav; + + if (command & (1 << i)) + datav = 0x20000; + else + datav = 0x00000; + + LMC_CSR_WRITE (sc, csr_9, datav); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + LMC_CSR_WRITE (sc, csr_9, (datav | 0x10000)); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + i--; + } + + i = 2; + while (i > 0) + { + LMC_CSR_WRITE (sc, csr_9, 0x40000); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + LMC_CSR_WRITE (sc, csr_9, 0x50000); + lmc_delay (); + /* __SLOW_DOWN_IO; */ + i--; + } + + lmc_trace(sc->lmc_device, "lmc_mii_writereg out"); +} + +static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/ +{ + int i; + + lmc_trace(sc->lmc_device, "lmc_softreset in"); + + /* Initialize the recieve rings and buffers. */ + sc->lmc_txfull = 0; + sc->lmc_next_rx = 0; + sc->lmc_next_tx = 0; + sc->lmc_taint_rx = 0; + sc->lmc_taint_tx = 0; + + /* + * Setup each one of the receiver buffers + * allocate an skbuff for each one, setup the the descriptor table + * and point each buffer at the next one + */ + + for (i = 0; i < LMC_RXDESCS; i++) + { + struct sk_buff *skb; + + if (sc->lmc_rxq[i] == NULL) + { + skb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2); + if(skb == NULL){ + printk(KERN_WARNING "%s: Failed to allocate receiver ring, will try again\n", sc->name); + sc->failed_ring = 1; + break; + } + else{ + sc->lmc_rxq[i] = skb; + } + } + else + { + skb = sc->lmc_rxq[i]; + } + + skb->dev = sc->lmc_device; + LMC_SKB_FREE(skb, 1); + + /* owned by 21140 */ + sc->lmc_rxring[i].status = 0x80000000; + + /* used to be PKT_BUF_SZ now uses skb since we loose some to head room */ + sc->lmc_rxring[i].length = skb->end - skb->data; + + /* use to be tail which is dumb since you're thinking why write + * to the end of the packj,et but since there's nothing there tail == data + */ + sc->lmc_rxring[i].buffer1 = virt_to_bus (skb->data); + + /* This is fair since the structure is static and we have the next address */ + sc->lmc_rxring[i].buffer2 = virt_to_bus (&sc->lmc_rxring[i + 1]); + + } + + /* + * Sets end of ring + */ + sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */ + sc->lmc_rxring[i - 1].buffer2 = virt_to_bus (&sc->lmc_rxring[0]); /* Point back to the start */ + LMC_CSR_WRITE (sc, csr_rxlist, virt_to_bus (sc->lmc_rxring)); /* write base address */ + + + /* Initialize the transmit rings and buffers */ + for (i = 0; i < LMC_TXDESCS; i++) + { + if (sc->lmc_txq[i] != NULL){ /* have buffer */ + dev_kfree_skb(sc->lmc_txq[i]); /* free it */ + sc->stats.tx_dropped++; /* We just dropped a packet */ + } + sc->lmc_txq[i] = 0; + sc->lmc_txring[i].status = 0x00000000; + sc->lmc_txring[i].buffer2 = virt_to_bus (&sc->lmc_txring[i + 1]); + } + sc->lmc_txring[i - 1].buffer2 = virt_to_bus (&sc->lmc_txring[0]); + LMC_CSR_WRITE (sc, csr_txlist, virt_to_bus (sc->lmc_txring)); + + lmc_trace(sc->lmc_device, "lmc_softreset out"); +} + +static int lmc_set_config(struct net_device *dev, struct ifmap *map) /*fold00*/ +{ + lmc_trace(dev, "lmc_set_config in"); + lmc_trace(dev, "lmc_set_config out"); + return -EOPNOTSUPP; +} + +void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/ +{ + lmc_trace(sc->lmc_device, "lmc_gpio_mkinput in"); + sc->lmc_gpio_io &= ~bits; + LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io)); + lmc_trace(sc->lmc_device, "lmc_gpio_mkinput out"); +} + +void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/ +{ + lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput in"); + sc->lmc_gpio_io |= bits; + LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io)); + lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput out"); +} + +void lmc_led_on(lmc_softc_t * const sc, u_int32_t led) /*fold00*/ +{ + lmc_trace(sc->lmc_device, "lmc_led_on in"); + if((~sc->lmc_miireg16) & led){ /* Already on! */ + lmc_trace(sc->lmc_device, "lmc_led_on aon out"); + return; + } + + sc->lmc_miireg16 &= ~led; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + lmc_trace(sc->lmc_device, "lmc_led_on out"); +} + +void lmc_led_off(lmc_softc_t * const sc, u_int32_t led) /*fold00*/ +{ + lmc_trace(sc->lmc_device, "lmc_led_off in"); + if(sc->lmc_miireg16 & led){ /* Already set don't do anything */ + lmc_trace(sc->lmc_device, "lmc_led_off aoff out"); + return; + } + + sc->lmc_miireg16 |= led; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + lmc_trace(sc->lmc_device, "lmc_led_off out"); +} + +static void lmc_reset(lmc_softc_t * const sc) /*fold00*/ +{ + lmc_trace(sc->lmc_device, "lmc_reset in"); + sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + + sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET; + lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16); + + /* + * make some of the GPIO pins be outputs + */ + lmc_gpio_mkoutput(sc, LMC_GEP_RESET); + + /* + * RESET low to force state reset. This also forces + * the transmitter clock to be internal, but we expect to reset + * that later anyway. + */ + sc->lmc_gpio &= ~(LMC_GEP_RESET); + LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); + + /* + * hold for more than 10 microseconds + */ + udelay(50); + + /* + * stop driving Xilinx-related signals + */ + lmc_gpio_mkinput(sc, LMC_GEP_RESET); + + /* + * Call media specific init routine + */ + sc->lmc_media->init(sc); + + sc->stats.resetCount++; + lmc_trace(sc->lmc_device, "lmc_reset out"); +} + +static void lmc_dec_reset(lmc_softc_t * const sc) /*fold00*/ +{ + u_int32_t val; + lmc_trace(sc->lmc_device, "lmc_dec_reset in"); + + /* + * disable all interrupts + */ + sc->lmc_intrmask = 0; + LMC_CSR_WRITE(sc, csr_intr, sc->lmc_intrmask); + + /* + * Reset the chip with a software reset command. + * Wait 10 microseconds (actually 50 PCI cycles but at + * 33MHz that comes to two microseconds but wait a + * bit longer anyways) + */ + LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); + udelay(25); +#ifdef __sparc__ + sc->lmc_busmode = LMC_CSR_READ(sc, csr_busmode); + sc->lmc_busmode = 0x00100000; + sc->lmc_busmode &= ~TULIP_BUSMODE_SWRESET; + LMC_CSR_WRITE(sc, csr_busmode, sc->lmc_busmode); +#endif + sc->lmc_cmdmode = LMC_CSR_READ(sc, csr_command); + + /* + * We want: + * no ethernet address in frames we write + * disable padding (txdesc, padding disable) + * ignore runt frames (rdes0 bit 15) + * no receiver watchdog or transmitter jabber timer + * (csr15 bit 0,14 == 1) + * if using 16-bit CRC, turn off CRC (trans desc, crc disable) + */ + + sc->lmc_cmdmode |= ( TULIP_CMD_PROMISCUOUS + | TULIP_CMD_FULLDUPLEX + | TULIP_CMD_PASSBADPKT + | TULIP_CMD_NOHEARTBEAT + | TULIP_CMD_PORTSELECT + | TULIP_CMD_RECEIVEALL + | TULIP_CMD_MUSTBEONE + ); + sc->lmc_cmdmode &= ~( TULIP_CMD_OPERMODE + | TULIP_CMD_THRESHOLDCTL + | TULIP_CMD_STOREFWD + | TULIP_CMD_TXTHRSHLDCTL + ); + + LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode); + + /* + * disable receiver watchdog and transmit jabber + */ + val = LMC_CSR_READ(sc, csr_sia_general); + val |= (TULIP_WATCHDOG_TXDISABLE | TULIP_WATCHDOG_RXDISABLE); + LMC_CSR_WRITE(sc, csr_sia_general, val); + + lmc_trace(sc->lmc_device, "lmc_dec_reset out"); +} + +static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, /*fold00*/ + size_t csr_size) +{ + lmc_trace(sc->lmc_device, "lmc_initcsrs in"); + sc->lmc_csrs.csr_busmode = csr_base + 0 * csr_size; + sc->lmc_csrs.csr_txpoll = csr_base + 1 * csr_size; + sc->lmc_csrs.csr_rxpoll = csr_base + 2 * csr_size; + sc->lmc_csrs.csr_rxlist = csr_base + 3 * csr_size; + sc->lmc_csrs.csr_txlist = csr_base + 4 * csr_size; + sc->lmc_csrs.csr_status = csr_base + 5 * csr_size; + sc->lmc_csrs.csr_command = csr_base + 6 * csr_size; + sc->lmc_csrs.csr_intr = csr_base + 7 * csr_size; + sc->lmc_csrs.csr_missed_frames = csr_base + 8 * csr_size; + sc->lmc_csrs.csr_9 = csr_base + 9 * csr_size; + sc->lmc_csrs.csr_10 = csr_base + 10 * csr_size; + sc->lmc_csrs.csr_11 = csr_base + 11 * csr_size; + sc->lmc_csrs.csr_12 = csr_base + 12 * csr_size; + sc->lmc_csrs.csr_13 = csr_base + 13 * csr_size; + sc->lmc_csrs.csr_14 = csr_base + 14 * csr_size; + sc->lmc_csrs.csr_15 = csr_base + 15 * csr_size; + lmc_trace(sc->lmc_device, "lmc_initcsrs out"); +} + +#if LINUX_VERSION_CODE >= 0x20363 +static void lmc_driver_timeout(struct net_device *dev) { /*fold00*/ + lmc_softc_t *sc; + u32 csr6; + LMC_SPIN_FLAGS; + + lmc_trace(dev, "lmc_driver_timeout in"); + + sc = dev->priv; + + spin_lock_irqsave(&sc->lmc_lock, flags); + + printk("%s: Xmitter busy|\n", dev->name); + + sc->stats.tx_tbusy_calls++ ; + if (jiffies - dev->trans_start < TX_TIMEOUT) { + goto bug_out; + } + + /* + * Chip seems to have locked up + * Reset it + * This whips out all our decriptor + * table and starts from scartch + */ + + LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO, + LMC_CSR_READ (sc, csr_status), + sc->stats.tx_ProcTimeout); + + lmc_running_reset (dev); + + LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); + LMC_EVENT_LOG(LMC_EVENT_RESET2, + lmc_mii_readreg (sc, 0, 16), + lmc_mii_readreg (sc, 0, 17)); + + /* restart the tx processes */ + csr6 = LMC_CSR_READ (sc, csr_command); + LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002); + LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002); + + /* immediate transmit */ + LMC_CSR_WRITE (sc, csr_txpoll, 0); + + sc->stats.tx_errors++; + sc->stats.tx_ProcTimeout++; /* -baz */ + + dev->trans_start = jiffies; + +bug_out: + + spin_unlock_irqrestore(&sc->lmc_lock, flags); + + lmc_trace(dev, "lmc_driver_timout out"); + + +} + +int lmc_setup(void) { /*FOLD00*/ + return lmc_probe(NULL); +} + +#endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_media.c linux/drivers/net/wan/lmc/lmc_media.c --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_media.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_media.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,1258 @@ +/* $Id: lmc_media.c,v 1.13 2000/04/11 05:25:26 asj Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +#if LINUX_VERSION_CODE < 0x20155 +#include +#endif + +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +#include +#include +#include +#include "../syncppp.h" +#include + +#if LINUX_VERSION_CODE >= 0x20200 +#include +//#include +#endif + +#include "lmc_ver.h" +#include "lmc.h" +#include "lmc_var.h" +#include "lmc_ioctl.h" +#include "lmc_debug.h" + +#define CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE 1 + + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + */ + +/* + * For lack of a better place, put the SSI cable stuff here. + */ +char *lmc_t1_cables[] = { + "V.10/RS423", "EIA530A", "reserved", "X.21", "V.35", + "EIA449/EIA530/V.36", "V.28/EIA232", "none", NULL +}; + +/* + * protocol independent method. + */ +static void lmc_set_protocol (lmc_softc_t * const, lmc_ctl_t *); + +/* + * media independent methods to check on media status, link, light LEDs, + * etc. + */ +static void lmc_ds3_init (lmc_softc_t * const); +static void lmc_ds3_default (lmc_softc_t * const); +static void lmc_ds3_set_status (lmc_softc_t * const, lmc_ctl_t *); +static void lmc_ds3_set_100ft (lmc_softc_t * const, int); +static int lmc_ds3_get_link_status (lmc_softc_t * const); +static void lmc_ds3_set_crc_length (lmc_softc_t * const, int); +static void lmc_ds3_set_scram (lmc_softc_t * const, int); +static void lmc_ds3_watchdog (lmc_softc_t * const); + +static void lmc_hssi_init (lmc_softc_t * const); +static void lmc_hssi_default (lmc_softc_t * const); +static void lmc_hssi_set_status (lmc_softc_t * const, lmc_ctl_t *); +static void lmc_hssi_set_clock (lmc_softc_t * const, int); +static int lmc_hssi_get_link_status (lmc_softc_t * const); +static void lmc_hssi_set_link_status (lmc_softc_t * const, int); +static void lmc_hssi_set_crc_length (lmc_softc_t * const, int); +static void lmc_hssi_watchdog (lmc_softc_t * const); + +static void lmc_ssi_init (lmc_softc_t * const); +static void lmc_ssi_default (lmc_softc_t * const); +static void lmc_ssi_set_status (lmc_softc_t * const, lmc_ctl_t *); +static void lmc_ssi_set_clock (lmc_softc_t * const, int); +static void lmc_ssi_set_speed (lmc_softc_t * const, lmc_ctl_t *); +static int lmc_ssi_get_link_status (lmc_softc_t * const); +static void lmc_ssi_set_link_status (lmc_softc_t * const, int); +static void lmc_ssi_set_crc_length (lmc_softc_t * const, int); +static void lmc_ssi_watchdog (lmc_softc_t * const); + +static void lmc_t1_init (lmc_softc_t * const); +static void lmc_t1_default (lmc_softc_t * const); +static void lmc_t1_set_status (lmc_softc_t * const, lmc_ctl_t *); +static int lmc_t1_get_link_status (lmc_softc_t * const); +static void lmc_t1_set_circuit_type (lmc_softc_t * const, int); +static void lmc_t1_set_crc_length (lmc_softc_t * const, int); +static void lmc_t1_set_clock (lmc_softc_t * const, int); +static void lmc_t1_watchdog (lmc_softc_t * const); + +static void lmc_dummy_set_1 (lmc_softc_t * const, int); +static void lmc_dummy_set2_1 (lmc_softc_t * const, lmc_ctl_t *); + +static inline void write_av9110_bit (lmc_softc_t *, int); +static void write_av9110 (lmc_softc_t *, u_int32_t, u_int32_t, u_int32_t, + u_int32_t, u_int32_t); + +lmc_media_t lmc_ds3_media = { + lmc_ds3_init, /* special media init stuff */ + lmc_ds3_default, /* reset to default state */ + lmc_ds3_set_status, /* reset status to state provided */ + lmc_dummy_set_1, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_ds3_set_100ft, /* set cable length */ + lmc_ds3_set_scram, /* set scrambler */ + lmc_ds3_get_link_status, /* get link status */ + lmc_dummy_set_1, /* set link status */ + lmc_ds3_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_ds3_watchdog +}; + +lmc_media_t lmc_hssi_media = { + lmc_hssi_init, /* special media init stuff */ + lmc_hssi_default, /* reset to default state */ + lmc_hssi_set_status, /* reset status to state provided */ + lmc_hssi_set_clock, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_hssi_get_link_status, /* get link status */ + lmc_hssi_set_link_status, /* set link status */ + lmc_hssi_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_hssi_watchdog +}; + +lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */ + lmc_ssi_default, /* reset to default state */ + lmc_ssi_set_status, /* reset status to state provided */ + lmc_ssi_set_clock, /* set clock source */ + lmc_ssi_set_speed, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_ssi_get_link_status, /* get link status */ + lmc_ssi_set_link_status, /* set link status */ + lmc_ssi_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_ssi_watchdog +}; + +lmc_media_t lmc_t1_media = { + lmc_t1_init, /* special media init stuff */ + lmc_t1_default, /* reset to default state */ + lmc_t1_set_status, /* reset status to state provided */ + lmc_t1_set_clock, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_t1_get_link_status, /* get link status */ + lmc_dummy_set_1, /* set link status */ + lmc_t1_set_crc_length, /* set CRC length */ + lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */ + lmc_t1_watchdog +}; + +static void +lmc_dummy_set_1 (lmc_softc_t * const sc, int a) +{ +} + +static void +lmc_dummy_set2_1 (lmc_softc_t * const sc, lmc_ctl_t * a) +{ +} + +/* + * HSSI methods + */ + +static void +lmc_hssi_init (lmc_softc_t * const sc) +{ + sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5200; + + lmc_gpio_mkoutput (sc, LMC_GEP_HSSI_CLOCK); +} + +static void +lmc_hssi_default (lmc_softc_t * const sc) +{ + sc->lmc_miireg16 = LMC_MII16_LED_ALL; + + sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN); + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT); + sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16); +} + +/* + * Given a user provided state, set ourselves up to match it. This will + * always reset the card if needed. + */ +static void +lmc_hssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + if (ctl == NULL) + { + sc->lmc_media->set_clock_source (sc, sc->ictl.clock_source); + lmc_set_protocol (sc, NULL); + + return; + } + + /* + * check for change in clock source + */ + if (ctl->clock_source && !sc->ictl.clock_source) + { + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_INT); + sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_INT; + } + else if (!ctl->clock_source && sc->ictl.clock_source) + { + sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT; + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT); + } + + lmc_set_protocol (sc, ctl); +} + +/* + * 1 == internal, 0 == external + */ +static void +lmc_hssi_set_clock (lmc_softc_t * const sc, int ie) +{ + int old; + old = sc->ictl.clock_source; + if (ie == LMC_CTL_CLOCK_SOURCE_EXT) + { + sc->lmc_gpio |= LMC_GEP_HSSI_CLOCK; + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT; + if(old != ie) + printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS); + } + else + { + sc->lmc_gpio &= ~(LMC_GEP_HSSI_CLOCK); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT; + if(old != ie) + printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS); + } +} + +/* + * return hardware link status. + * 0 == link is down, 1 == link is up. + */ +static int +lmc_hssi_get_link_status (lmc_softc_t * const sc) +{ + /* + * We're using the same code as SSI since + * they're practically the same + */ + return lmc_ssi_get_link_status(sc); +} + +static void +lmc_hssi_set_link_status (lmc_softc_t * const sc, int state) +{ + if (state == LMC_LINK_UP) + sc->lmc_miireg16 |= LMC_MII16_HSSI_TA; + else + sc->lmc_miireg16 &= ~LMC_MII16_HSSI_TA; + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +/* + * 0 == 16bit, 1 == 32bit + */ +static void +lmc_hssi_set_crc_length (lmc_softc_t * const sc, int state) +{ + if (state == LMC_CTL_CRC_LENGTH_32) + { + /* 32 bit */ + sc->lmc_miireg16 |= LMC_MII16_HSSI_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32; + } + else + { + /* 16 bit */ + sc->lmc_miireg16 &= ~LMC_MII16_HSSI_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16; + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +static void +lmc_hssi_watchdog (lmc_softc_t * const sc) +{ + /* HSSI is blank */ +} + +/* + * DS3 methods + */ + +/* + * Set cable length + */ +static void +lmc_ds3_set_100ft (lmc_softc_t * const sc, int ie) +{ + if (ie == LMC_CTL_CABLE_LENGTH_GT_100FT) + { + sc->lmc_miireg16 &= ~LMC_MII16_DS3_ZERO; + sc->ictl.cable_length = LMC_CTL_CABLE_LENGTH_GT_100FT; + } + else if (ie == LMC_CTL_CABLE_LENGTH_LT_100FT) + { + sc->lmc_miireg16 |= LMC_MII16_DS3_ZERO; + sc->ictl.cable_length = LMC_CTL_CABLE_LENGTH_LT_100FT; + } + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +static void +lmc_ds3_default (lmc_softc_t * const sc) +{ + sc->lmc_miireg16 = LMC_MII16_LED_ALL; + + sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN); + sc->lmc_media->set_cable_length (sc, LMC_CTL_CABLE_LENGTH_LT_100FT); + sc->lmc_media->set_scrambler (sc, LMC_CTL_OFF); + sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16); +} + +/* + * Given a user provided state, set ourselves up to match it. This will + * always reset the card if needed. + */ +static void +lmc_ds3_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + if (ctl == NULL) + { + sc->lmc_media->set_cable_length (sc, sc->ictl.cable_length); + sc->lmc_media->set_scrambler (sc, sc->ictl.scrambler_onoff); + lmc_set_protocol (sc, NULL); + + return; + } + + /* + * check for change in cable length setting + */ + if (ctl->cable_length && !sc->ictl.cable_length) + lmc_ds3_set_100ft (sc, LMC_CTL_CABLE_LENGTH_GT_100FT); + else if (!ctl->cable_length && sc->ictl.cable_length) + lmc_ds3_set_100ft (sc, LMC_CTL_CABLE_LENGTH_LT_100FT); + + /* + * Check for change in scrambler setting (requires reset) + */ + if (ctl->scrambler_onoff && !sc->ictl.scrambler_onoff) + lmc_ds3_set_scram (sc, LMC_CTL_ON); + else if (!ctl->scrambler_onoff && sc->ictl.scrambler_onoff) + lmc_ds3_set_scram (sc, LMC_CTL_OFF); + + lmc_set_protocol (sc, ctl); +} + +static void +lmc_ds3_init (lmc_softc_t * const sc) +{ + int i; + + sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5245; + + /* writes zeros everywhere */ + for (i = 0; i < 21; i++) + { + lmc_mii_writereg (sc, 0, 17, i); + lmc_mii_writereg (sc, 0, 18, 0); + } + + /* set some essential bits */ + lmc_mii_writereg (sc, 0, 17, 1); + lmc_mii_writereg (sc, 0, 18, 0x25); /* ser, xtx */ + + lmc_mii_writereg (sc, 0, 17, 5); + lmc_mii_writereg (sc, 0, 18, 0x80); /* emode */ + + lmc_mii_writereg (sc, 0, 17, 14); + lmc_mii_writereg (sc, 0, 18, 0x30); /* rcgen, tcgen */ + + /* clear counters and latched bits */ + for (i = 0; i < 21; i++) + { + lmc_mii_writereg (sc, 0, 17, i); + lmc_mii_readreg (sc, 0, 18); + } +} + +/* + * 1 == DS3 payload scrambled, 0 == not scrambled + */ +static void +lmc_ds3_set_scram (lmc_softc_t * const sc, int ie) +{ + if (ie == LMC_CTL_ON) + { + sc->lmc_miireg16 |= LMC_MII16_DS3_SCRAM; + sc->ictl.scrambler_onoff = LMC_CTL_ON; + } + else + { + sc->lmc_miireg16 &= ~LMC_MII16_DS3_SCRAM; + sc->ictl.scrambler_onoff = LMC_CTL_OFF; + } + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +/* + * return hardware link status. + * 0 == link is down, 1 == link is up. + */ +static int +lmc_ds3_get_link_status (lmc_softc_t * const sc) +{ + u_int16_t link_status, link_status_11; + int ret = 1; + + lmc_mii_writereg (sc, 0, 17, 7); + link_status = lmc_mii_readreg (sc, 0, 18); + + /* LMC5245 (DS3) & LMC1200 (DS1) LED definitions + * led0 yellow = far-end adapter is in Red alarm condition + * led1 blue = received an Alarm Indication signal + * (upstream failure) + * led2 Green = power to adapter, Gate Array loaded & driver + * attached + * led3 red = Loss of Signal (LOS) or out of frame (OOF) + * conditions detected on T3 receive signal + */ + + lmc_led_on(sc, LMC_DS3_LED2); + + if ((link_status & LMC_FRAMER_REG0_DLOS) || + (link_status & LMC_FRAMER_REG0_OOFS)){ + ret = 0; + if(sc->last_led_err[3] != 1){ + u16 r1; + lmc_mii_writereg (sc, 0, 17, 01); /* Turn on Xbit error as our cisco does */ + r1 = lmc_mii_readreg (sc, 0, 18); + r1 &= 0xfe; + lmc_mii_writereg(sc, 0, 18, r1); + printk(KERN_WARNING "%s: Red Alarm - Loss of Signal or Loss of Framing\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED3); /* turn on red LED */ + sc->last_led_err[3] = 1; + } + else { + lmc_led_off(sc, LMC_DS3_LED3); /* turn on red LED */ + if(sc->last_led_err[3] == 1){ + u16 r1; + lmc_mii_writereg (sc, 0, 17, 01); /* Turn off Xbit error */ + r1 = lmc_mii_readreg (sc, 0, 18); + r1 |= 0x01; + lmc_mii_writereg(sc, 0, 18, r1); + } + sc->last_led_err[3] = 0; + } + + lmc_mii_writereg(sc, 0, 17, 0x10); + link_status_11 = lmc_mii_readreg(sc, 0, 18); + if((link_status & LMC_FRAMER_REG0_AIS) || + (link_status_11 & LMC_FRAMER_REG10_XBIT)) { + ret = 0; + if(sc->last_led_err[0] != 1){ + printk(KERN_WARNING "%s: AIS Alarm or XBit Error\n", sc->name); + printk(KERN_WARNING "%s: Remote end has loss of signal or framing\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED0); + sc->last_led_err[0] = 1; + } + else { + lmc_led_off(sc, LMC_DS3_LED0); + sc->last_led_err[0] = 0; + } + + lmc_mii_writereg (sc, 0, 17, 9); + link_status = lmc_mii_readreg (sc, 0, 18); + + if(link_status & LMC_FRAMER_REG9_RBLUE){ + ret = 0; + if(sc->last_led_err[1] != 1){ + printk(KERN_WARNING "%s: Blue Alarm - Receiving all 1's\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED1); + sc->last_led_err[1] = 1; + } + else { + lmc_led_off(sc, LMC_DS3_LED1); + sc->last_led_err[1] = 0; + } + + return ret; +} + +/* + * 0 == 16bit, 1 == 32bit + */ +static void +lmc_ds3_set_crc_length (lmc_softc_t * const sc, int state) +{ + if (state == LMC_CTL_CRC_LENGTH_32) + { + /* 32 bit */ + sc->lmc_miireg16 |= LMC_MII16_DS3_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32; + } + else + { + /* 16 bit */ + sc->lmc_miireg16 &= ~LMC_MII16_DS3_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16; + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +static void +lmc_ds3_watchdog (lmc_softc_t * const sc) +{ + +} + + +/* + * SSI methods + */ + +static void +lmc_ssi_init (lmc_softc_t * const sc) +{ + u_int16_t mii17; + int cable; + + sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1000; + + mii17 = lmc_mii_readreg (sc, 0, 17); + + cable = (mii17 & LMC_MII17_SSI_CABLE_MASK) >> LMC_MII17_SSI_CABLE_SHIFT; + sc->ictl.cable_type = cable; + + lmc_gpio_mkoutput (sc, LMC_GEP_SSI_TXCLOCK); +} + +static void +lmc_ssi_default (lmc_softc_t * const sc) +{ + sc->lmc_miireg16 = LMC_MII16_LED_ALL; + + /* + * make TXCLOCK always be an output + */ + lmc_gpio_mkoutput (sc, LMC_GEP_SSI_TXCLOCK); + + sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN); + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT); + sc->lmc_media->set_speed (sc, NULL); + sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16); +} + +/* + * Given a user provided state, set ourselves up to match it. This will + * always reset the card if needed. + */ +static void +lmc_ssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + if (ctl == NULL) + { + sc->lmc_media->set_clock_source (sc, sc->ictl.clock_source); + sc->lmc_media->set_speed (sc, &sc->ictl); + lmc_set_protocol (sc, NULL); + + return; + } + + /* + * check for change in clock source + */ + if (ctl->clock_source == LMC_CTL_CLOCK_SOURCE_INT + && sc->ictl.clock_source == LMC_CTL_CLOCK_SOURCE_EXT) + { + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_INT); + sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_INT; + } + else if (ctl->clock_source == LMC_CTL_CLOCK_SOURCE_EXT + && sc->ictl.clock_source == LMC_CTL_CLOCK_SOURCE_INT) + { + sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT); + sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT; + } + + if (ctl->clock_rate != sc->ictl.clock_rate) + sc->lmc_media->set_speed (sc, ctl); + + lmc_set_protocol (sc, ctl); +} + +/* + * 1 == internal, 0 == external + */ +static void +lmc_ssi_set_clock (lmc_softc_t * const sc, int ie) +{ + int old; + old = ie; + if (ie == LMC_CTL_CLOCK_SOURCE_EXT) + { + sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT; + if(ie != old) + printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS); + } + else + { + sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK; + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT; + if(ie != old) + printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS); + } +} + +static void +lmc_ssi_set_speed (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + lmc_ctl_t *ictl = &sc->ictl; + lmc_av9110_t *av; + + /* original settings for clock rate of: + * 100 Khz (8,25,0,0,2) were incorrect + * they should have been 80,125,1,3,3 + * There are 17 param combinations to produce this freq. + * For 1.5 Mhz use 120,100,1,1,2 (226 param. combinations) + */ + if (ctl == NULL) + { + av = &ictl->cardspec.ssi; + ictl->clock_rate = 1500000; + av->f = ictl->clock_rate; + av->n = 120; + av->m = 100; + av->v = 1; + av->x = 1; + av->r = 2; + + write_av9110 (sc, av->n, av->m, av->v, av->x, av->r); + return; + } + + av = &ctl->cardspec.ssi; + + if (av->f == 0) + return; + + ictl->clock_rate = av->f; /* really, this is the rate we are */ + ictl->cardspec.ssi = *av; + + write_av9110 (sc, av->n, av->m, av->v, av->x, av->r); +} + +/* + * return hardware link status. + * 0 == link is down, 1 == link is up. + */ +static int +lmc_ssi_get_link_status (lmc_softc_t * const sc) +{ + u_int16_t link_status; + u_int32_t ticks; + int ret = 1; + int hw_hdsk = 1; + + /* + * missing CTS? Hmm. If we require CTS on, we may never get the + * link to come up, so omit it in this test. + * + * Also, it seems that with a loopback cable, DCD isn't asserted, + * so just check for things like this: + * DSR _must_ be asserted. + * One of DCD or CTS must be asserted. + */ + + /* LMC 1000 (SSI) LED definitions + * led0 Green = power to adapter, Gate Array loaded & + * driver attached + * led1 Green = DSR and DTR and RTS and CTS are set + * led2 Green = Cable detected + * led3 red = No timing is available from the + * cable or the on-board frequency + * generator. + */ + + link_status = lmc_mii_readreg (sc, 0, 16); + + /* Is the transmit clock still available */ + ticks = LMC_CSR_READ (sc, csr_gp_timer); + ticks = 0x0000ffff - (ticks & 0x0000ffff); + + lmc_led_on (sc, LMC_MII16_LED0); + + /* ====== transmit clock determination ===== */ + if (sc->lmc_timing == LMC_CTL_CLOCK_SOURCE_INT) { + lmc_led_off(sc, LMC_MII16_LED3); + } + else if (ticks == 0 ) { /* no clock found ? */ + ret = 0; + if(sc->last_led_err[3] != 1){ + sc->stats.tx_lossOfClockCnt++; + printk(KERN_WARNING "%s: Lost Clock, Link Down\n", sc->name); + } + sc->last_led_err[3] = 1; + lmc_led_on (sc, LMC_MII16_LED3); /* turn ON red LED */ + } + else { + if(sc->last_led_err[3] == 1) + printk(KERN_WARNING "%s: Clock Returned\n", sc->name); + sc->last_led_err[3] = 0; + lmc_led_off (sc, LMC_MII16_LED3); /* turn OFF red LED */ + } + + if ((link_status & LMC_MII16_SSI_DSR) == 0) { /* Also HSSI CA */ + ret = 0; + hw_hdsk = 0; + } + +#ifdef CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE + if ((link_status & (LMC_MII16_SSI_CTS | LMC_MII16_SSI_DCD)) == 0){ + ret = 0; + hw_hdsk = 0; + } +#endif + + if(hw_hdsk == 0){ + if(sc->last_led_err[1] != 1) + printk(KERN_WARNING "%s: DSR not asserted\n", sc->name); + sc->last_led_err[1] = 1; + lmc_led_off(sc, LMC_MII16_LED1); + } + else { + if(sc->last_led_err[1] != 0) + printk(KERN_WARNING "%s: DSR now asserted\n", sc->name); + sc->last_led_err[1] = 0; + lmc_led_on(sc, LMC_MII16_LED1); + } + + if(ret == 1) { + lmc_led_on(sc, LMC_MII16_LED2); /* Over all good status? */ + } + + return ret; +} + +static void +lmc_ssi_set_link_status (lmc_softc_t * const sc, int state) +{ + if (state == LMC_LINK_UP) + { + sc->lmc_miireg16 |= (LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS); + printk (LMC_PRINTF_FMT ": asserting DTR and RTS\n", LMC_PRINTF_ARGS); + } + else + { + sc->lmc_miireg16 &= ~(LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS); + printk (LMC_PRINTF_FMT ": deasserting DTR and RTS\n", LMC_PRINTF_ARGS); + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); + +} + +/* + * 0 == 16bit, 1 == 32bit + */ +static void +lmc_ssi_set_crc_length (lmc_softc_t * const sc, int state) +{ + if (state == LMC_CTL_CRC_LENGTH_32) + { + /* 32 bit */ + sc->lmc_miireg16 |= LMC_MII16_SSI_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32; + sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4; + + } + else + { + /* 16 bit */ + sc->lmc_miireg16 &= ~LMC_MII16_SSI_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16; + sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2; + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +/* + * These are bits to program the ssi frequency generator + */ +static inline void +write_av9110_bit (lmc_softc_t * sc, int c) +{ + /* + * set the data bit as we need it. + */ + sc->lmc_gpio &= ~(LMC_GEP_CLK); + if (c & 0x01) + sc->lmc_gpio |= LMC_GEP_DATA; + else + sc->lmc_gpio &= ~(LMC_GEP_DATA); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + + /* + * set the clock to high + */ + sc->lmc_gpio |= LMC_GEP_CLK; + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + + /* + * set the clock to low again. + */ + sc->lmc_gpio &= ~(LMC_GEP_CLK); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); +} + +static void +write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v, + u_int32_t x, u_int32_t r) +{ + int i; + +#if 0 + printk (LMC_PRINTF_FMT ": speed %u, %d %d %d %d %d\n", + LMC_PRINTF_ARGS, sc->ictl.clock_rate, n, m, v, x, r); +#endif + + sc->lmc_gpio |= LMC_GEP_SSI_GENERATOR; + sc->lmc_gpio &= ~(LMC_GEP_DATA | LMC_GEP_CLK); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + + /* + * Set the TXCLOCK, GENERATOR, SERIAL, and SERIALCLK + * as outputs. + */ + lmc_gpio_mkoutput (sc, (LMC_GEP_DATA | LMC_GEP_CLK + | LMC_GEP_SSI_GENERATOR)); + + sc->lmc_gpio &= ~(LMC_GEP_SSI_GENERATOR); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + + /* + * a shifting we will go... + */ + for (i = 0; i < 7; i++) + write_av9110_bit (sc, n >> i); + for (i = 0; i < 7; i++) + write_av9110_bit (sc, m >> i); + for (i = 0; i < 1; i++) + write_av9110_bit (sc, v >> i); + for (i = 0; i < 2; i++) + write_av9110_bit (sc, x >> i); + for (i = 0; i < 2; i++) + write_av9110_bit (sc, r >> i); + for (i = 0; i < 5; i++) + write_av9110_bit (sc, 0x17 >> i); + + /* + * stop driving serial-related signals + */ + lmc_gpio_mkinput (sc, + (LMC_GEP_DATA | LMC_GEP_CLK + | LMC_GEP_SSI_GENERATOR)); +} + +static void +lmc_ssi_watchdog (lmc_softc_t * const sc) +{ + u_int16_t mii17; + struct ssicsr2 + { + unsigned short dtr:1, dsr:1, rts:1, cable:3, crc:1, led0:1, led1:1, + led2:1, led3:1, fifo:1, ll:1, rl:1, tm:1, loop:1; + }; + struct ssicsr2 *ssicsr; + mii17 = lmc_mii_readreg (sc, 0, 17); + ssicsr = (struct ssicsr2 *) &mii17; + if (ssicsr->cable == 7) + { + lmc_led_off (sc, LMC_MII16_LED2); + } + else + { + lmc_led_on (sc, LMC_MII16_LED2); + } + +} + +/* + * T1 methods + */ + +/* + * The framer regs are multiplexed through MII regs 17 & 18 + * write the register address to MII reg 17 and the * data to MII reg 18. */ +static void +lmc_t1_write (lmc_softc_t * const sc, int a, int d) +{ + lmc_mii_writereg (sc, 0, 17, a); + lmc_mii_writereg (sc, 0, 18, d); +} + +/* Save a warning +static int +lmc_t1_read (lmc_softc_t * const sc, int a) +{ + lmc_mii_writereg (sc, 0, 17, a); + return lmc_mii_readreg (sc, 0, 18); +} +*/ + + +static void +lmc_t1_init (lmc_softc_t * const sc) +{ + u_int16_t mii16; + int i; + + sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1200; + mii16 = lmc_mii_readreg (sc, 0, 16); + + /* reset 8370 */ + mii16 &= ~LMC_MII16_T1_RST; + lmc_mii_writereg (sc, 0, 16, mii16 | LMC_MII16_T1_RST); + lmc_mii_writereg (sc, 0, 16, mii16); + + /* set T1 or E1 line. Uses sc->lmcmii16 reg in function so update it */ + sc->lmc_miireg16 = mii16; + lmc_t1_set_circuit_type(sc, LMC_CTL_CIRCUIT_TYPE_T1); + mii16 = sc->lmc_miireg16; + + lmc_t1_write (sc, 0x01, 0x1B); /* CR0 - primary control */ + lmc_t1_write (sc, 0x02, 0x42); /* JAT_CR - jitter atten config */ + lmc_t1_write (sc, 0x14, 0x00); /* LOOP - loopback config */ + lmc_t1_write (sc, 0x15, 0x00); /* DL3_TS - external data link timeslot */ + lmc_t1_write (sc, 0x18, 0xFF); /* PIO - programmable I/O */ + lmc_t1_write (sc, 0x19, 0x30); /* POE - programmable OE */ + lmc_t1_write (sc, 0x1A, 0x0F); /* CMUX - clock input mux */ + lmc_t1_write (sc, 0x20, 0x41); /* LIU_CR - RX LIU config */ + lmc_t1_write (sc, 0x22, 0x76); /* RLIU_CR - RX LIU config */ + lmc_t1_write (sc, 0x40, 0x03); /* RCR0 - RX config */ + lmc_t1_write (sc, 0x45, 0x00); /* RALM - RX alarm config */ + lmc_t1_write (sc, 0x46, 0x05); /* LATCH - RX alarm/err/cntr latch */ + lmc_t1_write (sc, 0x68, 0x40); /* TLIU_CR - TX LIU config */ + lmc_t1_write (sc, 0x70, 0x0D); /* TCR0 - TX framer config */ + lmc_t1_write (sc, 0x71, 0x05); /* TCR1 - TX config */ + lmc_t1_write (sc, 0x72, 0x0B); /* TFRM - TX frame format */ + lmc_t1_write (sc, 0x73, 0x00); /* TERROR - TX error insert */ + lmc_t1_write (sc, 0x74, 0x00); /* TMAN - TX manual Sa/FEBE config */ + lmc_t1_write (sc, 0x75, 0x00); /* TALM - TX alarm signal config */ + lmc_t1_write (sc, 0x76, 0x00); /* TPATT - TX test pattern config */ + lmc_t1_write (sc, 0x77, 0x00); /* TLB - TX inband loopback config */ + lmc_t1_write (sc, 0x90, 0x05); /* CLAD_CR - clock rate adapter config */ + lmc_t1_write (sc, 0x91, 0x05); /* CSEL - clad freq sel */ + lmc_t1_write (sc, 0xA6, 0x00); /* DL1_CTL - DL1 control */ + lmc_t1_write (sc, 0xB1, 0x00); /* DL2_CTL - DL2 control */ + lmc_t1_write (sc, 0xD0, 0x47); /* SBI_CR - sys bus iface config */ + lmc_t1_write (sc, 0xD1, 0x70); /* RSB_CR - RX sys bus config */ + lmc_t1_write (sc, 0xD4, 0x30); /* TSB_CR - TX sys bus config */ + for (i = 0; i < 32; i++) + { + lmc_t1_write (sc, 0x0E0 + i, 0x00); /* SBCn - sys bus per-channel ctl */ + lmc_t1_write (sc, 0x100 + i, 0x00); /* TPCn - TX per-channel ctl */ + lmc_t1_write (sc, 0x180 + i, 0x00); /* RPCn - RX per-channel ctl */ + } + for (i = 1; i < 25; i++) + { + lmc_t1_write (sc, 0x0E0 + i, 0x0D); /* SBCn - sys bus per-channel ctl */ + } + + mii16 |= LMC_MII16_T1_XOE; + lmc_mii_writereg (sc, 0, 16, mii16); + sc->lmc_miireg16 = mii16; +} + +static void +lmc_t1_default (lmc_softc_t * const sc) +{ + sc->lmc_miireg16 = LMC_MII16_LED_ALL; + sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN); + sc->lmc_media->set_circuit_type (sc, LMC_CTL_CIRCUIT_TYPE_T1); + sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16); + /* Right now we can only clock from out internal source */ + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT; +} +/* * Given a user provided state, set ourselves up to match it. This will * always reset the card if needed. + */ +static void +lmc_t1_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + if (ctl == NULL) + { + sc->lmc_media->set_circuit_type (sc, sc->ictl.circuit_type); + lmc_set_protocol (sc, NULL); + + return; + } + /* + * check for change in circuit type */ + if (ctl->circuit_type == LMC_CTL_CIRCUIT_TYPE_T1 + && sc->ictl.circuit_type == + LMC_CTL_CIRCUIT_TYPE_E1) sc->lmc_media->set_circuit_type (sc, + LMC_CTL_CIRCUIT_TYPE_E1); + else if (ctl->circuit_type == LMC_CTL_CIRCUIT_TYPE_E1 + && sc->ictl.circuit_type == LMC_CTL_CIRCUIT_TYPE_T1) + sc->lmc_media->set_circuit_type (sc, LMC_CTL_CIRCUIT_TYPE_T1); + lmc_set_protocol (sc, ctl); +} +/* + * return hardware link status. + * 0 == link is down, 1 == link is up. + */ static int +lmc_t1_get_link_status (lmc_softc_t * const sc) +{ + u_int16_t link_status; + int ret = 1; + + /* LMC5245 (DS3) & LMC1200 (DS1) LED definitions + * led0 yellow = far-end adapter is in Red alarm condition + * led1 blue = received an Alarm Indication signal + * (upstream failure) + * led2 Green = power to adapter, Gate Array loaded & driver + * attached + * led3 red = Loss of Signal (LOS) or out of frame (OOF) + * conditions detected on T3 receive signal + */ + lmc_trace(sc->lmc_device, "lmc_t1_get_link_status in"); + lmc_led_on(sc, LMC_DS3_LED2); + + lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM1_STATUS); + link_status = lmc_mii_readreg (sc, 0, 18); + + + if (link_status & T1F_RAIS) { /* turn on blue LED */ + ret = 0; + if(sc->last_led_err[1] != 1){ + printk(KERN_WARNING "%s: Receive AIS/Blue Alarm. Far end in RED alarm\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED1); + sc->last_led_err[1] = 1; + } + else { + if(sc->last_led_err[1] != 0){ + printk(KERN_WARNING "%s: End AIS/Blue Alarm\n", sc->name); + } + lmc_led_off (sc, LMC_DS3_LED1); + sc->last_led_err[1] = 0; + } + + /* + * Yellow Alarm is nasty evil stuff, looks at data patterns + * inside the channel and confuses it with HDLC framing + * ignore all yellow alarms. + * + * Do listen to MultiFrame Yellow alarm which while implemented + * different ways isn't in the channel and hence somewhat + * more reliable + */ + + if (link_status & T1F_RMYEL) { + ret = 0; + if(sc->last_led_err[0] != 1){ + printk(KERN_WARNING "%s: Receive Yellow AIS Alarm\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED0); + sc->last_led_err[0] = 1; + } + else { + if(sc->last_led_err[0] != 0){ + printk(KERN_WARNING "%s: End of Yellow AIS Alarm\n", sc->name); + } + lmc_led_off(sc, LMC_DS3_LED0); + sc->last_led_err[0] = 0; + } + + /* + * Loss of signal and los of frame + * Use the green bit to identify which one lit the led + */ + if(link_status & T1F_RLOF){ + ret = 0; + if(sc->last_led_err[3] != 1){ + printk(KERN_WARNING "%s: Local Red Alarm: Loss of Framing\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED3); + sc->last_led_err[3] = 1; + + } + else { + if(sc->last_led_err[3] != 0){ + printk(KERN_WARNING "%s: End Red Alarm (LOF)\n", sc->name); + } + if( ! (link_status & T1F_RLOS)) + lmc_led_off(sc, LMC_DS3_LED3); + sc->last_led_err[3] = 0; + } + + if(link_status & T1F_RLOS){ + ret = 0; + if(sc->last_led_err[2] != 1){ + printk(KERN_WARNING "%s: Local Red Alarm: Loss of Signal\n", sc->name); + } + lmc_led_on(sc, LMC_DS3_LED3); + sc->last_led_err[2] = 1; + + } + else { + if(sc->last_led_err[2] != 0){ + printk(KERN_WARNING "%s: End Red Alarm (LOS)\n", sc->name); + } + if( ! (link_status & T1F_RLOF)) + lmc_led_off(sc, LMC_DS3_LED3); + sc->last_led_err[2] = 0; + } + + sc->lmc_xinfo.t1_alarm1_status = link_status; + + lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM2_STATUS); + sc->lmc_xinfo.t1_alarm2_status = lmc_mii_readreg (sc, 0, 18); + + + lmc_trace(sc->lmc_device, "lmc_t1_get_link_status out"); + + return ret; +} + +/* + * 1 == T1 Circuit Type , 0 == E1 Circuit Type + */ +static void +lmc_t1_set_circuit_type (lmc_softc_t * const sc, int ie) +{ + if (ie == LMC_CTL_CIRCUIT_TYPE_T1) { + sc->lmc_miireg16 |= LMC_MII16_T1_Z; + sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_T1; + printk(KERN_INFO "%s: In T1 Mode\n", sc->name); + } + else { + sc->lmc_miireg16 &= ~LMC_MII16_T1_Z; + sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_E1; + printk(KERN_INFO "%s: In E1 Mode\n", sc->name); + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); + +} + +/* + * 0 == 16bit, 1 == 32bit */ +static void +lmc_t1_set_crc_length (lmc_softc_t * const sc, int state) +{ + if (state == LMC_CTL_CRC_LENGTH_32) + { + /* 32 bit */ + sc->lmc_miireg16 |= LMC_MII16_T1_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32; + sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4; + + } + else + { + /* 16 bit */ sc->lmc_miireg16 &= ~LMC_MII16_T1_CRC; + sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16; + sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2; + + } + + lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16); +} + +/* + * 1 == internal, 0 == external + */ +static void +lmc_t1_set_clock (lmc_softc_t * const sc, int ie) +{ + int old; + old = ie; + if (ie == LMC_CTL_CLOCK_SOURCE_EXT) + { + sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK); + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT; + if(old != ie) + printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS); + } + else + { + sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK; + LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio); + sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT; + if(old != ie) + printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS); + } +} + +static void +lmc_t1_watchdog (lmc_softc_t * const sc) +{ +} + +static void +lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl) +{ + if (ctl == 0) + { + sc->ictl.keepalive_onoff = LMC_CTL_ON; + + return; + } +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_media.h linux/drivers/net/wan/lmc/lmc_media.h --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_media.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_media.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,64 @@ +#ifndef _LMC_MEDIA_H_ +#define _LMC_MEDIA_H_ + +lmc_media_t lmc_ds3_media = { + lmc_ds3_init, /* special media init stuff */ + lmc_ds3_default, /* reset to default state */ + lmc_ds3_set_status, /* reset status to state provided */ + lmc_dummy_set_1, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_ds3_set_100ft, /* set cable length */ + lmc_ds3_set_scram, /* set scrambler */ + lmc_ds3_get_link_status, /* get link status */ + lmc_dummy_set_1, /* set link status */ + lmc_ds3_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_ds3_watchdog +}; + +lmc_media_t lmc_hssi_media = { + lmc_hssi_init, /* special media init stuff */ + lmc_hssi_default, /* reset to default state */ + lmc_hssi_set_status, /* reset status to state provided */ + lmc_hssi_set_clock, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_hssi_get_link_status, /* get link status */ + lmc_hssi_set_link_status, /* set link status */ + lmc_hssi_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_hssi_watchdog +}; + +lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */ + lmc_ssi_default, /* reset to default state */ + lmc_ssi_set_status, /* reset status to state provided */ + lmc_ssi_set_clock, /* set clock source */ + lmc_ssi_set_speed, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_ssi_get_link_status, /* get link status */ + lmc_ssi_set_link_status, /* set link status */ + lmc_ssi_set_crc_length, /* set CRC length */ + lmc_dummy_set_1, /* set T1 or E1 circuit type */ + lmc_ssi_watchdog +}; + +lmc_media_t lmc_t1_media = { + lmc_t1_init, /* special media init stuff */ + lmc_t1_default, /* reset to default state */ + lmc_t1_set_status, /* reset status to state provided */ + lmc_t1_set_clock, /* set clock source */ + lmc_dummy_set2_1, /* set line speed */ + lmc_dummy_set_1, /* set cable length */ + lmc_dummy_set_1, /* set scrambler */ + lmc_t1_get_link_status, /* get link status */ + lmc_dummy_set_1, /* set link status */ + lmc_t1_set_crc_length, /* set CRC length */ + lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */ + lmc_t1_watchdog +}; + + +#endif \ No newline at end of file diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_prot.h linux/drivers/net/wan/lmc/lmc_prot.h --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_prot.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_prot.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,14 @@ +#ifndef _LMC_PROTO_H_ +#define _LMC_PROTO_H_ + +void lmc_proto_init(lmc_softc_t * const) +void lmc_proto_attach(lmc_softc_t *sc const) +void lmc_proto_detach(lmc_softc *sc const) +void lmc_proto_reopen(lmc_softc_t *sc const) +int lmc_proto_ioctl(lmc_softc_t *sc const, struct ifreq *ifr, int cmd) +void lmc_proto_open(lmc_softc_t *sc const) +void lmc_proto_close(lmc_softc_t *sc const) +unsigned short lmc_proto_type(lmc_softc_t *sc const, struct skbuff *skb) + + +#endif \ No newline at end of file diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto.c linux/drivers/net/wan/lmc/lmc_proto.c --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_proto.c Fri Apr 21 16:38:26 2000 @@ -0,0 +1,270 @@ + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * With Help By: + * David Boggs + * Ron Crane + * Allan Cox + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + * + * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +#include +#include +#include +#include "../syncppp.h" +#include +#include +#include + +#include "lmc_ver.h" +#include "lmc.h" +#include "lmc_var.h" +#include "lmc_debug.h" +#include "lmc_ioctl.h" +#include "lmc_proto.h" +//#include "lmc_proto_raw.h" + +/* + * The compile-time variable SPPPSTUP causes the module to be + * compiled without referencing any of the sync ppp routines. + */ +#ifdef SPPPSTUB +#define SYNC_PPP_init() (void)0 +#define SPPP_detach(d) (void)0 +#define SPPP_open(d) 0 +#define SPPP_reopen(d) (void)0 +#define SPPP_close(d) (void)0 +#define SPPP_attach(d) (void)0 +#define SPPP_do_ioctl(d,i,c) -EOPNOTSUPP +#else +#if LINUX_VERSION_CODE < 0x20363 +#define SYNC_PPP_init sync_ppp_init +#define SPPP_attach(x) sppp_attach((struct ppp_device *)(x)->lmc_device) +#define SPPP_detach(x) sppp_detach((x)->lmc_device) +#define SPPP_open(x) sppp_open((x)->lmc_device) +#define SPPP_reopen(x) sppp_reopen((x)->lmc_device) +#define SPPP_close(x) sppp_close((x)->lmc_device) +#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->lmc_device, (y), (z)) +#else +#define SYNC_PPP_init sync_ppp_init +#define SPPP_attach(x) sppp_attach((x)->pd) +#define SPPP_detach(x) sppp_detach((x)->pd->dev) +#define SPPP_open(x) sppp_open((x)->pd->dev) +#define SPPP_reopen(x) sppp_reopen((x)->pd->dev) +#define SPPP_close(x) sppp_close((x)->pd->dev) +#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->pd->dev, (y), (z)) +#endif +#endif + +static int lmc_first_ppp_load = 0; + +// init +void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_init in"); + switch(sc->if_type){ + case LMC_PPP: + if(lmc_first_ppp_load == 0) +#ifndef MODULE + SYNC_PPP_init(); +#endif + +#if LINUX_VERSION_CODE >= 0x20363 + sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL); + sc->pd->dev = sc->lmc_device; +#endif + sc->if_ptr = sc->pd; + break; + case LMC_RAW: + break; + default: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_init out"); +} + +// attach +void lmc_proto_attach(lmc_softc_t *sc) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_attach in"); + switch(sc->if_type){ + case LMC_PPP: + { + struct net_device *dev = sc->lmc_device; + SPPP_attach(sc); + dev->do_ioctl = lmc_ioctl; + } + break; + case LMC_NET: + { + struct net_device *dev = sc->lmc_device; + /* + * They set a few basics because they don't use sync_ppp + */ + dev->flags |= IFF_POINTOPOINT; + dev->hard_header = 0; + dev->hard_header_len = 0; + dev->addr_len = 0; + } + case LMC_RAW: /* Setup the task queue, maybe we should notify someone? */ + { + } + default: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_attach out"); +} + +// detach +void lmc_proto_detach(lmc_softc_t *sc) /*FOLD00*/ +{ + switch(sc->if_type){ + case LMC_PPP: + SPPP_detach(sc); + break; + case LMC_RAW: /* Tell someone we're detaching? */ + break; + default: + break; + } + +} + +// reopen +void lmc_proto_reopen(lmc_softc_t *sc) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_reopen in"); + switch(sc->if_type){ + case LMC_PPP: + SPPP_reopen(sc); + break; + case LMC_RAW: /* Reset the interface after being down, prerape to receive packets again */ + break; + default: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_reopen out"); +} + + +// ioctl +int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_ioctl out"); + switch(sc->if_type){ + case LMC_PPP: + return SPPP_do_ioctl (sc, ifr, cmd); + break; + default: + return -EOPNOTSUPP; + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_ioctl out"); +} + +// open +void lmc_proto_open(lmc_softc_t *sc) /*FOLD00*/ +{ + int ret; + + lmc_trace(sc->lmc_device, "lmc_proto_open in"); + switch(sc->if_type){ + case LMC_PPP: + ret = SPPP_open(sc); + if(ret < 0) + printk("%s: syncPPP open failed: %d\n", sc->name, ret); + break; + case LMC_RAW: /* We're about to start getting packets! */ + break; + default: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_open out"); +} + +// close + +void lmc_proto_close(lmc_softc_t *sc) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_close in"); + switch(sc->if_type){ + case LMC_PPP: + SPPP_close(sc); + break; + case LMC_RAW: /* Interface going down */ + break; + default: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_close out"); +} + +unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_type in"); + switch(sc->if_type){ + case LMC_PPP: + return htons(ETH_P_WAN_PPP); + break; + case LMC_NET: + return htons(ETH_P_802_2); + break; + case LMC_RAW: /* Packet type for skbuff kind of useless */ + return htons(ETH_P_802_2); + break; + default: + printk(KERN_WARNING "%s: No protocol set for this interface, assuming 802.2 (which is wrong!!)\n", sc->name); + return htons(ETH_P_802_2); + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_tye out"); + +} + +void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/ +{ + lmc_trace(sc->lmc_device, "lmc_proto_netif in"); + switch(sc->if_type){ + case LMC_PPP: + case LMC_NET: + default: + netif_rx(skb); + break; + case LMC_RAW: + break; + } + lmc_trace(sc->lmc_device, "lmc_proto_netif out"); +} + diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto.h linux/drivers/net/wan/lmc/lmc_proto.h --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_proto.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,15 @@ +#ifndef _LMC_PROTO_H_ +#define _LMC_PROTO_H_ + +void lmc_proto_init(lmc_softc_t *sc); +void lmc_proto_attach(lmc_softc_t *sc); +void lmc_proto_detach(lmc_softc_t *sc); +void lmc_proto_reopen(lmc_softc_t *sc); +int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd); +void lmc_proto_open(lmc_softc_t *sc); +void lmc_proto_close(lmc_softc_t *sc); +unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb); +void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb); +int lmc_skb_rawpackets(char *buf, char **start, off_t offset, int len, int unused); + +#endif \ No newline at end of file diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto_raw.h linux/drivers/net/wan/lmc/lmc_proto_raw.h --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_proto_raw.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_proto_raw.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,4 @@ +#ifndef _LMC_PROTO_RAW_H_ +#define _LMC_PROTO_RAW_H_ + +#endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_var.h linux/drivers/net/wan/lmc/lmc_var.h --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_var.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_var.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,590 @@ +#ifndef _LMC_VAR_H_ +#define _LMC_VAR_H_ + +/* $Id: lmc_var.h,v 1.17 2000/04/06 12:16:47 asj Exp $ */ + + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + */ + +#include + +#ifndef __KERNEL__ +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +#endif + +/* + * basic definitions used in lmc include files + */ + +typedef struct lmc___softc lmc_softc_t; +typedef struct lmc___media lmc_media_t; +typedef struct lmc___ctl lmc_ctl_t; + +#define lmc_csrptr_t unsigned long +#define u_int16_t u16 +#define u_int8_t u8 +#define tulip_uint32_t u32 +#if LINUX_VERSION_CODE < 0x20155 +#define u_int32_t u32 +#endif + +#define LMC_REG_RANGE 0x80 + +#define LMC_PRINTF_FMT "%s" +#define LMC_PRINTF_ARGS (sc->lmc_device->name) + +#define TX_TIMEOUT (2*HZ) + +#define LMC_TXDESCS 32 +#define LMC_RXDESCS 32 + +#define LMC_LINK_UP 1 +#define LMC_LINK_DOWN 0 + +/* These macros for generic read and write to and from the dec chip */ +#define LMC_CSR_READ(sc, csr) \ + inl((sc)->lmc_csrs.csr) +#define LMC_CSR_WRITE(sc, reg, val) \ + outl((val), (sc)->lmc_csrs.reg) + +//#ifdef _LINUX_DELAY_H +// #define SLOW_DOWN_IO udelay(2); +// #undef __SLOW_DOWN_IO +// #define __SLOW_DOWN_IO udelay(2); +//#endif + +#define DELAY(n) SLOW_DOWN_IO + +#define lmc_delay() inl(sc->lmc_csrs.csr_9) + +/* This macro sync's up with the mii so that reads and writes can take place */ +#define LMC_MII_SYNC(sc) do {int n=32; while( n >= 0 ) { \ + LMC_CSR_WRITE((sc), csr_9, 0x20000); \ + lmc_delay(); \ + LMC_CSR_WRITE((sc), csr_9, 0x30000); \ + lmc_delay(); \ + n--; }} while(0); + +struct lmc_regfile_t { + lmc_csrptr_t csr_busmode; /* CSR0 */ + lmc_csrptr_t csr_txpoll; /* CSR1 */ + lmc_csrptr_t csr_rxpoll; /* CSR2 */ + lmc_csrptr_t csr_rxlist; /* CSR3 */ + lmc_csrptr_t csr_txlist; /* CSR4 */ + lmc_csrptr_t csr_status; /* CSR5 */ + lmc_csrptr_t csr_command; /* CSR6 */ + lmc_csrptr_t csr_intr; /* CSR7 */ + lmc_csrptr_t csr_missed_frames; /* CSR8 */ + lmc_csrptr_t csr_9; /* CSR9 */ + lmc_csrptr_t csr_10; /* CSR10 */ + lmc_csrptr_t csr_11; /* CSR11 */ + lmc_csrptr_t csr_12; /* CSR12 */ + lmc_csrptr_t csr_13; /* CSR13 */ + lmc_csrptr_t csr_14; /* CSR14 */ + lmc_csrptr_t csr_15; /* CSR15 */ +}; + +#define csr_enetrom csr_9 /* 21040 */ +#define csr_reserved csr_10 /* 21040 */ +#define csr_full_duplex csr_11 /* 21040 */ +#define csr_bootrom csr_10 /* 21041/21140A/?? */ +#define csr_gp csr_12 /* 21140* */ +#define csr_watchdog csr_15 /* 21140* */ +#define csr_gp_timer csr_11 /* 21041/21140* */ +#define csr_srom_mii csr_9 /* 21041/21140* */ +#define csr_sia_status csr_12 /* 2104x */ +#define csr_sia_connectivity csr_13 /* 2104x */ +#define csr_sia_tx_rx csr_14 /* 2104x */ +#define csr_sia_general csr_15 /* 2104x */ + +/* tulip length/control transmit descriptor definitions + * used to define bits in the second tulip_desc_t field (length) + * for the transmit descriptor -baz */ + +#define LMC_TDES_FIRST_BUFFER_SIZE ((u_int32_t)(0x000007FF)) +#define LMC_TDES_SECOND_BUFFER_SIZE ((u_int32_t)(0x003FF800)) +#define LMC_TDES_HASH_FILTERING ((u_int32_t)(0x00400000)) +#define LMC_TDES_DISABLE_PADDING ((u_int32_t)(0x00800000)) +#define LMC_TDES_SECOND_ADDR_CHAINED ((u_int32_t)(0x01000000)) +#define LMC_TDES_END_OF_RING ((u_int32_t)(0x02000000)) +#define LMC_TDES_ADD_CRC_DISABLE ((u_int32_t)(0x04000000)) +#define LMC_TDES_SETUP_PACKET ((u_int32_t)(0x08000000)) +#define LMC_TDES_INVERSE_FILTERING ((u_int32_t)(0x10000000)) +#define LMC_TDES_FIRST_SEGMENT ((u_int32_t)(0x20000000)) +#define LMC_TDES_LAST_SEGMENT ((u_int32_t)(0x40000000)) +#define LMC_TDES_INTERRUPT_ON_COMPLETION ((u_int32_t)(0x80000000)) + +#define TDES_SECOND_BUFFER_SIZE_BIT_NUMBER 11 +#define TDES_COLLISION_COUNT_BIT_NUMBER 3 + +/* Constants for the RCV descriptor RDES */ + +#define LMC_RDES_OVERFLOW ((u_int32_t)(0x00000001)) +#define LMC_RDES_CRC_ERROR ((u_int32_t)(0x00000002)) +#define LMC_RDES_DRIBBLING_BIT ((u_int32_t)(0x00000004)) +#define LMC_RDES_REPORT_ON_MII_ERR ((u_int32_t)(0x00000008)) +#define LMC_RDES_RCV_WATCHDOG_TIMEOUT ((u_int32_t)(0x00000010)) +#define LMC_RDES_FRAME_TYPE ((u_int32_t)(0x00000020)) +#define LMC_RDES_COLLISION_SEEN ((u_int32_t)(0x00000040)) +#define LMC_RDES_FRAME_TOO_LONG ((u_int32_t)(0x00000080)) +#define LMC_RDES_LAST_DESCRIPTOR ((u_int32_t)(0x00000100)) +#define LMC_RDES_FIRST_DESCRIPTOR ((u_int32_t)(0x00000200)) +#define LMC_RDES_MULTICAST_FRAME ((u_int32_t)(0x00000400)) +#define LMC_RDES_RUNT_FRAME ((u_int32_t)(0x00000800)) +#define LMC_RDES_DATA_TYPE ((u_int32_t)(0x00003000)) +#define LMC_RDES_LENGTH_ERROR ((u_int32_t)(0x00004000)) +#define LMC_RDES_ERROR_SUMMARY ((u_int32_t)(0x00008000)) +#define LMC_RDES_FRAME_LENGTH ((u_int32_t)(0x3FFF0000)) +#define LMC_RDES_OWN_BIT ((u_int32_t)(0x80000000)) + +#define RDES_FRAME_LENGTH_BIT_NUMBER 16 + +#define LMC_RDES_ERROR_MASK ( (u_int32_t)( \ + LMC_RDES_OVERFLOW \ + | LMC_RDES_DRIBBLING_BIT \ + | LMC_RDES_REPORT_ON_MII_ERR \ + | LMC_RDES_COLLISION_SEEN ) ) + + +/* + * Ioctl info + */ + +typedef struct { + u_int32_t n; + u_int32_t m; + u_int32_t v; + u_int32_t x; + u_int32_t r; + u_int32_t f; + u_int32_t exact; +} lmc_av9110_t; + +/* + * Common structure passed to the ioctl code. + */ +struct lmc___ctl { + u_int32_t cardtype; + u_int32_t clock_source; /* HSSI, T1 */ + u_int32_t clock_rate; /* T1 */ + u_int32_t crc_length; + u_int32_t cable_length; /* DS3 */ + u_int32_t scrambler_onoff; /* DS3 */ + u_int32_t cable_type; /* T1 */ + u_int32_t keepalive_onoff; /* protocol */ + u_int32_t ticks; /* ticks/sec */ + union { + lmc_av9110_t ssi; + } cardspec; + u_int32_t circuit_type; /* T1 or E1 */ +}; + + +/* + * Carefull, look at the data sheet, there's more to this + * structure than meets the eye. It should probably be: + * + * struct tulip_desc_t { + * u8 own:1; + * u32 status:31; + * u32 control:10; + * u32 buffer1; + * u32 buffer2; + * }; + * You could also expand status control to provide more bit information + */ + +struct tulip_desc_t { + s32 status; + s32 length; + u32 buffer1; + u32 buffer2; +}; + +/* + * media independent methods to check on media status, link, light LEDs, + * etc. + */ +struct lmc___media { + void (* init)(lmc_softc_t * const); + void (* defaults)(lmc_softc_t * const); + void (* set_status)(lmc_softc_t * const, lmc_ctl_t *); + void (* set_clock_source)(lmc_softc_t * const, int); + void (* set_speed)(lmc_softc_t * const, lmc_ctl_t *); + void (* set_cable_length)(lmc_softc_t * const, int); + void (* set_scrambler)(lmc_softc_t * const, int); + int (* get_link_status)(lmc_softc_t * const); + void (* set_link_status)(lmc_softc_t * const, int); + void (* set_crc_length)(lmc_softc_t * const, int); + void (* set_circuit_type)(lmc_softc_t * const, int); + void (* watchdog)(lmc_softc_t * const); +}; + + +#define STATCHECK 0xBEEFCAFE + +/* Included in this structure are first + * - standard enet_statistics + * - some other counters used for debug and driver performance + * evaluation -baz + */ +struct lmc_statistics +{ + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmitted */ + unsigned long rx_bytes; + unsigned long tx_bytes; + + unsigned long rx_errors; /* bad packets received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* no space in linux buffers */ + unsigned long tx_dropped; /* no space available in linux */ + unsigned long multicast; /* multicast packets received */ + unsigned long collisions; + + /* detailed rx_errors: */ + unsigned long rx_length_errors; + unsigned long rx_over_errors; /* receiver ring buff overflow */ + unsigned long rx_crc_errors; /* recved pkt with crc error */ + unsigned long rx_frame_errors; /* recv'd frame alignment error */ + unsigned long rx_fifo_errors; /* recv'r fifo overrun */ + unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + unsigned long tx_aborted_errors; + unsigned long tx_carrier_errors; + unsigned long tx_fifo_errors; + unsigned long tx_heartbeat_errors; + unsigned long tx_window_errors; + + /* for cslip etc */ + unsigned long rx_compressed; + unsigned long tx_compressed; + + /* ------------------------------------- + * Custom stats & counters follow -baz */ + u_int32_t version_size; + u_int32_t lmc_cardtype; + + u_int32_t tx_ProcTimeout; + u_int32_t tx_IntTimeout; + u_int32_t tx_NoCompleteCnt; + u_int32_t tx_MaxXmtsB4Int; + u_int32_t tx_TimeoutCnt; + u_int32_t tx_OutOfSyncPtr; + u_int32_t tx_tbusy0; + u_int32_t tx_tbusy1; + u_int32_t tx_tbusy_calls; + u_int32_t resetCount; + u_int32_t lmc_txfull; + u_int32_t tbusy; + u_int32_t dirtyTx; + u_int32_t lmc_next_tx; + u_int32_t otherTypeCnt; + u_int32_t lastType; + u_int32_t lastTypeOK; + u_int32_t txLoopCnt; + u_int32_t usedXmtDescripCnt; + u_int32_t txIndexCnt; + u_int32_t rxIntLoopCnt; + + u_int32_t rx_SmallPktCnt; + u_int32_t rx_BadPktSurgeCnt; + u_int32_t rx_BuffAllocErr; + u_int32_t tx_lossOfClockCnt; + + /* T1 error counters */ + u_int32_t framingBitErrorCount; + u_int32_t lineCodeViolationCount; + + u_int32_t lossOfFrameCount; + u_int32_t changeOfFrameAlignmentCount; + u_int32_t severelyErroredFrameCount; + + u_int32_t check; +}; + + +typedef struct lmc_xinfo { + u_int32_t Magic0; /* BEEFCAFE */ + + u_int32_t PciCardType; + u_int32_t PciSlotNumber; /* PCI slot number */ + + u_int16_t DriverMajorVersion; + u_int16_t DriverMinorVersion; + u_int16_t DriverSubVersion; + + u_int16_t XilinxRevisionNumber; + u_int16_t MaxFrameSize; + + u_int16_t t1_alarm1_status; + u_int16_t t1_alarm2_status; + + int link_status; + u_int32_t mii_reg16; + + u_int32_t Magic1; /* DEADBEEF */ +} LMC_XINFO; + + +/* + * forward decl + */ +struct lmc___softc { + void *if_ptr; /* General purpose pointer (used by SPPP) */ + char *name; + u8 board_idx; + struct lmc_statistics stats; + struct net_device *lmc_device; + + int hang, rxdesc, bad_packet, some_counter; + u_int32_t txgo; + struct lmc_regfile_t lmc_csrs; + volatile u_int32_t lmc_txtick; + volatile u_int32_t lmc_rxtick; + u_int32_t lmc_flags; + u_int32_t lmc_intrmask; /* our copy of csr_intr */ + u_int32_t lmc_cmdmode; /* our copy of csr_cmdmode */ + u_int32_t lmc_busmode; /* our copy of csr_busmode */ + u_int32_t lmc_gpio_io; /* state of in/out settings */ + u_int32_t lmc_gpio; /* state of outputs */ + struct sk_buff* lmc_txq[LMC_TXDESCS]; + struct sk_buff* lmc_rxq[LMC_RXDESCS]; + volatile + struct tulip_desc_t lmc_rxring[LMC_RXDESCS]; + volatile + struct tulip_desc_t lmc_txring[LMC_TXDESCS]; + unsigned int lmc_next_rx, lmc_next_tx; + volatile + unsigned int lmc_taint_tx, lmc_taint_rx; + int lmc_tx_start, lmc_txfull; + int lmc_txbusy; + u_int16_t lmc_miireg16; + int lmc_ok; + int last_link_status; + int lmc_cardtype; + u_int32_t last_frameerr; + lmc_media_t *lmc_media; + struct timer_list timer; + lmc_ctl_t ictl; + u_int32_t TxDescriptControlInit; + struct net_device *next_module; /* Link to the next module */ + int tx_TimeoutInd; /* additional driver state */ + int tx_TimeoutDisplay; + unsigned int lastlmc_taint_tx; + int lasttx_packets; + u_int32_t tx_clockState; + u_int32_t lmc_crcSize; + LMC_XINFO lmc_xinfo; + char lmc_yel, lmc_blue, lmc_red; /* for T1 and DS3 */ + char lmc_timing; /* for HSSI and SSI */ + int got_irq; + + char last_led_err[4]; + + u32 last_int; + u32 num_int; + +#if LINUX_VERSION_CODE >= 0x20200 + spinlock_t lmc_lock; +#endif + u_int16_t if_type; /* PPP or NET */ + struct ppp_device *pd; + + /* Failure cases */ + u8 failed_ring; + u8 failed_recv_alloc; + + /* Structure check */ + u32 check; +}; + +#define LMC_PCI_TIME 1 +#define LMC_EXT_TIME 0 + +#define PKT_BUF_SZ 1542 /* was 1536 */ + +/* CSR5 settings */ +#define TIMER_INT 0x00000800 +#define TP_LINK_FAIL 0x00001000 +#define TP_LINK_PASS 0x00000010 +#define NORMAL_INT 0x00010000 +#define ABNORMAL_INT 0x00008000 +#define RX_JABBER_INT 0x00000200 +#define RX_DIED 0x00000100 +#define RX_NOBUFF 0x00000080 +#define RX_INT 0x00000040 +#define TX_FIFO_UNDER 0x00000020 +#define TX_JABBER 0x00000008 +#define TX_NOBUFF 0x00000004 +#define TX_DIED 0x00000002 +#define TX_INT 0x00000001 + +/* CSR6 settings */ +#define OPERATION_MODE 0x00000200 /* Full Duplex */ +#define PROMISC_MODE 0x00000040 /* Promiscuous Mode */ +#define RECIEVE_ALL 0x40000000 /* Recieve All */ +#define PASS_BAD_FRAMES 0x00000008 /* Pass Bad Frames */ + +/* Dec control registers CSR6 as well */ +#define LMC_DEC_ST 0x00002000 +#define LMC_DEC_SR 0x00000002 + +/* CSR15 settings */ +#define RECV_WATCHDOG_DISABLE 0x00000010 +#define JABBER_DISABLE 0x00000001 + +/* More settings */ +/* + * aSR6 -- Command (Operation Mode) Register + */ +#define TULIP_CMD_RECEIVEALL 0x40000000L /* (RW) Receivel all frames? */ +#define TULIP_CMD_MUSTBEONE 0x02000000L /* (RW) Must Be One (21140) */ +#define TULIP_CMD_TXTHRSHLDCTL 0x00400000L /* (RW) Transmit Threshold Mode (21140) */ +#define TULIP_CMD_STOREFWD 0x00200000L /* (RW) Store and Foward (21140) */ +#define TULIP_CMD_NOHEARTBEAT 0x00080000L /* (RW) No Heartbeat (21140) */ +#define TULIP_CMD_PORTSELECT 0x00040000L /* (RW) Post Select (100Mb) (21140) */ +#define TULIP_CMD_FULLDUPLEX 0x00000200L /* (RW) Full Duplex Mode */ +#define TULIP_CMD_OPERMODE 0x00000C00L /* (RW) Operating Mode */ +#define TULIP_CMD_PROMISCUOUS 0x00000041L /* (RW) Promiscuous Mode */ +#define TULIP_CMD_PASSBADPKT 0x00000008L /* (RW) Pass Bad Frames */ +#define TULIP_CMD_THRESHOLDCTL 0x0000C000L /* (RW) Threshold Control */ + +#define TULIP_GP_PINSET 0x00000100L +#define TULIP_BUSMODE_SWRESET 0x00000001L +#define TULIP_WATCHDOG_TXDISABLE 0x00000001L +#define TULIP_WATCHDOG_RXDISABLE 0x00000010L + +#define TULIP_STS_NORMALINTR 0x00010000L /* (RW) Normal Interrupt */ +#define TULIP_STS_ABNRMLINTR 0x00008000L /* (RW) Abnormal Interrupt */ +#define TULIP_STS_ERI 0x00004000L /* (RW) Early Receive Interupt */ +#define TULIP_STS_SYSERROR 0x00002000L /* (RW) System Error */ +#define TULIP_STS_GTE 0x00000800L /* (RW) General Pupose Timer Exp */ +#define TULIP_STS_ETI 0x00000400L /* (RW) Early Transmit Interupt */ +#define TULIP_STS_RXWT 0x00000200L /* (RW) Receiver Watchdog Timeout */ +#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receiver Process Stopped */ +#define TULIP_STS_RXNOBUF 0x00000080L /* (RW) Receive Buf Unavail */ +#define TULIP_STS_RXINTR 0x00000040L /* (RW) Receive Interrupt */ +#define TULIP_STS_TXUNDERFLOW 0x00000020L /* (RW) Transmit Underflow */ +#define TULIP_STS_TXJABER 0x00000008L /* (RW) Jabber timeout */ +#define TULIP_STS_TXNOBUF 0x00000004L +#define TULIP_STS_TXSTOPPED 0x00000002L /* (RW) Transmit Process Stopped */ +#define TULIP_STS_TXINTR 0x00000001L /* (RW) Transmit Interrupt */ + +#define TULIP_STS_RXS_STOPPED 0x00000000L /* 000 - Stopped */ + +#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receive Process Stopped */ +#define TULIP_STS_RXNOBUF 0x00000080L + +#define TULIP_CMD_TXRUN 0x00002000L /* (RW) Start/Stop Transmitter */ +#define TULIP_CMD_RXRUN 0x00000002L /* (RW) Start/Stop Receive Filtering */ +#define TULIP_DSTS_TxDEFERRED 0x00000001 /* Initially Deferred */ +#define TULIP_DSTS_OWNER 0x80000000 /* Owner (1 = 21040) */ +#define TULIP_DSTS_RxMIIERR 0x00000008 +#define LMC_DSTS_ERRSUM (TULIP_DSTS_RxMIIERR) + +#define TULIP_DEFAULT_INTR_MASK (TULIP_STS_NORMALINTR \ + | TULIP_STS_RXINTR \ + | TULIP_STS_TXINTR \ + | TULIP_STS_ABNRMLINTR \ + | TULIP_STS_SYSERROR \ + | TULIP_STS_TXSTOPPED \ + | TULIP_STS_TXUNDERFLOW\ + | TULIP_STS_RXSTOPPED ) + +#define DESC_OWNED_BY_SYSTEM ((u_int32_t)(0x00000000)) +#define DESC_OWNED_BY_DC21X4 ((u_int32_t)(0x80000000)) + +#ifndef TULIP_CMD_RECEIVEALL +#define TULIP_CMD_RECEIVEALL 0x40000000L +#endif + + +/* PCI register values */ +#define CORRECT_VENDOR_ID 0x1011 +#define CORRECT_DEV_ID 9 + +#define PCI_VENDOR_LMC 0x1376 +#define PCI_PRODUCT_LMC_HSSI 0x0003 +#define PCI_PRODUCT_LMC_DS3 0x0004 +#define PCI_PRODUCT_LMC_SSI 0x0005 +#define PCI_PRODUCT_LMC_T1 0x0006 + +/* Adapcter module number */ +#define LMC_ADAP_HSSI 2 +#define LMC_ADAP_DS3 3 +#define LMC_ADAP_SSI 4 +#define LMC_ADAP_T1 5 + +#define HDLC_HDR_LEN 4 +#define HDLC_ADDR_LEN 1 +#define HDLC_SLARP 0x8035 +#define LMC_MTU 1500 +#define SLARP_LINECHECK 2 + +#define LMC_CRC_LEN_16 2 /* 16-bit CRC */ +#define LMC_CRC_LEN_32 4 + +#if LINUX_VERSION_CODE < 0x20100 +#define test_and_set_bit(val, addr) set_bit(val, addr) +#endif + +#ifdef LMC_HDLC +/* definition of an hdlc header. */ +struct hdlc_hdr +{ + u8 address; + u8 control; + u16 type; +}; + +/* definition of a slarp header. */ +struct slarp +{ + long code; + union sl + { + struct + { + ulong address; + ulong mask; + ushort unused; + } add; + struct + { + ulong mysequence; + ulong yoursequence; + ushort reliability; + ulong time; + } chk; + } t; +}; +#endif /* LMC_HDLC */ + + +#endif /* _LMC_VAR_H_ */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_ver.h linux/drivers/net/wan/lmc/lmc_ver.h --- v2.3.99-pre5/linux/drivers/net/wan/lmc/lmc_ver.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/lmc/lmc_ver.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,123 @@ +#ifndef _IF_LMC_LINUXVER_ +#define _IF_LMC_LINUXVER_ + + /* + * Copyright (c) 1997-2000 LAN Media Corporation (LMC) + * All rights reserved. www.lanmedia.com + * + * This code is written by: + * Andrew Stanley-Jones (asj@cban.com) + * Rob Braun (bbraun@vix.com), + * Michael Graff (explorer@vix.com) and + * Matt Thomas (matt@3am-software.com). + * + * This software may be used and distributed according to the terms + * of the GNU Public License version 2, incorporated herein by reference. + */ + + /* + * This file defines and controls all linux version + * differences. + * + * This is being done to keep 1 central location where all linux + * version differences can be kept and maintained. as this code was + * found version issues where pepered throughout the source code and + * made the souce code not only hard to read but version problems hard + * to track down. If I'm overiding a function/etc with something in + * this file it will be prefixed by "LMC_" which will mean look + * here for the the version dependant change that's been done. + * + */ + +#if LINUX_VERSION_CODE < 0x20363 +#define net_device device +#endif + +#if LINUX_VERSION_CODE < 0x20363 +#define LMC_XMITTER_BUSY(x) (x)->tbusy = 1 +#define LMC_XMITTER_FREE(x) (x)->tbusy = 0 +#define LMC_XMITTER_INIT(x) (x)->tbusy = 0 +#else +#define LMC_XMITTER_BUSY(x) netif_stop_queue(x) +#define LMC_XMITTER_FREE(x) netif_wake_queue(x) +#define LMC_XMITTER_INIT(x) netif_start_queue(x) + +#endif + + +#if LINUX_VERSION_CODE < 0x20100 +//typedef unsigned int u_int32_t; + +#define LMC_SETUP_20_DEV {\ + int indx; \ + for (indx = 0; indx < DEV_NUMBUFFS; indx++) \ + skb_queue_head_init (&dev->buffs[indx]); \ + } \ + dev->family = AF_INET; \ + dev->pa_addr = 0; \ + dev->pa_brdaddr = 0; \ + dev->pa_mask = 0xFCFFFFFF; \ + dev->pa_alen = 4; /* IP addr. sizeof(u32) */ + +#else + +#define LMC_SETUP_20_DEV + +#endif + + +#if LINUX_VERSION_CODE < 0x20155 /* basically 2.2 plus */ + +#define LMC_DEV_KFREE_SKB(skb) dev_kfree_skb((skb), FREE_WRITE) +#define LMC_PCI_PRESENT() pcibios_present() + +#else /* Mostly 2.0 kernels */ + +#define LMC_DEV_KFREE_SKB(skb) dev_kfree_skb(skb) +#define LMC_PCI_PRESENT() pci_present() + +#endif + +#if LINUX_VERSION_CODE < 0x20200 +#else + +#endif + +#if LINUX_VERSION_CODE < 0x20100 +#define LMC_SKB_FREE(skb, val) (skb->free = val) +#else +#define LMC_SKB_FREE(skb, val) +#endif + + +#if (LINUX_VERSION_CODE >= 0x20200) + +#define LMC_SPIN_FLAGS unsigned long flags; +#define LMC_SPIN_LOCK_INIT(x) spin_lock_init(&(x)->lmc_lock); +#define LMC_SPIN_UNLOCK(x) ((x)->lmc_lock = SPIN_LOCK_UNLOCKED) +#define LMC_SPIN_LOCK_IRQSAVE(x) spin_lock_irqsave (&(x)->lmc_lock, flags); +#define LMC_SPIN_UNLOCK_IRQRESTORE(x) spin_unlock_irqrestore (&(x)->lmc_lock, flags); +#else +#define LMC_SPIN_FLAGS +#define LMC_SPIN_LOCK_INIT(x) +#define LMC_SPIN_UNLOCK(x) +#define LMC_SPIN_LOCK_IRQSAVE(x) +#define LMC_SPIN_UNLOCK_IRQRESTORE(x) +#endif + + +#if LINUX_VERSION_CODE >= 0x20100 +#define LMC_COPY_FROM_USER(x, y, z) if(copy_from_user ((x), (y), (z))) return -EFAULT +#define LMC_COPY_TO_USER(x, y, z) if(copy_to_user ((x), (y), (z))) return -EFAULT +#else +#define LMC_COPY_FROM_USER(x, y, z) if(verify_area(VERIFY_READ, (y), (z))) \ + return -EFAULT; \ + memcpy_fromfs ((x), (y), (z)) + +#define LMC_COPY_TO_USER(x, y, z) if(verify_area(VERIFY_WRITE, (x), (z))) \ + return -EFAULT; \ + memcpy_tofs ((x), (y), (z)) +#endif + + +#endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c --- v2.3.99-pre5/linux/drivers/net/wan/sdla_chdlc.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/wan/sdla_chdlc.c Fri Apr 21 16:08:45 2000 @@ -22,6 +22,7 @@ * Aug 07, 1998 David Fong Initial version. *****************************************************************************/ +#include #include #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ @@ -2762,7 +2763,7 @@ void s508_lock (sdla_t *card, unsigned long *smp_flags) { -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_lock_irqsave(&card->lock, *smp_flags); if (card->next){ spin_lock(&card->next->lock); @@ -2774,7 +2775,7 @@ void s508_unlock (sdla_t *card, unsigned long *smp_flags) { -#ifdef __SMP__ +#ifdef CONFIG_SMP if (card->next){ spin_unlock(&card->next->lock); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c --- v2.3.99-pre5/linux/drivers/net/wan/sdla_fr.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/wan/sdla_fr.c Fri Apr 21 16:08:45 2000 @@ -109,6 +109,7 @@ * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ +#include #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ @@ -3677,13 +3678,13 @@ { if (card->hw.type != SDLA_S514){ -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_lock_irqsave(&card->lock, *smp_flags); #else disable_irq(card->hw.irq); #endif } -#ifdef __SMP__ +#ifdef CONFIG_SMP else{ spin_lock(&card->lock); } @@ -3693,13 +3694,13 @@ void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) { if (card->hw.type != SDLA_S514){ -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_unlock_irqrestore(&card->lock, *smp_flags); #else enable_irq(card->hw.irq); #endif } -#ifdef __SMP__ +#ifdef CONFIG_SMP else{ spin_unlock(&card->lock); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c --- v2.3.99-pre5/linux/drivers/net/wan/sdla_ppp.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/wan/sdla_ppp.c Fri Apr 21 16:08:45 2000 @@ -74,6 +74,7 @@ * Jan 06, 1997 Gene Kozin Initial version. *****************************************************************************/ +#include #include #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ @@ -2896,7 +2897,7 @@ void s508_lock (sdla_t *card, unsigned long *smp_flags) { -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_lock_irqsave(&card->lock, *smp_flags); #else disable_irq(card->hw.irq); @@ -2905,7 +2906,7 @@ void s508_unlock (sdla_t *card, unsigned long *smp_flags) { -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_unlock_irqrestore(&card->lock, *smp_flags); #else enable_irq(card->hw.irq); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c --- v2.3.99-pre5/linux/drivers/net/wan/sdladrv.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/wan/sdladrv.c Wed Apr 12 09:38:57 2000 @@ -308,7 +308,7 @@ #ifdef MODULE int init_module (void) #else -__initfunc(int wanpipe_init(void)) +int __init wanpipe_init(void) #endif { printk(KERN_INFO "%s v%u.%u %s\n", diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/sdlamain.c linux/drivers/net/wan/sdlamain.c --- v2.3.99-pre5/linux/drivers/net/wan/sdlamain.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/wan/sdlamain.c Fri Apr 21 16:08:45 2000 @@ -391,7 +391,7 @@ if (!card->configured){ - #ifdef __SMP__ + #ifdef CONFIG_SMP /* Initialize the Spin lock */ printk(KERN_INFO "%s: Initializing SMP\n",wandev->name); spin_lock_init(&card->lock); @@ -825,13 +825,13 @@ /* Use spin lock only for S508 */ -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_lock(&card->lock); #endif sdla_intack(&card->hw); if (card->isr) card->isr(card); -#ifdef __SMP__ +#ifdef CONFIG_SMP spin_unlock(&card->lock); #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c --- v2.3.99-pre5/linux/drivers/net/wan/syncppp.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/net/wan/syncppp.c Fri Apr 21 16:08:45 2000 @@ -33,7 +33,7 @@ * * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 * - * $Id: if_spppsubr.c,v 1.12 1996/06/10 23:17:45 gpalmer Exp $ + * $Id: syncppp.c,v 1.18 2000/04/11 05:25:31 asj Exp $ */ #undef DEBUG @@ -193,7 +193,7 @@ * * This can be called directly by cards that do not have * timing constraints but is normally called from the network layer - * after interrupt servicing to process frames queued via netif_rx. + * after interrupt servicing to process frames queued via netif_rx(). * * We process the options in the card. If the frame is destined for * the protocol stacks then it requeues the frame for the upper level @@ -395,7 +395,7 @@ if (sp->pp_alivecnt == MAXALIVECNT) { /* No keepalive packets got. Stop the interface. */ - printk (KERN_WARNING "%s: down\n", dev->name); + printk (KERN_WARNING "%s: protocol down\n", dev->name); if_down (dev); if (! (sp->pp_flags & PP_CISCO)) { /* Shut down the PPP link. */ @@ -529,7 +529,6 @@ sppp_ipcp_open (sp); break; case LCP_STATE_OPENED: -#if 0 /* Remote magic changed -- close session. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; @@ -537,7 +536,6 @@ sppp_lcp_open (sp); /* An ACK has already been sent. */ sp->lcp.state = LCP_STATE_ACK_SENT; -#endif break; } break; @@ -549,7 +547,7 @@ (dev->flags & IFF_UP)) { /* Coming out of loopback mode. */ sp->pp_link_state=SPPP_LINK_UP; - printk (KERN_INFO "%s: up\n", dev->name); + printk (KERN_INFO "%s: protocol up\n", dev->name); } switch (sp->lcp.state) { case LCP_STATE_CLOSED: @@ -716,7 +714,7 @@ if (sp->pp_link_state==SPPP_LINK_DOWN && (dev->flags & IFF_UP)) { sp->pp_link_state=SPPP_LINK_UP; - printk (KERN_INFO "%s: up\n", dev->name); + printk (KERN_INFO "%s: protocol up\n", dev->name); } break; case CISCO_ADDR_REQ: diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c --- v2.3.99-pre5/linux/drivers/net/wan/z85230.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/net/wan/z85230.c Wed Apr 12 09:47:26 2000 @@ -1313,12 +1313,12 @@ /** * z8530_channel_load - Load channel data * @c: Z8530 channel to configure - * @rtable: Table of register, value pairs + * @rtable: table of register, value pairs * FIXME: ioctl to allow user uploaded tables * * Load a Z8530 channel up from the system data. We use +16 to - * indicate the 'prime' registers. The value 255 terminates the - * table + * indicate the "prime" registers. The value 255 terminates the + * table. */ int z8530_channel_load(struct z8530_channel *c, u8 *rtable) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c --- v2.3.99-pre5/linux/drivers/net/yellowfin.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/yellowfin.c Fri Apr 21 16:08:52 2000 @@ -1418,7 +1418,6 @@ * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog --- v2.3.99-pre5/linux/drivers/parport/ChangeLog Tue Apr 11 15:09:18 2000 +++ linux/drivers/parport/ChangeLog Thu Apr 13 09:25:44 2000 @@ -1,3 +1,20 @@ +2000-04-04 Tim Waugh + + * parport_pc.c: Add support for another PCI card. + +2000-04-04 Tim Waugh + + * daisy.c: Documentation in kernel-doc format. + + * ieee1284.c: Likewise. + + * share.c: Likewise. + +2000-04-01 Tim Waugh + + * share.c (parport_register_device): Need to hold the module + reference counts before sleeping. + 2000-03-27 Tim Waugh * parport_pc.c (parport_pc_ecp_read_block_pio): Correct operation diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/parport/daisy.c linux/drivers/parport/daisy.c --- v2.3.99-pre5/linux/drivers/parport/daisy.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/parport/daisy.c Wed Apr 12 09:47:26 2000 @@ -174,7 +174,26 @@ return; } -/* Find a device by canonical device number. */ +/** + * parport_open - find a device by canonical device number + * @devnum: canonical device number + * @name: name to associate with the device + * @pf: preemption callback + * @kf: kick callback + * @irqf: interrupt handler + * @flags: registration flags + * @handle: driver data + * + * This function is similar to parport_register_device(), except + * that it locates a device by its number rather than by the port + * it is attached to. See parport_find_device() and + * parport_find_class(). + * + * All parameters except for @devnum are the same as for + * parport_register_device(). The return value is the same as + * for parport_register_device(). + **/ + struct pardevice *parport_open (int devnum, const char *name, int (*pf) (void *), void (*kf) (void *), void (*irqf) (int, void *, struct pt_regs *), @@ -219,13 +238,32 @@ return dev; } -/* The converse of parport_open. */ +/** + * parport_close - close a device opened with parport_open() + * @dev: device to close + * + * This is to parport_open() as parport_unregister_device() is to + * parport_register_device(). + **/ + void parport_close (struct pardevice *dev) { parport_unregister_device (dev); } -/* Convert device coordinates into a canonical device number. */ +/** + * parport_device_num - convert device coordinates into a + * canonical device number + * @parport: parallel port number + * @mux: multiplexor port number (-1 for no multiplexor) + * @daisy: daisy chain address (-1 for no daisy chain address) + * + * This tries to locate a device on the given parallel port, + * multiplexor port and daisy chain address, and returns its + * device number or -NXIO if no device with those coordinates + * exists. + **/ + int parport_device_num (int parport, int mux, int daisy) { struct daisydev *dev = topology; @@ -240,7 +278,32 @@ return dev->devnum; } -/* Convert a canonical device number into device coordinates. */ +/** + * parport_device_coords - convert a canonical device number into + * device coordinates + * @devnum: device number + * @parport: pointer to storage for parallel port number + * @mux: pointer to storage for multiplexor port number + * @daisy: pointer to storage for daisy chain address + * + * This function converts a device number into its coordinates in + * terms of which parallel port in the system it is attached to, + * which multiplexor port it is attached to if there is a + * multiplexor on that port, and which daisy chain address it has + * if it is in a daisy chain. + * + * The caller must allocate storage for @parport, @mux, and + * @daisy. + * + * If there is no device with the specified device number, -ENXIO + * is returned. Otherwise, the values pointed to by @parport, + * @mux, and @daisy are set to the coordinates of the device, + * with -1 for coordinates with no value. + * + * This function is not actually very useful, but this interface + * was suggested by IEEE 1284.3. + **/ + int parport_device_coords (int devnum, int *parport, int *mux, int *daisy) { struct daisydev *dev = topology; @@ -437,6 +500,28 @@ /* Find a device with a particular manufacturer and model string, starting from a given device number. Like the PCI equivalent, 'from' itself is skipped. */ + +/** + * parport_find_device - find a device with a specified + * manufacturer and model string + * @mfg: required manufacturer string + * @mdl: required model string + * @from: previous device number found in search, or %NULL for + * new search + * + * This walks through the list of parallel port devices looking + * for a device whose 'MFG' string matches @mfg and whose 'MDL' + * string matches @mdl in their IEEE 1284 Device ID. + * + * When a device is found matching those requirements, its device + * number is returned; if there is no matching device, a negative + * value is returned. + * + * A new search it initiated by passing %NULL as the @from + * argument. If @from is not %NULL, the search continues from + * that device. + **/ + int parport_find_device (const char *mfg, const char *mdl, int from) { struct daisydev *d = topology; /* sorted by devnum */ @@ -462,8 +547,25 @@ return -1; } -/* Find a device in a particular class. Like the PCI equivalent, - 'from' itself is skipped. */ +/** + * parport_find_class - find a device in a specified class + * @cls: required class + * @from: previous device number found in search, or %NULL for + * new search + * + * This walks through the list of parallel port devices looking + * for a device whose 'CLS' string matches @cls in their IEEE + * 1284 Device ID. + * + * When a device is found matching those requirements, its device + * number is returned; if there is no matching device, a negative + * value is returned. + * + * A new search it initiated by passing %NULL as the @from + * argument. If @from is not %NULL, the search continues from + * that device. + **/ + int parport_find_class (parport_device_class cls, int from) { struct daisydev *d = topology; /* sorted by devnum */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c --- v2.3.99-pre5/linux/drivers/parport/ieee1284.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/parport/ieee1284.c Wed Apr 12 09:47:26 2000 @@ -42,11 +42,22 @@ parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]); } -/* Wait for a parport_ieee1284_wakeup. - * 0: success - * <0: error (exit as soon as possible) - * >0: timed out +/** + * parport_wait_event - wait for an event on a parallel port + * @port: port to wait on + * @timeout: time to wait (in jiffies) + * + * This function waits for up to @timeout jiffies for an + * interrupt to occur on a parallel port. If the port timeout is + * set to zero, it returns immediately. + * + * If an interrupt occurs before the timeout period elapses, this + * function returns one immediately. If it times out, it returns + * a value greater than zero. An error code less than zero + * indicates an error (most likely a pending signal), and the + * calling code should finish what it's doing as soon as it can. */ + int parport_wait_event (struct parport *port, signed long timeout) { int ret; @@ -72,13 +83,29 @@ return ret; } -/* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to - * 25 for this. After this time we can create a timeout because the - * peripheral doesn't conform to IEEE1284. We want to save CPU time: we are - * waiting a maximum time of 500 us busy (this is for speed). If there is - * not the right answer in this time, we call schedule and other processes - * are able to eat the time up to 40ms. - */ +/** + * parport_poll_peripheral - poll status lines + * @port: port to watch + * @mask: status lines to watch + * @result: desired values of chosen status lines + * @usec: timeout + * + * This function busy-waits until the masked status lines have + * the desired values, or until the timeout period elapses. The + * @mask and @result parameters are bitmasks, with the bits + * defined by the constants in parport.h: %PARPORT_STATUS_BUSY, + * and so on. + * + * This function does not call schedule(); instead it busy-waits + * using udelay(). It currently has a resolution of 5usec. + * + * If the status lines take on the desired values before the + * timeout period elapses, parport_poll_peripheral() returns zero + * immediately. A zero return value greater than zero indicates + * a timeout. An error code (less than zero) indicates an error, + * most likely a signal that arrived, and the caller should + * finish what it is doing as soon as possible. +*/ int parport_poll_peripheral(struct parport *port, unsigned char mask, @@ -102,6 +129,31 @@ return 1; } +/** + * parport_wait_peripheral - wait for status lines to change in 35ms + * @port: port to watch + * @mask: status lines to watch + * @result: desired values of chosen status lines + * + * This function waits until the masked status lines have the + * desired values, or until 35ms have elapsed (see IEEE 1284-1994 + * page 24 to 25 for why this value in particular is hardcoded). + * The @mask and @result parameters are bitmasks, with the bits + * defined by the constants in parport.h: %PARPORT_STATUS_BUSY, + * and so on. + * + * The port is polled quickly to start off with, in anticipation + * of a fast response from the peripheral. This fast polling + * time is configurable (using /proc), and defaults to 500usec. + * If the timeout for this port (see parport_set_timeout()) is + * zero, the fast polling time is 35ms, and this function does + * not call schedule(). + * + * If the timeout for this port is non-zero, after the fast + * polling fails it uses parport_wait_event() to wait for up to + * 10ms, waking up if an interrupt occurs. + */ + int parport_wait_peripheral(struct parport *port, unsigned char mask, unsigned char result) @@ -255,12 +307,21 @@ } #endif /* IEEE1284 support */ -/* Negotiate an IEEE 1284 mode. - * return values are: - * 0 - handshake OK; IEEE1284 peripheral and mode available - * -1 - handshake failed; peripheral is not compliant (or none present) - * 1 - handshake OK; IEEE1284 peripheral present but mode not available +/** + * parport_negotiate - negotiate an IEEE 1284 mode + * @port: port to use + * @mode: mode to negotiate to + * + * Use this to negotiate to a particular IEEE 1284 transfer mode. + * The @mode parameter should be one of the constants in + * parport.h starting %IEEE1284_MODE_xxx. + * + * The return value is 0 if the peripheral has accepted the + * negotiation to the mode specified, -1 if the peripheral is not + * IEEE 1284 compliant (or not present), or 1 if the peripheral + * has rejected the negotiation. */ + int parport_negotiate (struct parport *port, int mode) { #ifndef CONFIG_PARPORT_1284 @@ -513,7 +574,24 @@ #endif /* IEEE1284 support */ } -/* Write a block of data. */ +/** + * parport_write - write a block of data to a parallel port + * @port: port to write to + * @buffer: data buffer (in kernel space) + * @len: number of bytes of data to transfer + * + * This will write up to @len bytes of @buffer to the port + * specified, using the IEEE 1284 transfer mode most recently + * negotiated to (using parport_negotiate()), as long as that + * mode supports forward transfers (host to peripheral). + * + * It is the caller's responsibility to ensure that the first + * @len bytes of @buffer are valid. + * + * This function returns the number of bytes transferred (if zero + * or positive), or else an error code. + */ + ssize_t parport_write (struct parport *port, const void *buffer, size_t len) { #ifndef CONFIG_PARPORT_1284 @@ -578,7 +656,24 @@ #endif /* IEEE1284 support */ } -/* Read a block of data. */ +/** + * parport_read - read a block of data from a parallel port + * @port: port to read from + * @buffer: data buffer (in kernel space) + * @len: number of bytes of data to transfer + * + * This will read up to @len bytes of @buffer to the port + * specified, using the IEEE 1284 transfer mode most recently + * negotiated to (using parport_negotiate()), as long as that + * mode supports reverse transfers (peripheral to host). + * + * It is the caller's responsibility to ensure that the first + * @len bytes of @buffer are available to write to. + * + * This function returns the number of bytes transferred (if zero + * or positive), or else an error code. + */ + ssize_t parport_read (struct parport *port, void *buffer, size_t len) { #ifndef CONFIG_PARPORT_1284 @@ -637,7 +732,23 @@ #endif /* IEEE1284 support */ } -/* Set the amount of time we wait while nothing's happening. */ +/** + * parport_set_timeout - set the inactivity timeout for a device + * on a port + * @dev: device on a port + * @inactivity: inactivity timeout (in jiffies) + * + * This sets the inactivity timeout for a particular device on a + * port. This affects functions like parport_wait_peripheral(). + * The special value 0 means not to call schedule() while dealing + * with this device. + * + * The return value is the previous inactivity timeout. + * + * Any callers of parport_wait_event() for this device are woken + * up. + */ + long parport_set_timeout (struct pardevice *dev, long inactivity) { long int old = dev->timeout; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.3.99-pre5/linux/drivers/parport/parport_pc.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/parport/parport_pc.c Fri Apr 21 15:56:02 2000 @@ -427,6 +427,8 @@ size_t got; frob_econtrol (port, 0xe0, ECR_EPP << 5); + parport_pc_data_reverse (port); + parport_pc_write_control (port, 0x4); got = parport_pc_epp_read_data (port, buf, length, flags); frob_econtrol (port, 0xe0, ECR_PS2 << 5); @@ -440,6 +442,8 @@ size_t written; frob_econtrol (port, 0xe0, ECR_EPP << 5); + parport_pc_write_control (port, 0x4); + parport_pc_data_forward (port); written = parport_pc_epp_write_data (port, buf, length, flags); frob_econtrol (port, 0xe0, ECR_PS2 << 5); @@ -452,6 +456,8 @@ size_t got; frob_econtrol (port, 0xe0, ECR_EPP << 5); + parport_pc_data_reverse (port); + parport_pc_write_control (port, 0x4); got = parport_pc_epp_read_addr (port, buf, length, flags); frob_econtrol (port, 0xe0, ECR_PS2 << 5); @@ -465,6 +471,8 @@ size_t written; frob_econtrol (port, 0xe0, ECR_EPP << 5); + parport_pc_write_control (port, 0x4); + parport_pc_data_forward (port); written = parport_pc_epp_write_addr (port, buf, length, flags); frob_econtrol (port, 0xe0, ECR_PS2 << 5); @@ -582,7 +590,7 @@ if (end < MAX_DMA_ADDRESS) { /* If it would cross a 64k boundary, cap it at the end. */ if ((start ^ end) & ~0xffffUL) - maxlen = (0x10000 - start) & 0xffff; + maxlen = 0x10000 - (start & 0xffff); dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length, PCI_DMA_TODEVICE); @@ -1733,7 +1741,7 @@ oecr = inb (ECONTROL (pb)); /* Search for SMC style EPP+ECP mode */ outb (0x80, ECONTROL (pb)); - + outb (0x04, CONTROL (pb)); result = parport_EPP_supported(pb); outb (oecr, ECONTROL (pb)); @@ -2254,6 +2262,7 @@ boca_ioppar, plx_9050, afavlab_tk9902, + timedia_1889, }; @@ -2291,6 +2300,7 @@ /* boca_ioppar */ { 1, { { 0, -1 }, } }, /* plx_9050 */ { 2, { { 4, -1 }, { 5, -1 }, } }, /* afavlab_tk9902 */ { 1, { { 0, 1 }, } }, + /* timedia_1889 */ { 1, { { 2, -1 }, } }, }; static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = { @@ -2348,6 +2358,8 @@ PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0,0, plx_9050 }, { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902, PCI_ANY_ID, PCI_ANY_ID, 0, 0, afavlab_tk9902 }, + { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, timedia_1889 }, { 0, }, /* terminate list */ }; MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/parport/share.c linux/drivers/parport/share.c --- v2.3.99-pre5/linux/drivers/parport/share.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/parport/share.c Thu Apr 13 09:25:44 2000 @@ -104,18 +104,19 @@ } /** - * parport_register_driver - register a parallel port device driver - * @drv: structure describing the driver + * parport_register_driver - register a parallel port device driver + * @drv: structure describing the driver * - * This can be called by a parallel port device driver in order to - * receive notifications about ports being found in the system, as - * well as ports no longer available. + * This can be called by a parallel port device driver in order + * to receive notifications about ports being found in the + * system, as well as ports no longer available. * - * The @drv structure is allocated by the caller and must not be - * deallocated until after calling parport_unregister_driver(). + * The @drv structure is allocated by the caller and must not be + * deallocated until after calling parport_unregister_driver(). * - * Returns 0 on success. Currently it always succeeds. + * Returns 0 on success. Currently it always succeeds. **/ + int parport_register_driver (struct parport_driver *drv) { struct parport *port; @@ -135,22 +136,23 @@ } /** - * parport_unregister_driver - deregister a parallel port device driver - * @arg: structure describing the driver that was given to - * parport_register_driver() - * - * This should be called by a parallel port device driver that has - * registered itself using parport_register_driver() when it is about - * to be unloaded. - * - * When it returns, the driver's attach() routine will no longer be - * called, and for each port that attach() was called for, the - * detach() routine will hae been called. - * - * If the caller's attach() function can block, it is their - * responsibility to make sure to wait for it to exit before - * unloading. + * parport_unregister_driver - deregister a parallel port device driver + * @arg: structure describing the driver that was given to + * parport_register_driver() + * + * This should be called by a parallel port device driver that + * has registered itself using parport_register_driver() when it + * is about to be unloaded. + * + * When it returns, the driver's attach() routine will no longer + * be called, and for each port that attach() was called for, the + * detach() routine will have been called. + * + * If the caller's attach() function can block, it is their + * responsibility to make sure to wait for it to exit before + * unloading. **/ + void parport_unregister_driver (struct parport_driver *arg) { struct parport_driver *drv = driver_chain, *olddrv = NULL; @@ -180,16 +182,17 @@ } /** - * parport_enumerate - return a list of the system's parallel ports + * parport_enumerate - return a list of the system's parallel ports * - * This returns the head of the list of parallel ports in the system. - * The structure that is returned describes the first port in the - * list, and its 'next' member points to the next port, or %NULL if - * it's the last port. + * This returns the head of the list of parallel ports in the + * system, as a &struct parport. The structure that is returned + * describes the first port in the list, and its 'next' member + * points to the next port, or %NULL if it's the last port. * - * If there are no parallel ports in the system, parport_enumerate() - * will return %NULL. + * If there are no parallel ports in the system, + * parport_enumerate() will return %NULL. **/ + struct parport *parport_enumerate(void) { if (!portlist) @@ -199,32 +202,34 @@ } /** - * parport_register_port - register a parallel port - * @base: base I/O address - * @irq: IRQ line - * @dma: DMA channel - * @ops: pointer to the port driver's port operations structure - * - * When a parallel port (lowlevel) driver finds a port that should be - * made available to parallel port device drivers, it should call - * parport_register_port(). The @base, @irq, and @dma parameters are - * for the convenience of port drivers, and for ports where they - * aren't meaningful needn't be set to anything special. They can be - * altered afterwards by adjusting the relevant members of the parport - * structure that is returned and represents the port. They should - * not be tampered with after calling parport_announce_port, however. - * - * If there are parallel port device drivers in the system that have - * registered themselves using parport_register_driver(), they are not - * told about the port at this time; that is done by - * parport_announce_port(). + * parport_register_port - register a parallel port + * @base: base I/O address + * @irq: IRQ line + * @dma: DMA channel + * @ops: pointer to the port driver's port operations structure + * + * When a parallel port (lowlevel) driver finds a port that + * should be made available to parallel port device drivers, it + * should call parport_register_port(). The @base, @irq, and + * @dma parameters are for the convenience of port drivers, and + * for ports where they aren't meaningful needn't be set to + * anything special. They can be altered afterwards by adjusting + * the relevant members of the parport structure that is returned + * and represents the port. They should not be tampered with + * after calling parport_announce_port, however. + * + * If there are parallel port device drivers in the system that + * have registered themselves using parport_register_driver(), + * they are not told about the port at this time; that is done by + * parport_announce_port(). * - * The @ops structure is allocated by the caller, and must not be - * deallocated before calling parport_unregister_port(). + * The @ops structure is allocated by the caller, and must not be + * deallocated before calling parport_unregister_port(). * - * If there is no memory to allocate a new parport structure, this - * function will return %NULL. + * If there is no memory to allocate a new parport structure, + * this function will return %NULL. **/ + struct parport *parport_register_port(unsigned long base, int irq, int dma, struct parport_operations *ops) { @@ -310,16 +315,17 @@ } /** - * parport_announce_port - tell device drivers about a parallel port - * @port: parallel port to announce + * parport_announce_port - tell device drivers about a parallel port + * @port: parallel port to announce * - * After a port driver has registered a parallel port with - * parport_register_port, and performed any necessary initialisation - * or adjustments, it should call parport_announce_port() in order to - * notify all device drivers that have called - * parport_register_driver(). Their attach() functions will be - * called, with @port as the parameter. + * After a port driver has registered a parallel port with + * parport_register_port, and performed any necessary + * initialisation or adjustments, it should call + * parport_announce_port() in order to notify all device drivers + * that have called parport_register_driver(). Their attach() + * functions will be called, with @port as the parameter. **/ + void parport_announce_port (struct parport *port) { #ifdef CONFIG_PARPORT_1284 @@ -364,22 +370,24 @@ } /** - * parport_unregister_port - deregister a parallel port - * @port: parallel port to deregister + * parport_unregister_port - deregister a parallel port + * @port: parallel port to deregister * - * When a parallel port driver is forcibly unloaded, or a parallel - * port becomes inaccessible, the port driver must call this function - * in order to deal with device drivers that still want to use it. - * - * The parport structure associated with the port has its operations - * structure replaced with one containing 'null' operations that - * return errors or just don't do anything. - * - * Any drivers that have registered themselves using - * parport_register_driver() are notified that the port is no longer - * accessible by having their detach() routines called with @port as - * the parameter. + * When a parallel port driver is forcibly unloaded, or a + * parallel port becomes inaccessible, the port driver must call + * this function in order to deal with device drivers that still + * want to use it. + * + * The parport structure associated with the port has its + * operations structure replaced with one containing 'null' + * operations that return errors or just don't do anything. + * + * Any drivers that have registered themselves using + * parport_register_driver() are notified that the port is no + * longer accessible by having their detach() routines called + * with @port as the parameter. **/ + void parport_unregister_port(struct parport *port) { struct parport *p; @@ -415,70 +423,74 @@ } /** - * parport_register_device - register a device on a parallel port - * @port: port to which the device is attached - * @name: a name to refer to the device - * @pf: preemption callback - * @kf: kick callback (wake-up) - * @irq_func: interrupt handler - * @flags: registration flags - * @handle: data for callback functions - * - * This function, called by parallel port device drivers, declares - * that a device is connected to a port, and tells the system all it - * needs to know. - * - * The @name is allocated by the caller and must not be deallocated - * until the caller calls @parport_unregister_device for that device. - * - * The preemption callback function, @pf, is called when this device - * driver has claimed access to the port but another device driver - * wants to use it. It is given @handle as its parameter, and should - * return zero if it is willing for the system to release the port to - * another driver on its behalf. If it wants to keep control of the - * port it should return non-zero, and no action will be taken. It is - * good manners for the driver to try to release the port at the - * earliest opportunity after its preemption callback rejects a - * preemption attempt. Note that if a preemption callback is happy - * for preemption to go ahead, there is no need to release the port; - * it is done automatically. This function may not block, as it may - * be called from interrupt context. If the device driver does not - * support preemption, @pf can be %NULL. - * - * The wake-up ("kick") callback function, @kf, is called when the - * port is available to be claimed for exclusive access; that is, - * parport_claim() is guaranteed to succeed when called from inside - * the wake-up callback function. If the driver wants to claim the - * port it should do so; otherwise, it need not take any action. This - * function may not block, as it may be called from interrupt context. - * If the device driver does not want to be explicitly invited to - * claim the port in this way, @kf can be %NULL. - * - * The interrupt handler, @irq_func, is called when an interrupt - * arrives from the parallel port. Note that if a device driver wants - * to use interrupts it should use parport_enable_irq(), and can also - * check the irq member of the parport structure representing the - * port. - * - * The parallel port (lowlevel) driver is the one that has called - * request_irq() and whose interrupt handler is called first. This - * handler does whatever needs to be done to the hardware to - * acknowledge the interrupt (for PC-style ports there is nothing - * special to be done). It then tells the IEEE 1284 code about the - * interrupt, which may involve reacting to an IEEE 1284 event - * depending on the current IEEE 1284 phase. After this, it calls - * @irq_func. Needless to say, @irq_func will be called from - * interrupt context, and may not block. - * - * The %PARPORT_DEV_EXCL flag is for preventing port sharing, and so - * should only be used when sharing the port with other device drivers - * is impossible and would lead to incorrect behaviour. Use it - * sparingly! Normally, @flags will be zero. - * - * This function returns a pointer to a structure that represents the - * device on the port, or %NULL if there is not enough memory to - * allocate space for that structure. + * parport_register_device - register a device on a parallel port + * @port: port to which the device is attached + * @name: a name to refer to the device + * @pf: preemption callback + * @kf: kick callback (wake-up) + * @irq_func: interrupt handler + * @flags: registration flags + * @handle: data for callback functions + * + * This function, called by parallel port device drivers, + * declares that a device is connected to a port, and tells the + * system all it needs to know. + * + * The @name is allocated by the caller and must not be + * deallocated until the caller calls @parport_unregister_device + * for that device. + * + * The preemption callback function, @pf, is called when this + * device driver has claimed access to the port but another + * device driver wants to use it. It is given @handle as its + * parameter, and should return zero if it is willing for the + * system to release the port to another driver on its behalf. + * If it wants to keep control of the port it should return + * non-zero, and no action will be taken. It is good manners for + * the driver to try to release the port at the earliest + * opportunity after its preemption callback rejects a preemption + * attempt. Note that if a preemption callback is happy for + * preemption to go ahead, there is no need to release the port; + * it is done automatically. This function may not block, as it + * may be called from interrupt context. If the device driver + * does not support preemption, @pf can be %NULL. + * + * The wake-up ("kick") callback function, @kf, is called when + * the port is available to be claimed for exclusive access; that + * is, parport_claim() is guaranteed to succeed when called from + * inside the wake-up callback function. If the driver wants to + * claim the port it should do so; otherwise, it need not take + * any action. This function may not block, as it may be called + * from interrupt context. If the device driver does not want to + * be explicitly invited to claim the port in this way, @kf can + * be %NULL. + * + * The interrupt handler, @irq_func, is called when an interrupt + * arrives from the parallel port. Note that if a device driver + * wants to use interrupts it should use parport_enable_irq(), + * and can also check the irq member of the parport structure + * representing the port. + * + * The parallel port (lowlevel) driver is the one that has called + * request_irq() and whose interrupt handler is called first. + * This handler does whatever needs to be done to the hardware to + * acknowledge the interrupt (for PC-style ports there is nothing + * special to be done). It then tells the IEEE 1284 code about + * the interrupt, which may involve reacting to an IEEE 1284 + * event depending on the current IEEE 1284 phase. After this, + * it calls @irq_func. Needless to say, @irq_func will be called + * from interrupt context, and may not block. + * + * The %PARPORT_DEV_EXCL flag is for preventing port sharing, and + * so should only be used when sharing the port with other device + * drivers is impossible and would lead to incorrect behaviour. + * Use it sparingly! Normally, @flags will be zero. + * + * This function returns a pointer to a structure that represents + * the device on the port, or %NULL if there is not enough memory + * to allocate space for that structure. **/ + struct pardevice * parport_register_device(struct parport *port, const char *name, int (*pf)(void *), void (*kf)(void *), @@ -581,11 +593,12 @@ } /** - * parport_unregister_device - deregister a device on a parallel port - * @dev: pointer to structure representing device + * parport_unregister_device - deregister a device on a parallel port + * @dev: pointer to structure representing device * - * This undoes the effect of parport_register_device(). + * This undoes the effect of parport_register_device(). **/ + void parport_unregister_device(struct pardevice *dev) { struct parport *port; @@ -633,15 +646,17 @@ } /** - * parport_claim - claim access to a parallel port device - * @dev: pointer to structure representing a device on the port + * parport_claim - claim access to a parallel port device + * @dev: pointer to structure representing a device on the port * - * This function will not block and so can be used from interrupt - * context. If parport_claim() succeeds in claiming access to the - * port it returns zero and the port is available to use. It may fail - * (returning non-zero) if the port is in use by another driver and - * that driver is not willing to relinquish control of the port. + * This function will not block and so can be used from interrupt + * context. If parport_claim() succeeds in claiming access to + * the port it returns zero and the port is available to use. It + * may fail (returning non-zero) if the port is in use by another + * driver and that driver is not willing to relinquish control of + * the port. **/ + int parport_claim(struct pardevice *dev) { struct pardevice *oldcad; @@ -744,14 +759,15 @@ } /** - * parport_claim_or_block - claim access to a parallel port device - * @dev: pointer to structure representing a device on the port + * parport_claim_or_block - claim access to a parallel port device + * @dev: pointer to structure representing a device on the port * - * This behaves like parport_claim(), but will block if necessary to - * wait for the port to be free. A return value of 1 indicates that - * it slept; 0 means that it succeeded without needing to sleep. A - * negative error code indicates failure. + * This behaves like parport_claim(), but will block if necessary + * to wait for the port to be free. A return value of 1 + * indicates that it slept; 0 means that it succeeded without + * needing to sleep. A negative error code indicates failure. **/ + int parport_claim_or_block(struct pardevice *dev) { int r; @@ -795,13 +811,14 @@ } /** - * parport_release - give up access to a parallel port device - * @dev: pointer to structure representing parallel port device + * parport_release - give up access to a parallel port device + * @dev: pointer to structure representing parallel port device * - * This function cannot fail, but it should not be called without the - * port claimed. Similarly, if the port is already claimed you should - * not try claiming it again. + * This function cannot fail, but it should not be called without + * the port claimed. Similarly, if the port is already claimed + * you should not try claiming it again. **/ + void parport_release(struct pardevice *dev) { struct parport *port = dev->port->physport; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.3.99-pre5/linux/drivers/pci/pci.c Wed Apr 12 10:02:34 2000 +++ linux/drivers/pci/pci.c Wed Apr 12 09:16:31 2000 @@ -1068,6 +1068,7 @@ EXPORT_SYMBOL(pci_assign_resource); EXPORT_SYMBOL(pci_register_driver); EXPORT_SYMBOL(pci_unregister_driver); +EXPORT_SYMBOL(pci_dev_driver); EXPORT_SYMBOL(pci_match_device); EXPORT_SYMBOL(pci_find_parent_resource); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids --- v2.3.99-pre5/linux/drivers/pci/pci.ids Tue Apr 11 15:09:18 2000 +++ linux/drivers/pci/pci.ids Mon Apr 24 15:17:07 2000 @@ -4,7 +4,7 @@ # Maintained by Martin Mares # If you have any new entries, send them to the maintainer. # -# $Id: pci.ids,v 1.53 2000/03/09 08:19:20 mj Exp $ +# $Id: pci.ids,v 1.56 2000/04/17 16:11:58 mj Exp $ # # Vendors, devices and subsystems. Please keep sorted. @@ -18,7 +18,8 @@ 001a Ascend Communications, Inc. 0033 Paradyne corp. 003d Lockheed Martin-Marietta Corp -0070 Hauppage computer works Inc. +0070 Hauppauge computer works Inc. +0100 Ncipher Corp Ltd 0675 Dynalink 1700 IS64PH ISDN Adapter 1702 IS64PH ISDN Adapter @@ -34,7 +35,12 @@ 3034 QVision 1280/p 4000 4000 [Triflex] 6010 HotPlug PCI Bridge 6010 + 7020 USB Controller + a0ec Fibre Channel Host Controller + a0f0 Advanced System Management Controller a0f3 Triflex PCI to ISA Bridge + a0f7 PCI Hotplug Controller + a0f8 USB Open Host Controller ae10 Smart-2/P RAID Controller 0e11 4030 Smart-2/P Array Controller 0e11 4031 Smart-2SL Array Controller @@ -43,13 +49,16 @@ ae29 MIS-L ae2a MPC ae2b MIS-E + ae31 System Management Controller ae32 Netelligent 10/100 + ae33 Triflex Dual EIDE Controller ae34 Netelligent 10 ae35 Integrated NetFlex-3/P ae40 Netelligent 10/100 Dual ae43 ProLiant Integrated Netelligent 10/100 ae69 CETUS-L ae6c Northstar + ae6d NorthStar CPU to PCI Bridge b011 Integrated Netelligent 10/100 b012 Netelligent 10 T/2 b030 Netelligent WS 5100 @@ -66,6 +75,7 @@ 0004 53c815 0005 53c810AP 0006 53c860 + 000a 53c1510 000b 53c896 000c 53c895 000d 53c885 @@ -74,6 +84,7 @@ 1092 8760 FirePort 40 Dual SCSI Controller 1de1 3904 DC390F Ultra Wide SCSI Controller 0012 53c895a + 0020 53c1010 Ultra3 SCSI Adapter 008f 53c875J 1092 8000 FirePort 40 SCSI Controller 1092 8760 FirePort 40 Dual SCSI Host Adapter @@ -83,13 +94,24 @@ 0901 61C102 1000 63C815 1001 Initio + 0010 PCI 1616 Measurement card with 32 digital I/O lines + 0011 OPTO-PCI Opto-Isolated digital I/O board + 0012 PCI-AD/DA Analogue I/O board + 0013 PCI-OPTO-RELAIS Digital I/O board with relay outputs + 0014 PCI-Counter/Timer Counter Timer board + 0015 PCI-DAC416 Analogue output board + 0016 PCI-MFB Analogue I/O board + 0017 PROTO-3 PCI Prototyping board 9100 INI-9100/9100W SCSI Host 1002 ATI Technologies Inc 4158 68800AX [Mach32] 4354 215CT [Mach64 CT] 4358 210888CX [Mach64 CX] 4554 210888ET [Mach64 ET] + 4654 Mach64 VT 4742 3D Rage Pro AGP 1X/2X + 1028 4082 Optiplex GX1 Onboard Display Adapter + 8086 4152 Rage 3D Pro AGP 4744 3D Rage Pro AGP 1X 4747 3D Rage Pro 4749 3D Rage Pro @@ -99,17 +121,26 @@ 474f Rage XL 4750 3D Rage Pro 215GP 4751 3D Rage Pro 215GQ + 4752 Rage XL 4753 Rage XC 4754 3D Rage I/II 215GT [Mach64 GT] 4755 3D Rage II+ 215GTB [Mach64 GTB] 4756 3D Rage IIC 215IIC [Mach64 GT IIC] 4757 3D Rage IIC AGP + 1028 0089 Rage 3D IIC + 1028 4082 Rage 3D IIC + 1028 8082 Rage 3D IIC + 1028 c082 Rage 3D IIC 4758 210888GX [Mach64 GX] 4759 3D Rage IIC 475a 3D Rage IIC AGP + 1002 0087 Rage 3D IIC 4c42 3D Rage LT Pro AGP-133 + 0e11 b0e8 Rage 3D LT Pro 0e11 b10e 3D Rage LT Pro (Compaq Armada 1750) + 1028 0085 Rage 3D LT Pro 4c44 3D Rage LT Pro AGP-66 + 4c46 Mobility M3 AGP 2x 4c47 3D Rage LT-G 215LG 4c49 3D Rage LT Pro 4c4d 3D Rage P/M Mobility AGP 2x @@ -125,15 +156,17 @@ 5044 Rage 128 PD 5045 Rage 128 PE 5046 Rage 128 PF + 1002 2000 Rage Fury MAXX AGP 4x (TMDS) (VGA device) + 1002 2001 Rage Fury MAXX AGP 4x (TMDS) (Extra device?!) 5047 Rage 128 PG 5048 Rage 128 PH 5049 Rage 128 PI - 504A Rage 128 PJ - 504B Rage 128 PK - 504C Rage 128 PL - 504D Rage 128 PM - 504E Rage 128 PN - 504F Rage 128 PO + 504a Rage 128 PJ + 504b Rage 128 PK + 504c Rage 128 PL + 504d Rage 128 PM + 504e Rage 128 PN + 504f Rage 128 PO 5050 Rage 128 PP 5051 Rage 128 PQ 5052 Rage 128 PR @@ -150,12 +183,15 @@ 5345 Rage 128 SE 5346 Rage 128 SF 5347 Rage 128 SG - 534B Rage 128 SK - 534C Rage 128 SL - 534D Rage 128 SM + 5348 Rage 128 4x + 534b Rage 128 SK + 534c Rage 128 SL + 534d Rage 128 SM + 534e Rage 128 4x 5354 Mach 64 VT 1002 5654 Mach 64 reference 5654 264VT [Mach64 VT] + 1002 5654 Mach64VT Reference 5655 264VT3 [Mach64 VT3] 5656 264VT4 [Mach64 VT4] 1003 ULSI Systems @@ -175,6 +211,18 @@ 0105 82C147 0200 82C975 0280 82C925 + 0304 QSound ThunderBird PCI Audio + 1004 0304 QSound ThunderBird PCI Audio + 122d 1206 DSP368 Audio + 1483 5020 XWave Thunder 3D Audio + 0305 QSound ThunderBird PCI Audio Gameport + 1004 0305 QSound ThunderBird PCI Audio Gameport + 122d 1207 DSP368 Audio Gameport + 1483 5021 XWave Thunder 3D Audio Gameport + 0306 QSound ThunderBird PCI Audio Support Registers + 1004 0306 QSound ThunderBird PCI Audio Support Registers + 122d 1208 DSP368 Audio Support Registers + 1483 5022 XWave Thunder 3D Audio Support Registers 0702 VAS96011 [Golden Gate II] 1005 Avance Logic Inc. [ALI] 2064 ALG2032/2064 @@ -191,6 +239,9 @@ 100b National Semiconductor Corporation 0001 DP83810 0002 87415 + 000f OHCI Compliant FireWire Controller + 0011 National PCI System I/O + 0012 USB Controller d001 87410 100c Tseng Labs Inc 3202 ET4000/W32p rev A @@ -215,14 +266,15 @@ 10b8 2001 SMC9332BDT EtherPower 10/100 10b8 2002 SMC9332BVT EtherPower T4 10/100 10b8 2003 SMC9334BDT EtherPower 10/100 (1-port) + 1109 2400 ANA-6944A/TX Fast Ethernet 1112 2300 RNS2300 Fast Ethernet 1112 2320 RNS2320 Fast Ethernet 1112 2340 RNS2340 Fast Ethernet 1113 1207 EN-1207-TX Fast Ethernet - 1109 2400 ANA-6944A/TX Fast Ethernet 1186 1100 DFE-500TX Fast Ethernet 1186 1112 DFE-570TX Fast Ethernet 1282 9100 AEF-380TXD Fast Ethernet + 1385 1100 FA310TX Fast Ethernet 2646 0001 KNE100TX Fast Ethernet 000a 21230 Video Codec 000d PBXGB [TGA2] @@ -245,14 +297,17 @@ 115d 0002 Cardbus Ethernet 10/100 1179 0203 Fast Ethernet 1179 0204 Cardbus Fast Ethernet + 1186 1100 DFE-500TX Fast Ethernet 1186 1101 DFE-500TX Fast Ethernet 1186 1102 DFE-500TX Fast Ethernet 1266 0004 Eagle Fast EtherMAX 12af 0019 NetFlyer Cardbus Fast Ethernet + 1374 0001 Cardbus Ethernet Card 10/100 1395 0001 10/100 Ethernet CardBus PC Card 8086 0001 EtherExpress PRO/100 Mobile CardBus 32 0021 DECchip 21052 0022 DECchip 21150 + 0023 DECchip 21150 0024 DECchip 21152 0025 DECchip 21153 0026 DECchip 21154 @@ -260,6 +315,7 @@ 0046 DECchip 21554 9005 1364 Dell PowerEdge RAID Controller 2 9005 1365 Dell PowerEdge RAID Controller 2 + 1065 RAID Controller 1012 Micronics Computers Inc 1013 Cirrus Logic 0038 GD 7548 @@ -273,6 +329,7 @@ 00b0 GD 5440 00b8 GD 5446 00bc GD 5480 + 1013 00bc CL-GD5480 00d0 GD 5462 00d2 GD 5462 [Laguna I] 00d4 GD 5464 [Laguna] @@ -287,12 +344,26 @@ 1204 GD 7541 [Nordic Light] 4400 CD 4400 6001 CS 4610/11 [CrystalClear SoundFusion Audio Accelerator] + 1014 1010 CS4610 SoundFusion Audio Accelerator 6003 CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator] + 1013 4280 Crystal SoundFusion PCI Audio Accelerator + 6005 Crystal CS4281 PCI Audio + 1013 4281 Crystal CS4281 PCI Audio + 10cf 10a8 Crystal CS4281 PCI Audio + 10cf 10a9 Crystal CS4281 PCI Audio + 10cf 10aa Crystal CS4281 PCI Audio + 10cf 10ab Crystal CS4281 PCI Audio + 10cf 10ac Crystal CS4281 PCI Audio + 10cf 10ad Crystal CS4281 PCI Audio + 10cf 10b4 Crystal CS4281 PCI Audio + 1179 0001 Crystal CS4281 PCI Audio + 14c0 000c Crystal CS4281 PCI Audio 1014 IBM 0002 PCI to MCA Bridge 0005 Alta Lite 0007 Alta MP 000a Fire Coral + 0017 CPU to PCI Bridge 0018 TR Auto LANstreamer 001b GXT-150P 001d 82G2675 @@ -302,19 +373,22 @@ 002e ServeRAID controller 0036 Miami 003e 16/4 Token ring UTP/STP controller - 1014 003E Token-Ring Adapter - 1014 00CD Token-Ring Adapter + Wake-On-LAN - 1014 00CE 16/4 Token-Ring Adapter 2 - 1014 00CF 16/4 Token-Ring Adapter Special - 1014 00E4 High-Speed 100/16/4 Token-Ring Adapter - 1014 00E5 16/4 Token-Ring Adapter 2 + Wake-On-LAN + 1014 003e Token-Ring Adapter + 1014 00cd Token-Ring Adapter + Wake-On-LAN + 1014 00ce 16/4 Token-Ring Adapter 2 + 1014 00cf 16/4 Token-Ring Adapter Special + 1014 00e4 High-Speed 100/16/4 Token-Ring Adapter + 1014 00e5 16/4 Token-Ring Adapter 2 + Wake-On-LAN 0046 MPIC interrupt controller + 0047 PCI to PCI Bridge + 0048 PCI to PCI Bridge 0053 25 MBit ATM Controller 0057 MPEG PCI Bridge - 005C i82557B 10/100 + 005c i82557B 10/100 007d 3780IDSP [MWave] 0095 20H2999 PCI Docking Bridge 00b7 256-bit Graphics Rasterizer [Fire GL1] + 1902 00b8 Fire GL1 ffff MPIC-2 interrupt controller 1015 LSI Logic Corp of Canada 1016 ICL Personal Systems @@ -339,6 +413,11 @@ c24a 90C 101e American Megatrends Inc. 9010 MegaRAID + 9030 EIDE Controller + 9031 EIDE Controller + 9032 EIDE & SCSI Controller + 9033 SCSI Controller + 9040 Multimedia card 9060 MegaRAID 101f PictureTel 1020 Hitachi Computer Products @@ -373,9 +452,16 @@ 2000 4DWave DX 2001 4DWave NX 8400 CyberBlade/i7 + 1023 8400 CyberBlade i7 AGP 8420 CyberBlade/i7d + 0e11 b15a CyberBlade i7 AGP 8500 CyberBlade/i1 + 8520 CyberBlade i1 + 0e11 b16e CyberBlade i1 AGP + 1023 8520 CyberBlade i1 AGP 9320 TGUI 9320 + 9350 GUI Accelerator + 9360 Flat panel GUI Accelerator 9382 Cyber 9382 [Reference design] 9383 Cyber 9383 [Reference design] 9385 Cyber 9385 [Reference design] @@ -390,12 +476,15 @@ 9470 TGUI 9470 9520 Cyber 9520 9525 Cyber 9525 + 9540 Cyber 9540 9660 TGUI 9660/968x/968x 9680 TGUI 9680 9682 TGUI 9682 9683 TGUI 9683 9685 ProVIDIA 9685 9750 3DIm`age 975 + 1014 9750 3DImage 9750 + 1023 9750 3DImage 9750 9753 TGUI 9753 9754 TGUI 9754 9759 TGUI 975 @@ -403,6 +492,7 @@ 9785 TGUI 9785 9850 3DImage 9850 9880 Blade 3D PCI/AGP + 1023 9880 Blade 3D 1024 Zenith Data Systems 1025 Acer Incorporated [ALI] 1435 M1435 @@ -412,11 +502,18 @@ 1461 M1461 1489 M1489 1511 M1511 + 1512 ALI M1512 Aladdin 1513 M1513 + 1521 ALI M1521 Aladdin III CPU Bridge + 10b9 1521 ALI M1521 Aladdin III CPU Bridge + 1523 ALI M1523 ISA Bridge + 10b9 1523 ALI M1523 ISA Bridge 1531 M1531 Northbridge [Aladdin IV/IV+] 1533 M1533 PCI-to-ISA Bridge + 10b9 1533 ALI M1533 Aladdin IV/V ISA South Bridge 1535 M1535 PCI Bridge + Super I/O + FIR 1541 M1541 Northbridge [Aladdin V] + 10b9 1541 ALI M1541 Aladdin V/V+ AGP+PCI North Bridge 1542 M1542 Northbridge [Aladdin V] 1543 M1543 PCI-to-ISA Bridge + Super I/O + FIR 1561 M1561 Northbridge [Aladdin 7] @@ -432,12 +529,26 @@ 3307 M3307 MPEG-I Video Controller 3309 M3309 MPEG-II Video w/ Software Audio Decoder 3321 M3321 MPEG-II Audio/Video Decoder + 5212 ALI M4803 + 5215 ALI PCI EIDE Controller 5217 M5217H 5219 M5219 5225 M5225 5229 M5229 5235 M5235 + 5237 ALI M5237 PCI USB Host Controller + 5240 EIDE Controller + 5241 PCMCIA Bridge + 5242 General Purpose Controller + 5243 PCI to PCI Bridge Controller + 5244 Floppy Disk Controller + 5247 ALI M1541 PCI to PCI Bridge 5251 M5251 P1394 OHCI Controller + 5427 ALI PCI to AGP Bridge + 5451 ALI M5451 PCI AC-Link Controller Audio Device + 5453 ALI M5453 PCI AC-Link Controller Modem Device + 7101 ALI M7101 PCI PMU Power Management Controller + 10b9 7101 ALI M7101 PCI PMU Power Management Controller 1028 Dell Computer Corporation 0001 PowerEdge Expandable RAID Controller 2/Si 0002 PowerEdge Expandable RAID Controller 3/Di @@ -452,8 +563,14 @@ 0518 MGA-II [Athena] 0519 MGA 2064W [Millennium] 051a MGA 1064SG [Mystique] + 102b 1100 MGA-1084SG Mystique + 102b 1200 MGA-1084SG Mystique 1100 102b MGA-1084SG Mystique + 110a 0018 Scenic Pro C5 (D1025) 051b MGA 2164W [Millennium II] + 102b 051b MGA-2164W Millennium II + 102b 1100 MGA-2164W Millennium II + 102b 1200 MGA-2164W Millennium II 051e MGA 1064SG [Mystique] AGP 051f MGA 2164W [Millennium II] AGP 0520 MGA G200 @@ -475,10 +592,16 @@ 102b ca60 Millennium G250 LE AGP 102b ca6c Millennium G250 AGP 102b dbbc Millennium G200 AGP + 102b dbc2 Millennium G200 MMS (Dual G200) + 102b dbc8 Millennium G200 MMS (Dual G200) + 102b dbe2 Millennium G200 MMS (Quad G200) + 102b dbe8 Millennium G200 MMS (Quad G200) 102b f806 Mystique G200 Video AGP + 102b ff00 MGA-G200 AGP 102b ff02 Mystique G200 AGP 102b ff03 Millennium G200 AGP 102b ff04 Marvel G200 AGP + 110a 0032 MGA-G200 AGP 0525 MGA G400 AGP 0e11 b16f Matrox MGA-G400 AGP 102b 0328 Millennium G400 16Mb SDRAM @@ -497,9 +620,16 @@ 102b ff01 Productiva G100 102b ff05 Productiva G100 Multi-Monitor 1001 MGA G100 [Productiva] AGP + 102b 1001 MGA-G100 AGP + 102b ff00 MGA-G100 AGP + 102b ff01 MGA-G100 Productiva AGP + 102b ff03 Millennium G100 AGP + 102b ff04 MGA-G100 AGP 102b ff05 MGA-G100 Productiva AGP Multi-Monitor + 110a 001e MGA-G100 AGP 2007 MGA Mistral 4536 VIA Framegrabber + 6573 Shark 10/100 Multiport SwitchNIC 102c Chips and Technologies 00b8 F64310 00c0 F69000 HiQVideo @@ -532,12 +662,16 @@ 0003 ATM Controller 0004 R4000 PCI Bridge 0005 PCI to 486-like bus Bridge + 0006 GUI Accelerator 0007 PCI to UX-Bus Bridge + 0008 GUI Accelerator + 0009 GUI Accelerator for W98 001a [Nile II] 0021 Vrc4373 [Nile I] 0029 PowerVR PCX1 002a PowerVR 3D 0035 USB + 003e NAPCCARD Cardbus Controller 0046 PowerVR PCX2 [midas] 005a Vrc5074 [Nile 4] 0063 Firewarden @@ -565,7 +699,9 @@ 0006 85C501/2/3 0008 85C503/5513 0009 ACPI + 0018 SiS85C503/5513 (LPC Bridge) 0200 5597/5598 VGA + 1039 0000 SiS5597 SVGA (Shared RAM) 0204 82C204 0205 SG86C205 0406 85C501/2 @@ -577,34 +713,81 @@ 0620 620 Host 0630 630 Host 0900 SiS900 10/100 Ethernet + 1039 0900 SiS900 10/100 Ethernet Adapter 3602 83C602 5107 5107 + 5300 SiS540 PCI Display Adapter + 5401 486 PCI Chipset 5511 5511/5512 5513 5513 [IDE] + 1039 5513 SiS5513 EIDE Controller (A,B step) 5517 5517 5571 5571 + 5581 5581 Pentium Chipset + 5582 5582 5591 5591/5592 Host + 5596 5596 Pentium Chipset 5597 5597 [SiS5582] 5600 5600 Host 6204 Video decoder & MPEG interface + 6205 VGA Controller 6236 6236 3D-AGP + 6300 SiS630 GUI Accelerator+3D 6306 6306 3D-AGP + 1039 6306 SiS530,620 GUI Accelerator+3D 6326 86C326 + 1039 6326 SiS6326 GUI Accelerator 1092 0a50 SpeedStar A50 1092 0a70 SpeedStar A70 1092 4910 SpeedStar A70 1092 4920 SpeedStar A70 + 1569 6326 SiS6326 GUI Accelerator 7001 7001 7007 OHCI Compliant FireWire Controller + 7016 SiS7016 10/100 Ethernet Adapter + 1039 7016 SiS7016 10/100 Ethernet Adapter + 7018 SiS PCI Audio Accelerator + 1014 01b6 SiS PCI Audio Accelerator + 1014 01b7 SiS PCI Audio Accelerator + 1019 7018 SiS PCI Audio Accelerator + 1025 000e SiS PCI Audio Accelerator + 1025 0018 SiS PCI Audio Accelerator + 1039 7018 SiS PCI Audio Accelerator + 1043 800b SiS PCI Audio Accelerator + 1054 7018 SiS PCI Audio Accelerator + 107d 5330 SiS PCI Audio Accelerator + 107d 5350 SiS PCI Audio Accelerator + 1170 3209 SiS PCI Audio Accelerator + 1462 400a SiS PCI Audio Accelerator + 14a4 2089 SiS PCI Audio Accelerator + 14cd 2194 SiS PCI Audio Accelerator + 14ff 1100 SiS PCI Audio Accelerator + 152d 8808 SiS PCI Audio Accelerator + 1558 1103 SiS PCI Audio Accelerator + 1558 2200 SiS PCI Audio Accelerator + 1563 7018 SiS PCI Audio Accelerator + 15c5 0111 SiS PCI Audio Accelerator + 270f a171 SiS PCI Audio Accelerator + a0a0 0022 SiS PCI Audio Accelerator 103a Seiko Epson Corporation 103b Tatung Co. of America 103c Hewlett-Packard Company 1030 J2585A 1031 J2585B + 103c 1040 J2973A DeskDirect 10BaseT NIC + 103c 1041 J2585B DeskDirect 10/100VG NIC + 103c 1042 J2970A DeskDirect 10BaseT/2 NIC 1040 J2973A DeskDirect 10BaseT NIC 1041 J2585B DeskDirect 10/100 NIC 1042 J2970A DeskDirect 10BaseT/2 NIC 1064 79C970 PCnet Ethernet Controller + 10c1 NetServer Smart IRQ Router + 10ed TopTools Remote Control + 1200 82557B 10/100 NIC + 1219 NetServer PCI Hot-Plug Controller + 121a NetServer SMIC Controller + 121b NetServer Legacy COM Port Decoder + 121c NetServer PCI COM Port Decoder 2910 E2910A 2925 E2925A 103e Solliday Engineering @@ -640,8 +823,10 @@ c822 82C822 c824 82C824 c825 82C825 [Firebridge 2] + c832 82C832 c861 82C861 c895 82C895 + c935 EV1935 ECTIVA MachOne PCI Audio d568 82C825 [Firebridge 2] 1046 IPC Corporation, Ltd. 1047 Genoa Systems Corp @@ -678,11 +863,13 @@ 1097 3d01 Jeronimo Pro 3d3d 0100 Reference Permedia 2 3D 8000 PCILynx/PCILynx2 IEEE 1394 Link Layer Controller - e4bf 1010 CF1-1-SNARE - e4bf 1020 CF1-2-SNARE + e4bf 1010 CF1-1-SNARE + e4bf 1020 CF1-2-SNARE 8009 OHCI Compliant FireWire Controller 8019 TSB12LV23 OHCI Compliant IEEE-1394 Controller - e4bf 1010 CF2-1-CYMBAL + 11bd 000a Studio DV500-1394 + 11bd 000e Studio DV + e4bf 1010 CF2-1-CYMBAL a001 TDC1570 a100 TDC1561 ac10 PCI1050 @@ -701,15 +888,24 @@ ac1e PCI1211 ac1f PCI1251B ac20 TI 2030 + ac30 PCI1260 PC card Cardbus Controller + ac40 PCI4450 PC card Cardbus Controller + ac41 PCI4410 PC card Cardbus Controller + ac42 PCI4451 PC card Cardbus Controller + ac50 PCI1410 PC card Cardbus Controller ac51 PCI1420 + ac52 PCI1451 PC card Cardbus Controller + ac53 PCI1421 PC card Cardbus Controller fe00 FireWire Host Controller fe03 12C01A FireWire Host Controller 104d Sony Corporation - 8039 CXD3222 iLINK Controller + 8009 CXD1947Q i.LINK Controller + 8039 CXD3222 i.LINK Controller 8056 Rockwell HCF 56K modem 104e Oak Technology, Inc 0017 OTI-64017 0107 OTI-107 [Spitfire] + 0109 Video Adapter 0111 OTI-64111 [Spitfire] 0217 OTI-64217 0317 OTI-64317 @@ -719,35 +915,48 @@ 0001 W83769F 0105 W82C105 0840 W89C840 + 1050 0001 W89C840 Ethernet Adapter + 1050 0840 W89C840 Ethernet Adapter 0940 W89C940 5a5a W89C940F 9970 W9970CF 1051 Anigma, Inc. +1052 ?Young Micro Systems 1053 Young Micro Systems 1054 Hitachi, Ltd 1055 EFAR Microsystems 1056 ICL -# Motorola made a mistake and used this value, please duplicate Moto -# entries here -- Cort -1507 Motorola - 0001 MPC105 [Eagle] - 0002 MPC106 [Grackle] - 0003 MPC8240 [Kahlua] - 0100 MC145575 [HFC-PCI] - 0431 KTI829c 100VG - 4801 Raven - 4802 Falcon - 4803 Hawk - 4806 CPX8216 +# Motorola made a mistake and used 1507 instead of 1057 in some chips. +# Please look at the 1507 entry as well when updating this. 1057 Motorola 0001 MPC105 [Eagle] 0002 MPC106 [Grackle] 0100 MC145575 [HFC-PCI] 0431 KTI829c 100VG + 1801 Audio I/O Controller (MIDI) + ecc0 0030 Layla 4801 Raven 4802 Falcon 4803 Hawk 4806 CPX8216 + 5600 SM56 PCI Modem + 1057 0300 SM56 PCI Speakerphone Modem + 1057 0301 SM56 PCI Voice Modem + 1057 0302 SM56 PCI Fax Modem + 1057 5600 SM56 PCI Voice modem + 13d2 0300 SM56 PCI Speakerphone Modem + 13d2 0301 SM56 PCI Voice modem + 13d2 0302 SM56 PCI Fax Modem + 1436 0300 SM56 PCI Speakerphone Modem + 1436 0301 SM56 PCI Voice modem + 1436 0302 SM56 PCI Fax Modem + 144f 100c SM56 PCI Fax Modem + 1494 0300 SM56 PCI Speakerphone Modem + 1494 0301 SM56 PCI Voice modem + 14c8 0300 SM56 PCI Speakerphone Modem + 14c8 0302 SM56 PCI Fax Modem + 1668 0300 SM56 PCI Speakerphone Modem + 1668 0302 SM56 PCI Fax Modem 1058 Electronics & Telecommunications RSH 1059 Teknor Industrial Computers Inc 105a Promise Technology, Inc. @@ -784,6 +993,7 @@ 0891 UM8891A 1001 UM886A 673a UM8886BF + 673b EIDE Master/DMA 8710 UM8710 886a UM8886A 8881 UM8881F @@ -795,6 +1005,7 @@ 9026 UM9026 e881 UM8881N e886 UM8886N + e88a UM8886N e891 UM8891N 1061 I.I.T. 0001 AGX016 @@ -828,6 +1039,8 @@ 0010 Heathrow Mac I/O 0017 Paddington Mac I/O 106c Hyundai Electronics America + 8801 Dual Pentium ISA/PCI Motherboard + 8802 PowerPC ISA/PCI Motherboard 8803 Dual Window Graphics Accelerator 8804 LAN Controller 8805 100-BaseT LAN @@ -838,13 +1051,29 @@ 1071 Mitac 1072 GIT Co Ltd 1073 Yamaha Corporation + 0001 3D GUI Accelerator 0002 YGV615 [RPA3 3D-Graphics Controller] 0003 YMF-740 0004 YMF-724 - 000C YMF-740C [DS-1L Audio Controller] - 000D YMF-724F [DS-1 Audio Controller] + 1073 0004 YMF724-Based PCI Audio Adapter + 0005 DS1 Audio + 1073 0005 DS-XG PCI Audio CODEC + 0006 DS1 Audio + 0008 DS1 Audio + 1073 0008 DS-XG PCI Audio CODEC + 000a DS1L Audio + 1073 0004 DS-XG PCI Audio CODEC + 1073 000a DS-XG PCI Audio CODEC + 000c YMF-740C [DS-1L Audio Controller] + 107a 000c DS-XG PCI Audio CODEC + 000d YMF-724F [DS-1 Audio Controller] + 1073 000d DS-XG PCI Audio CODEC 0010 YMF-744B [DS-1S Audio Controller] + 1073 0006 DS-XG PCI Audio CODEC + 1073 0010 DS-XG PCI Audio CODEC 0012 YMF-754 [DS-1E Audio Controller] + 1073 0012 DS-XG PCI Audio Codec + 0020 DS-1 Audio 1074 NexGen Microsystems 4e78 82c500/1 1075 Advanced Integrations Research @@ -899,18 +1128,24 @@ 0010 VME Bridge Model 618 3000 VME Bridge Model 2706 108c Oakleigh Systems Inc. -108d Olicom +108d Olicom 0001 Token-Ring 16/4 PCI Adapter (3136/3137) 0002 16/4 Token Ring 0004 RapidFire 3139 Token-Ring 16/4 PCI Adapter + 108d 0004 OC-3139/3140 RapidFire Token-Ring 16/4 Adapter 0005 GoCard 3250 Token-Ring 16/4 CardBus PC Card 0006 OC-3530 RapidFire Token-Ring 100 0007 RapidFire 3141 Token-Ring 16/4 PCI Fiber Adapter + 108d 0007 OC-3141 RapidFire Token-Ring 16/4 Adapter 0008 RapidFire 3540 HSTR 100/16/4 PCI Adapter + 108d 0008 OC-3540 RapidFire HSTR 100/16/4 Adapter 0011 OC-2315 0012 OC-2325 0013 OC-2183/2185 0014 OC-2326 + 0019 OC-2327/2250 10/100 Ethernet Adapter + 108d 0016 OC-2327 Rapidfire 10/100 Ethernet Adapter + 108d 0017 OC-2250 GoCard 10/100 Ethernet Adapter 0021 OC-6151/6152 [RapidFire ATM 155] 0022 ATM Adapter 108e Sun Microsystems Computer Corp. @@ -918,6 +1153,7 @@ 1000 EBUS 1001 Happy Meal 5000 Simba Advanced PCI Bridge + 5043 SunPCI Co-processor 8000 PCI Bus Module a000 Ultra IIi 108f Systemsoft @@ -928,7 +1164,7 @@ 0040 3D graphics frame buffer 0041 3D graphics frame buffer 0060 Proprietary bus bridge - 00E4 Powerstorm 4D50T + 00e4 Powerstorm 4D50T 0720 Motion JPEG codec 1092 Diamond Multimedia Systems 00a0 Speedstar Pro SE @@ -992,15 +1228,94 @@ 109e Brooktree Corporation 0350 Bt848 TV with DMA push 0351 Bt849A Video capture + 036c Bt879(??) Video Capture + 13e9 0070 Win/TV (Video Section) 036e Bt878 + 127a 0001 Bt878 Mediastream Controller NTSC + 127a 0002 Bt878 Mediastream Controller PAL BG + 127a 0003 Bt878a Mediastream Controller PAL BG + 127a 0048 Bt878/832 Mediastream Controller + 144f 3000 MagicTView CPH060 - Video + 14f1 0001 Bt878 Mediastream Controller NTSC + 14f1 0002 Bt878 Mediastream Controller PAL BG + 14f1 0003 Bt878a Mediastream Controller PAL BG + 14f1 0048 Bt878/832 Mediastream Controller 1851 1850 FlyVideo'98 - Video 1851 1851 FlyVideo II 1852 1852 FlyVideo'98 - Video (with FM Tuner) 036f Bt879 + 127a 0044 Bt879 Video Capture NTSC + 127a 0122 Bt879 Video Capture PAL I + 127a 0144 Bt879 Video Capture NTSC + 127a 0222 Bt879 Video Capture PAL BG + 127a 0244 Bt879a Video Capture NTSC + 127a 0322 Bt879 Video Capture NTSC + 127a 0422 Bt879 Video Capture NTSC + 127a 1122 Bt879 Video Capture PAL I + 127a 1222 Bt879 Video Capture PAL BG + 127a 1322 Bt879 Video Capture NTSC + 127a 1522 Bt879a Video Capture PAL I + 127a 1622 Bt879a Video Capture PAL BG + 127a 1722 Bt879a Video Capture NTSC + 14f1 0044 Bt879 Video Capture NTSC + 14f1 0122 Bt879 Video Capture PAL I + 14f1 0144 Bt879 Video Capture NTSC + 14f1 0222 Bt879 Video Capture PAL BG + 14f1 0244 Bt879a Video Capture NTSC + 14f1 0322 Bt879 Video Capture NTSC + 14f1 0422 Bt879 Video Capture NTSC + 14f1 1122 Bt879 Video Capture PAL I + 14f1 1222 Bt879 Video Capture PAL BG + 14f1 1322 Bt879 Video Capture NTSC + 14f1 1522 Bt879a Video Capture PAL I + 14f1 1622 Bt879a Video Capture PAL BG + 14f1 1722 Bt879a Video Capture NTSC 1851 1850 FlyVideo'98 - Video 1851 1851 FlyVideo II 1852 1852 FlyVideo'98 - Video (with FM Tuner) + 0370 Bt880 Video Capture + 1851 1850 FlyVideo'98 + 1851 1851 FlyVideo'98 EZ - video + 1852 1852 FlyVideo'98 (with FM Tuner) 0878 Bt878 + 127a 0001 Bt878 Video Capture (Audio Section) + 127a 0002 Bt878 Video Capture (Audio Section) + 127a 0003 Bt878 Video Capture (Audio Section) + 127a 0048 Bt878 Video Capture (Audio Section) + 13e9 0070 Win/TV (Audio Section) + 144f 3000 MagicTView CPH060 - Audio + 14f1 0001 Bt878 Video Capture (Audio Section) + 14f1 0002 Bt878 Video Capture (Audio Section) + 14f1 0003 Bt878 Video Capture (Audio Section) + 14f1 0048 Bt878 Video Capture (Audio Section) + 0879 Bt879 Video Capture (Audio Section) + 127a 0044 Bt879 Video Capture (Audio Section) + 127a 0122 Bt879 Video Capture (Audio Section) + 127a 0144 Bt879 Video Capture (Audio Section) + 127a 0222 Bt879 Video Capture (Audio Section) + 127a 0244 Bt879 Video Capture (Audio Section) + 127a 0322 Bt879 Video Capture (Audio Section) + 127a 0422 Bt879 Video Capture (Audio Section) + 127a 1122 Bt879 Video Capture (Audio Section) + 127a 1222 Bt879 Video Capture (Audio Section) + 127a 1322 Bt879 Video Capture (Audio Section) + 127a 1522 Bt879 Video Capture (Audio Section) + 127a 1622 Bt879 Video Capture (Audio Section) + 127a 1722 Bt879 Video Capture (Audio Section) + 14f1 0044 Bt879 Video Capture (Audio Section) + 14f1 0122 Bt879 Video Capture (Audio Section) + 14f1 0144 Bt879 Video Capture (Audio Section) + 14f1 0222 Bt879 Video Capture (Audio Section) + 14f1 0244 Bt879 Video Capture (Audio Section) + 14f1 0322 Bt879 Video Capture (Audio Section) + 14f1 0422 Bt879 Video Capture (Audio Section) + 14f1 1122 Bt879 Video Capture (Audio Section) + 14f1 1222 Bt879 Video Capture (Audio Section) + 14f1 1322 Bt879 Video Capture (Audio Section) + 14f1 1522 Bt879 Video Capture (Audio Section) + 14f1 1622 Bt879 Video Capture (Audio Section) + 14f1 1722 Bt879 Video Capture (Audio Section) + 0880 Bt880 Video Capture (Audio Section) 2115 BtV 2115 Mediastream controller 2125 BtV 2125 Mediastream controller 2164 BtV 2164 @@ -1108,35 +1423,75 @@ 0006 16/4 Cardbus Adapter 10b6 0006 16/4 CardBus Adapter 0007 Presto PCI Adapter + 10b6 0007 Presto PCI 0009 Smart 100/16/4 PCI-HS Ringnode + 10b6 0009 Smart 100/16/4 PCI-HS Ringnode 000a Smart 100/16/4 PCI Ringnode + 10b6 000a Smart 100/16/4 PCI Ringnode 000b 16/4 CardBus Adapter Mk2 + 10b6 000b 16/4 Cardbus Adapter Mk2 1000 Collage 25 ATM Adapter 1001 Collage 155 ATM Server Adapter 10b7 3Com Corporation 0001 3c985 1000BaseSX 3390 Token Link Velocity 3590 3c359 TokenLink Velocity XL + 10b7 3590 TokenLink Velocity XL Adapter + 4500 3c450 Cyclone/unknown + 5055 3c555 Laptop Hurricane 5057 3c575 [Megahertz] 10/100 LAN CardBus + 10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus PC Card 5157 3c575 [Megahertz] 10/100 LAN CardBus + 10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card + 5257 3CCFE575CT Cyclone CardBus 5900 3c590 10BaseT [Vortex] + 5920 3c592 EISA 10mbps Demon/Vortex 5950 3c595 100BaseTX [Vortex] 5951 3c595 100BaseT4 [Vortex] 5952 3c595 100Base-MII [Vortex] + 5970 3c597 EISA Fast Demon/Vortex + 6560 3CCFE656 Cyclone CardBus + 6562 3CCFEM656 Cyclone CardBus + 7646 3cSOHO100-TX Hurricane 8811 Token ring 9000 3c900 10BaseT [Boomerang] 9001 3c900 Combo [Boomerang] 9004 3c900B-TPO [Etherlink XL TPO] + 10b7 9004 3C900B-TPO Etherlink XL TPO 10Mb 9005 3c900B-Combo [Etherlink XL Combo] + 10b7 9005 3C900B-Combo Etherlink XL Combo 9006 3c900B-TPC [Etherlink XL TPC] - 900A 3c900B-FL [Etherlink XL FL] + 900a 3c900B-FL [Etherlink XL FL] 9050 3c905 100BaseTX [Boomerang] 9051 3c905 100BaseT4 9055 3c905B 100BaseTX [Cyclone] + 1028 0080 3C905B Fast Etherlink XL 10/100 + 1028 0081 3C905B Fast Etherlink XL 10/100 + 1028 0082 3C905B Fast Etherlink XL 10/100 + 1028 0083 3C905B Fast Etherlink XL 10/100 + 1028 0084 3C905B Fast Etherlink XL 10/100 + 1028 0085 3C905B Fast Etherlink XL 10/100 + 1028 0086 3C905B Fast Etherlink XL 10/100 + 1028 0087 3C905B Fast Etherlink XL 10/100 + 1028 0088 3C905B Fast Etherlink XL 10/100 + 1028 0089 3C905B Fast Etherlink XL 10/100 + 1028 0090 3C905B Fast Etherlink XL 10/100 + 1028 0091 3C905B Fast Etherlink XL 10/100 + 1028 0092 3C905B Fast Etherlink XL 10/100 + 1028 0093 3C905B Fast Etherlink XL 10/100 + 1028 0094 3C905B Fast Etherlink XL 10/100 + 1028 0095 3C905B Fast Etherlink XL 10/100 + 1028 0096 3C905B Fast Etherlink XL 10/100 + 1028 0097 3C905B Fast Etherlink XL 10/100 + 1028 0098 3C905B Fast Etherlink XL 10/100 + 1028 0099 3C905B Fast Etherlink XL 10/100 + 10b7 9055 3C905B Fast Etherlink XL 10/100 9058 3c905B-Combo [Deluxe Etherlink XL 10/100] - 905A 3c905B-FX [Fast Etherlink XL FX 10/100] + 905a 3c905B-FX [Fast Etherlink XL FX 10/100] 9200 3c905C-TX [Fast Etherlink] + 10b7 1000 3C905C-TX Fast Etherlink for PC Management NIC 9800 3c980-TX [Fast Etherlink XL Server Adapter] + 10b7 9800 3c980-TX Fast Etherlink XL Server Adapter 10b8 Standard Microsystems Corp [SMC] 0005 83C170QF 1055 e000 LANEPIC @@ -1147,11 +1502,20 @@ 10b8 a016 EtherPower II 10/100 10b8 a017 EtherPower II 10/100 0006 LANEPIC + 1055 e100 LANEPIC Cardbus Fast Ethernet Adapter + 1055 e102 LANEPIC Cardbus Fast Ethernet Adapter + 1055 e300 LANEPIC Cardbus Fast Ethernet Adapter + 1055 e302 LANEPIC Cardbus Fast Ethernet Adapter + 10b8 a012 LANEPIC Cardbus Fast Ethernet Adapter + 13a2 8002 LANEPIC Cardbus Fast Ethernet Adapter + 13a2 8006 LANEPIC Cardbus Fast Ethernet Adapter 1000 FDC 37c665 1001 FDC 37C922 a011 83C170QF b106 SMC34C90 10b9 Acer Laboratories Inc. [ALi] + 0111 C-Media CMI8738/C3DX Audio Device (OEM) + 10b9 0111 C-Media CMI8738/C3DX Audio Device (OEM) 1435 M1435 1445 M1445 1449 M1449 @@ -1162,12 +1526,18 @@ 1512 M1512 [Aladdin] 1513 M1513 [Aladdin] 1521 M1521 [Aladdin III] + 10b9 1521 ALI M1521 Aladdin III CPU Bridge 1523 M1523 + 10b9 1523 ALI M1523 ISA Bridge 1531 M1531 [Aladdin IV] 1533 M1533 PCI to ISA Bridge [Aladdin IV] + 10b9 1533 ALI M1533 Aladdin IV ISA Bridge 1541 M1541 + 10b9 1541 ALI M1541 Aladdin V/V+ AGP System Controller 1543 M1543 1621 M1621 + 1631 ALI M1631 PCI North Bridge Aladdin Pro III + 1641 ALI M1641 PCI North Bridge Aladdin Pro IV 3141 M3141 3143 M3143 3145 M3145 @@ -1187,6 +1557,7 @@ 5243 M5243 5247 M5247 7101 M7101 PMU + 10b9 7101 ALI M7101 Power Management Controller 10ba Mitsubishi Electric Corp. 0301 AccelGraphics AccelECLIPSE 10bb Dapha Electronics Corporation @@ -1209,10 +1580,40 @@ 0002 NM2090 [MagicGraph 128V] 0003 NM2093 [MagicGraph 128ZV] 0004 NM2160 [MagicGraph 128XD] - 0005 [MagicGraph 256AV] - 0006 [MagicGraph 256ZX] + 1014 00ba MagicGraph 128XD + 1025 1007 MagicGraph 128XD + 1028 0074 MagicGraph 128XD + 1028 0075 MagicGraph 128XD + 1028 007d MagicGraph 128XD + 1028 007e MagicGraph 128XD + 1033 802f MagicGraph 128XD + 104d 801b MagicGraph 128XD + 104d 802f MagicGraph 128XD + 104d 830b MagicGraph 128XD + 10ba 0e00 MagicGraph 128XD + 10c8 0004 MagicGraph 128XD + 10cf 1029 MagicGraph 128XD + 10f7 8308 MagicGraph 128XD + 10f7 8309 MagicGraph 128XD + 10f7 830b MagicGraph 128XD + 10f7 830d MagicGraph 128XD + 10f7 8312 MagicGraph 128XD + 0005 [MagicMedia 256AV] + 0006 NM2360 [MagicMedia 256ZX] 0083 [MagicGraph 128ZV Plus] - 8005 [MagicMedia 256AV] + 8005 [MagicMedia 256AV Audio] + 0e11 b0d1 MagicMedia 256AV Audio Device on Discovery + 0e11 b126 MagicMedia 256AV Audio Device on Durango + 1014 00dd MagicMedia 256AV Audio Device on BlackTip Thinkpad + 1025 1003 MagicMedia 256AV Audio Device on TravelMate 720 + 1028 008f MagicMedia 256AV Audio Device on Colorado Inspiron + 103c 0007 MagicMedia 256AV Audio Device on Voyager II + 103c 0008 MagicMedia 256AV Audio Device on Voyager III + 103c 000d MagicMedia 256AV Audio Device on Omnibook 900 + 10c8 8005 MagicMedia 256AV Audio Device on FireAnt + 110a 8005 MagicMedia 256AV Audio Device + 14c0 0004 MagicMedia 256AV Audio Device + 8006 NM2360 [MagicMedia 256ZX Audio] 10c9 Dataexpert Corporation 10ca Fujitsu Microelectr., Inc. 10cb Omron Corporation @@ -1221,6 +1622,7 @@ 1100 ASC1100 1200 ASC1200 [(abp940) Fast SCSI-II] 1300 ABP940-U / ABP960-U + 10cd 1310 ASC1300 SCSI Adapter 2300 ABP940-UW 10ce Radius 10cf Citicorp TTI @@ -1258,7 +1660,6 @@ 1043 0200 V3400 TNT 1092 0550 Viper V550 1092 0552 Viper V550 - 1102 1015 Graphics Blaster CT6710 1092 4804 Viper V550 1092 4808 Viper V550 1092 4810 Viper V550 @@ -1269,31 +1670,70 @@ 1092 4904 Viper V550 1092 4914 Viper V550 1092 8225 Viper V550 + 10de 0020 Riva TNT + 1102 1015 Graphics Blaster CT6710 + 1102 1016 Graphics Blaster RIVA TNT 0028 Riva TnT2 [NV5] 1043 0200 AGP-V3800 SGRAM + 1043 0201 AGP-V3800 SDRAM + 1043 0205 PCI-V3800 + 1043 4000 AGP-V3800PRO 1092 4804 Viper V770 1092 4a00 Viper V770 1092 4a02 Viper V770 Ultra 1092 6a02 Viper V770 Ultra 1092 7a02 Viper V770 Ultra + 10de 0005 RIVA TNT2 Pro 1102 1020 3D Blaster RIVA TNT2 + 1102 1026 3D Blaster RIVA TNT2 Digital 14af 5810 Maxi Gamer Xentor 0029 Riva TnT2 Ultra [NV5] 1043 0200 AGP-V3800 Deluxe + 1043 0201 AGP-V3800 Ultra SDRAM + 1043 0205 PCI-V3800 Ultra 1102 1021 3D Blaster RIVA TNT2 Ultra + 1102 1029 3D Blaster RIVA TNT2 Ultra + 1102 102f 3D Blaster RIVA TNT2 Ultra 14af 5820 Maxi Gamer Xentor 32 002a Riva TnT2 [NV5] 002b Riva TnT2 [NV5] 002c Vanta [NV6] 1043 0200 AGP-V3800 Combat SDRAM + 1043 0201 AGP-V3800 Combat 1092 6820 Viper V730 + 1102 1031 CT6938 VANTA 8MB + 1102 1034 CT6894 VANTA 16MB 14af 5008 Maxi Gamer Phoenix 2 002d Vanta [NV6] 1043 0200 AGP-V3800M + 1043 0201 AGP-V3800M + 1102 1023 CT6892 RIVA TNT2 Value + 1102 1024 CT6932 RIVA TNT2 Value 32Mb + 1102 102c CT6931 RIVA TNT2 Value (Jumper) + 1462 8808 MSI-8808 002e Vanta [NV6] 002f Vanta [NV6] 00a0 Riva TNT2 14af 5810 Maxi Gamer Xentor + 0100 GeForce 256 + 1043 0200 AGP-V6600 SGRAM + 1043 0201 AGP-V6600 SDRAM + 1043 4008 AGP-V6600 SGRAM + 1043 4009 AGP-V6600 SDRAM + 1102 102d CT6941 GeForce 256 + 0101 GeForce 256 DDR + 1043 0202 AGP-V6800 DDR + 1043 400a AGP-V6800 DDR SGRAM + 1043 400b AGP-V6800 DDR SDRAM + 1102 102e CT6971 GeForce 256 DDR + 0103 Quadro (GeForce 256 GL) + 0110 NV11 + 0111 NV11 DDR + 0113 NV11 GL + 0150 NV15 (Geforce2 GTS) + 0151 NV15 DDR (Geforce2 GTS) + 0152 NV15 Bladerunner (Geforce2 GTS) + 0153 NV15 GL (Quadro2) 10df Emulex Corporation 10df Light Pulse Fibre Channel Adapter 1ae5 LP6000 Fibre Channel Host Adapter @@ -1327,6 +1767,9 @@ 8088 Kingsberg Spacetec Format Synchronizer 8089 Kingsberg Spacetec Serial Output Board 809c S5933_HEPC3 + 80d7 PCI-9112 + 80d9 PCI-9118 + 80da PCI-9812 811a PCI-IEEE1355-DS-DE Interface 8170 S5933 "Matchmaker" [PCI Chipset Development Tool] 10e9 Alps Electric Co., Ltd. @@ -1349,6 +1792,9 @@ 1186 0300 DE-528 1259 2400 AT-2400 8129 RTL-8129 + 10ec 8129 RT8129 Fast Ethernet Adapter + 8138 RT8139 (B/C) Cardbus Fast Ethernet Adapter + 10ec 8138 RT8139 (B/C) Fast Ethernet Adapter 8139 RTL-8139 1025 8920 ALN-325 1025 8921 ALN-325 @@ -1407,12 +1853,16 @@ 1102 0020 CT4850 SBLive! Value 1102 0021 CT4620 SBLive! 1102 002f SBLive! mainboard implementation + 1102 4001 E-mu APS 1102 8022 CT4780 SBLive! Value + 1102 8023 CT4790 SoundBlaster PCI512 1102 8024 CT4760 SBLive! + 1102 8025 SBLive! Mainboard Implementation 1102 8026 CT4830 SBLive! Value 1102 8027 CT4832 SBLive! Value 1102 8031 CT4831 SBLive! Value 1102 8040 CT4760 SBLive! + 1102 8051 CT4850 SBLive! Value 7002 SB Live! 1102 0020 Gameport Joystick 1103 Triones Technologies, Inc. @@ -1424,7 +1874,6 @@ 1106 VIA Technologies, Inc. 0391 VT8371 [KX133] 0501 VT8501 - 0601 VT8601 0505 VT82C505 0561 VT82C561 0571 VT82C586 IDE [Apollo] @@ -1434,11 +1883,17 @@ 1106 0000 MVP3 ISA Bridge 0595 VT82C595 [Apollo VP2] 0596 VT82C596 ISA [Apollo PRO] + 1106 0000 VT82C596/A/B PCI to ISA Bridge + 1458 0596 VT82C596/A/B PCI to ISA Bridge 0597 VT82C597 [Apollo VP3] 0598 VT82C598 [Apollo MVP3] + 0601 VT8601 0680 VT82C680 [Apollo P6] 0686 VT82C686 [Apollo Super] + 1106 0000 VT82C686/A PCI to ISA Bridge + 1106 0686 VT82C686/A PCI to ISA Bridge 0691 VT82C691 [Apollo PRO] + 1458 0691 VT82C691 Apollo Pro System Controller 0693 VT82C693 [Apollo Pro Plus] 0926 VT82C926 [Amazon] 1000 VT82C570MV @@ -1449,10 +1904,13 @@ 1234 0925 MVP3 USB Controller 3040 VT82C586B ACPI 3043 VT86C100A [Rhine 10/100] - 1106 0100 VT86C100A + 10bd 0000 VT86C100A Fast Ethernet Adapter + 1106 0100 VT86C100A Fast Ethernet Adapter 1186 1400 DFE-530TX + 3044 OHCI Compliant IEEE 1394 Host Controller 3057 VT82C686 [Apollo Super ACPI] 3058 VT82C686 [Apollo Super AC97/Audio] + 1462 3091 MS-6309 Onboard Audio 3068 VT82C686 [Apollo Super AC97/Modem] 5030 VT82C596 ACPI [Apollo PRO] 6100 VT85C100A [Rhine II] @@ -1462,8 +1920,8 @@ 8596 VT82C596 [Apollo PRO AGP] 8597 VT82C597 [Apollo VP3 AGP] 8598 VT82C598 [Apollo MVP3 AGP] - 8691 VT82C691 [Apollo Pro] 8601 VT8601 + 8691 VT82C691 [Apollo Pro] 1107 Stratus Computers 0576 VIA VT82C570MV [Apollo] (Wrong vendor ID!) 1108 Proteon, Inc. @@ -1473,8 +1931,8 @@ 0108 P1690Plus 0138 P1690Plus 0139 P1690Plus - 013C P1690Plus - 013D P1690Plus + 013c P1690Plus + 013d P1690Plus 1109 Cogent Data Technologies, Inc. 1400 EM110TX [EX110TX] 110a Siemens Nixdorf AG @@ -1495,23 +1953,27 @@ # DJ- Some people say that 0x1112 is Rockwell International ? 1112 RNS - Div. of Meret Communications Inc 2200 FDDI Adapter + 2300 Fast Ethernet Adapter 2340 4 Port Fast Ethernet Adapter 2400 ATM Adapter 1113 Accton Technology Corporation 1211 SMC2-1211TX + 103c 1207 EN-1207D Fast Ethernet Adapter + 1113 1211 EN-1207D Fast Ethernet Adapter 1217 EN-1217 Ethernet Adapter 5105 10Mbps Network card 9211 EN-1207D Fast Ethernet Adapter + 1113 9211 EN-1207D Fast Ethernet Adapter 1114 Atmel Corporation 1115 3D Labs 1116 Data Translation 0022 DT3001 0023 DT3002 0024 DT3003 - 0028 DT3003-PGL 0025 DT3004 0026 DT3005 0027 DT3001-PGL + 0028 DT3003-PGL 1117 Datacube, Inc 9500 Max-1C SVGA card 9501 Max-1C image processing @@ -1545,8 +2007,8 @@ 0115 GDT 6121RP1/6521RP1 0118 GDT 6x18RD 0119 GDT 6x28RD - 011A GDT 6x38RD - 011B GDT 6x58RD + 011a GDT 6x38RD + 011b GDT 6x58RD 0120 GDT 6117RP2/6517RP2 0121 GDT 6127RP2/6527RP2 0122 GDT 6537RP2 @@ -1555,8 +2017,8 @@ 0125 GDT 6121RP2/6521RP2 0168 GDT 7x18RN 0169 GDT 7x28RN - 016A GDT 7x38RN - 016B GDT 7x58RN + 016a GDT 7x38RN + 016b GDT 7x58RN 0210 GDT 6x19RD 0211 GDT 6x29RD 0260 GDT 7x19RN @@ -1565,7 +2027,9 @@ 0000 155P-MF1 (FPGA) 0002 155P-MF1 (ASIC) 0003 ENI-25P ATM Adapter + 111a 0000 ENI-25p Miniport ATM Adapter 0005 Speedstream 30xx ATM Adapter + 111a 0001 SS-3010 Miniport ATM Adapter 111b Teledyne Electronic Systems 111c Tricord Systems Inc. 0001 Powerbis Bridge @@ -1581,6 +2045,7 @@ 1123 Excellent Design, Inc. 1124 Leutron Vision AG 1125 Eurocore +1126 Vigra 1127 FORE Systems Inc 0200 ForeRunner PCA-200 ATM 0210 PCA-200PC @@ -1601,6 +2066,9 @@ 1131 Philips Semiconductors 7145 SAA7145 7146 SAA7146 + 114b 2003 DVRaptor Video Edit/Capture Card + 11bd 0006 DV500 Overlay + 11bd 000a DV500 Overlay 1132 Mitel Corp. 1133 Eicon Technology Corporation 7901 EiconCard S90 @@ -1612,11 +2080,17 @@ b921 EiconCard P92 b922 EiconCard P92 e001 DIVA 20PRO + 1133 e001 DIVA Pro 2.0 S/T e002 DIVA 20 + 1133 e002 DIVA 2.0 S/T e003 DIVA 20PRO_U + 1133 e003 DIVA Pro 2.0 U e004 DIVA 20_U + 1133 e004 DIVA 2.0 U e010 DIVA Server BRI-2M + 1133 e010 DIVA Server BRI-2M e014 DIVA Server PRO-30M + 1133 e014 DIVA Server PRI-30M 1134 Mercury Computer Systems 0001 Raceway Bridge 1135 Fuji Xerox Co Ltd @@ -1626,6 +2100,7 @@ 1138 Ziatech Corporation 8905 8905 [STD 32 Bridge] 1139 Dynamic Pictures, Inc + 0001 VGA Compatable 3D Graphics 113a FWB Inc 113b Network Computing Devices 113c Cyclone Microsystems, Inc. @@ -1640,9 +2115,9 @@ 113f Equinox Systems, Inc. 0808 SST-64P Adapter 1010 SST-128P Adapter - 80C0 SST-16P Adapter - 80C4 SST-16P Adapter - 80C8 SST-16P Adapter + 80c0 SST-16P Adapter + 80c4 SST-16P Adapter + 80c8 SST-16P Adapter 8888 SST-4P Adapter 9090 SST-8P Adapter 1140 Intervoice Inc @@ -1699,8 +2174,8 @@ 0006 AccelePort Xr,C/X 0009 AccelePort Xr/J 000a AccelePort EPC/J - 000C DataFirePRIme T1 (1-port) - 000D SyncPort 2-Port (x.25/FR) + 000c DataFirePRIme T1 (1-port) + 000d SyncPort 2-Port (x.25/FR) 0011 AccelePort 8r EIA-232 (IBM) 0012 AccelePort 8r EIA-422 0013 AccelePort Xr @@ -1708,9 +2183,9 @@ 0015 AccelePort Xem 0016 AccelePort EPC/X 0017 AccelePort C/X - 001A DataFirePRIme E1 (1-port) - 001B AccelePort C/X (IBM) - 001D DataFire RAS T1/E1/PRI + 001a DataFirePRIme E1 (1-port) + 001b AccelePort C/X (IBM) + 001d DataFire RAS T1/E1/PRI 0023 AccelePort RAS 0024 DataFire RAS B4 ST/U 0026 AccelePort 4r 920 @@ -1760,6 +2235,7 @@ 1014 0183 10/100 EtherJet Cardbus Adapter 115d 0183 Cardbus Ethernet 10/100 0101 Cardbus 56k modem + 115d 1081 Cardbus 56k Modem 0103 Cardbus Ethernet + 56k Modem 115d 1181 CBEM56G-100 Ethernet + 56k Modem 8086 9181 PRO/100 LAN + Modem56 CardBus @@ -1771,10 +2247,12 @@ 1163 Rendition 0001 Verite 1000 2000 Verite V2000/V2100/V2200 + 1092 2000 Stealth II S220 1164 Advanced Peripherals Technologies 1165 Imagraph Corporation 0001 Motion TPEG Recorder/Player with audio 1166 Relience Computer + 0007 CNB20-LE CPU to PCI Bridge 0008 CNB20HE 0009 CNB20HE 1167 Mutoh Industries Inc @@ -1799,6 +2277,7 @@ 1176 SBE Incorporated 1177 Silicon Engineering 1178 Alfa, Inc. + afa1 Fast Ethernet Adapter 1179 Toshiba America Info Systems 0404 DVD Decoder card 0406 Tecra Video Capture device @@ -1807,9 +2286,14 @@ 0603 ToPIC95 PCI to CardBus Bridge for Notebooks 060a ToPIC95 060f ToPIC97 + 0617 ToPIC95 PCI to Cardbus Bridge with ZV Support + 0618 CPU to PCI and PCI to ISA bridge 0701 FIR Port # This is apparently incorrect. Does anyone know the correct ID? # 0701 Lucent DSP1645 [Mars] + 0d01 FIR Port Type-DO + 1179 0001 FIR Port Type-DO +117a A-Trend Technology 117b L G Electronics, Inc. 117c Atto Technology 117d Becton & Dickinson @@ -1856,9 +2340,13 @@ 118e Hermstedt GmbH 118f Green Logic 1190 Tripace + c731 TP-910/920/940 PCI Ultra(Wide) SCSI Adapter 1191 Artop Electronic Corp + 0003 SCSI Cache Host Adapter 0004 ATP8400 0005 ATP850UF + 0006 ATP860 NO-BIOS + 0007 ATP860 8002 AEC6710 SCSI-2 Host Adapter 8010 AEC6712UW SCSI 8020 AEC6712U SCSI @@ -1906,6 +2394,7 @@ 11ad f003 LNE100TX 11ad ffff LNE100TX 1385 f004 FA310TX + c115 LNE100TX Fast Ethernet Adapter 11ae Aztech System Ltd 11af Avid Technology Inc. 11b0 V3 Semiconductor Inc. @@ -1918,6 +2407,7 @@ 11b4 Leitch Technology International 11b5 Radstone Technology Plc 11b6 United Video Corp +11b7 Motorola 11b8 XPoint Technologies, Inc 0001 Quad PeerMaster 11b9 Pathlight Technology Inc. @@ -1974,6 +2464,11 @@ 144d 2104 LT56PT Modem 149f 0440 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 1668 0440 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + 0443 LT WinModem + 0444 LT WinModem + 0445 LT WinModem + 0446 LT WinModem + 0447 LT WinModem 0448 WinModem 56k 13e0 0040 LT WinModem 56k Data+Fax+Voice+Dsvd 0449 WinModem 56k @@ -1982,12 +2477,28 @@ 13e0 0041 TelePath Internet 56k WinModem 144f 0449 Lucent 56k V.90 DFi Modem 1468 0449 Presario 56k V.90 DFi Modem - 044A F-1156IV WinModem (V90, 56KFlex) + 044a F-1156IV WinModem (V90, 56KFlex) 13e0 0012 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 13e0 0042 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd 144f 1005 LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + 044b LT WinModem + 044c LT WinModem + 044d LT WinModem + 044e LT WinModem + 0450 LT WinModem + 0451 LT WinModem + 0452 LT WinModem + 0453 LT WinModem + 0454 LT WinModem + 0455 LT WinModem + 0456 LT WinModem + 0457 LT WinModem + 0458 LT WinModem + 0459 LT WinModem + 045a LT WinModem 0480 Venus WinModem (V90, 56KFlex) 11c2 Sand Microelectronics +11c3 NEC Corp 11c4 Document Technologies, Inc 11c5 Shiva Corporation 11c6 Dainippon Screen Mfg. Co. Ltd @@ -2070,6 +2581,7 @@ 1401 ReadyLink 2000 2011 RL100-ATX 10/100 2201 ReadyLink 100TX (Winbond W89C840) + 11f6 2011 ReadyLink 100TX 9881 RL100TX 11f7 Scientific Atlanta 11f8 PMC-Sierra Inc. @@ -2088,9 +2600,9 @@ 0006 RocketPort 8J 0008 RocketPort 8-port 0009 RocketPort 16-port - 000A RocketPort Plus Quadcable - 000B RocketPort Plus Octacable - 000C RocketPort 8-port Modem + 000a RocketPort Plus Quadcable + 000b RocketPort Plus Octacable + 000c RocketPort 8-port Modem 11ff Scion Corporation 1200 CSS Corporation 1201 Vista Controls Corp @@ -2129,6 +2641,8 @@ 673a 6730 6832 6832 6836 6836 + 6872 OZ6812 Cardbus Controller + 6933 OZ6933 Cardbus Controller 1218 Hybricon Corp. 1219 First Virtual Corporation 121a 3Dfx Interactive, Inc. @@ -2142,10 +2656,16 @@ 1092 4803 Monster Fusion AGP 1092 8030 Monster Fusion 1092 8035 Monster Fusion AGP + 10b0 0001 Dragon 4000 + 1102 1017 CT6760 3D Blaster Banshee 121a 0001 Voodoo Banshee AGP 121a 0003 Voodoo Banshee AGP SGRAM 121a 0004 Voodoo Banshee + 139c 0016 Raven + 139c 0017 Raven + 14af 0002 Maxi Gamer Phoenix 3030 3030 Skywell Magic TwinPower + 0004 Voodoo Banshee 0005 Voodoo 3 121a 0004 Voodoo3 AGP 121a 0030 Voodoo3 AGP @@ -2186,7 +2706,9 @@ 122d Aztech System Ltd 1206 368DSP 50dc 3328 Audio + 122d 0001 3328 Audio 80da 3328 Audio + 122d 0001 3328 Audio 122e Xyratex 122f Andrew Corporation 1230 Fishcamp Engineering @@ -2211,7 +2733,13 @@ 123e Simutech, Inc. 123f C-Cube Microsystems 00e4 MPEG + 8120 E4? + 11bd 0006 DV500 E4 + 11bd 000a DV500 E4 8888 Cinemaster C 3.0 DVD Decoder + 1002 0001 Cinemaster C 3.0 DVD Decoder + 1002 0002 Cinemaster C 3.0 DVD Decoder + 1328 0001 Cinemaster C 3.0 DVD Decoder 1240 Marathon Technologies Corp. 1241 DSC Communications 1242 Jaycor Networks, Inc. @@ -2220,6 +2748,7 @@ 1244 AVM Audiovisuelles MKTG & Computer System GmbH 0700 B1 ISDN 0a00 A1 ISDN [Fritz] + 1244 0a00 FRITZ!Card ISDN Controller 1245 A.P.D., S.A. 1246 Dipix Technologies, Inc. 1247 Xylon Research, Inc. @@ -2257,10 +2786,26 @@ 0000 ES336H Fax Modem (Early Model) 1948 Solo? 1968 ES1968 Maestro 2 + 1028 0085 ES1968 Maestro-2 PCI + 1033 8051 ES1968 Maestro-2 Audiodrive 1969 ES1969 Solo-1 Audiodrive + 1014 0166 ES1969 SOLO-1 AudioDrive on IBM Aptiva Mainboard + 125d 8888 Solo-1 Audio Adapter + 525f c888 ES1969 SOLO-1 AudioDrive (+ES1938) 1978 ES1978 Maestro 2E + 1033 803c ES1978 Maestro-2E Audiodrive + 1033 8058 ES1978 Maestro-2E Audiodrive + 1092 4000 Monster Sound MX400 + 1179 0001 ES1978 Maestro-2E Audiodrive 1988 ES1988 Allegro-1 + 1092 4100 Sonic Impact S100 + 125d 1988 ESS Allegro-1 Audiodrive + 1989 ESS Modem + 125d 1989 ESS Modem + 1998 ES1983S Maestro-3i PCI Audio Accelerator + 1999 ES1983S Maestro-3i PCI Modem Accelerator 2808 ES336H Fax Modem (Later Model) + 2838 ES2838/2839 SuperLink Modem 2898 ES2898 Modem 125e Specialvideo Engineering SRL 125f Concurrent Technologies, Inc. @@ -2275,6 +2820,7 @@ 1266 Microdyne Corporation 0001 NE10/100 Adapter (i82557B) 1910 NE2000Plus (RT8029) Ethernet Adapter + 1266 1910 NE2000Plus Ethernet Adapter 1267 S. A. Telecommunications 5352 PCR2101 5a4b Telsat Turbo @@ -2286,6 +2832,12 @@ 126d Splash Technology, Inc. 126e Sumitomo Metal Industries, Ltd. 126f Silicon Motion, Inc. + 0710 SM710 LynxEM + 0712 SM712 LynxEM+ + 0720 SM720 Lynx3DM + 0810 SM810 LynxE + 0811 SM811 LynxE + 0820 SM820 Lynx3D 0910 SM910 1270 Olympus Optical Co., Ltd. 1271 GW Instruments @@ -2294,7 +2846,66 @@ 0002 DirecPC 1274 Ensoniq 1371 ES1371 [AudioPCI-97] + 0e11 b1a7 ES1371, ES1373 AudioPCI + 1033 80ac ES1371, ES1373 AudioPCI + 1042 1854 Tazer + 107b 8054 Tabor2 + 1274 1371 Creative Sound Blaster AudioPCI64V, AudioPCI128 + 1462 6470 ES1371, ES1373 AudioPCI On Motherboard MS-6147 1.1A + 1462 6560 ES1371, ES1373 AudioPCI On Motherboard MS-6156 1.10 + 1462 6630 ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 1.0A + 1462 6631 ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 1.0A + 1462 6632 ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 2.0A + 1462 6633 ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 2.0A + 1462 6820 ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00 + 1462 6822 ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00A + 1462 6830 ES1371, ES1373 AudioPCI On Motherboard MS-6183 1.00 + 1462 6880 ES1371, ES1373 AudioPCI On Motherboard MS-6188 1.00 + 1462 6900 ES1371, ES1373 AudioPCI On Motherboard MS-6190 1.00 + 1462 6910 ES1371, ES1373 AudioPCI On Motherboard MS-6191 + 1462 6930 ES1371, ES1373 AudioPCI On Motherboard MS-6193 + 1462 6990 ES1371, ES1373 AudioPCI On Motherboard MS-6199BX 2.0A + 1462 6991 ES1371, ES1373 AudioPCI On Motherboard MS-6199VIA 2.0A + 14a4 2077 ES1371, ES1373 AudioPCI On Motherboard KR639 + 14a4 2105 ES1371, ES1373 AudioPCI On Motherboard MR800 + 14a4 2107 ES1371, ES1373 AudioPCI On Motherboard MR801 + 14a4 2172 ES1371, ES1373 AudioPCI On Motherboard DR739 + 1509 9902 ES1371, ES1373 AudioPCI On Motherboard KW11 + 1509 9903 ES1371, ES1373 AudioPCI On Motherboard KW31 + 1509 9904 ES1371, ES1373 AudioPCI On Motherboard KA11 + 1509 9905 ES1371, ES1373 AudioPCI On Motherboard KC13 + 152d 8801 ES1371, ES1373 AudioPCI On Motherboard CP810E + 152d 8802 ES1371, ES1373 AudioPCI On Motherboard CP810 + 152d 8803 ES1371, ES1373 AudioPCI On Motherboard P3810E + 152d 8804 ES1371, ES1373 AudioPCI On Motherboard P3810-S + 152d 8805 ES1371, ES1373 AudioPCI On Motherboard P3820-S + 270f 2001 ES1371, ES1373 AudioPCI On Motherboard 6CTR + 270f 2200 ES1371, ES1373 AudioPCI On Motherboard 6WTX + 270f 3000 ES1371, ES1373 AudioPCI On Motherboard 6WSV + 270f 3100 ES1371, ES1373 AudioPCI On Motherboard 6WIV2 + 270f 3102 ES1371, ES1373 AudioPCI On Motherboard 6WIV + 270f 7060 ES1371, ES1373 AudioPCI On Motherboard 6ASA2 + 8086 4249 ES1371, ES1373 AudioPCI On Motherboard BI440ZX + 8086 424c ES1371, ES1373 AudioPCI On Motherboard BL440ZX + 8086 425a ES1371, ES1373 AudioPCI On Motherboard BZ440ZX + 8086 4341 ES1371, ES1373 AudioPCI On Motherboard Cayman + 8086 4343 ES1371, ES1373 AudioPCI On Motherboard Cape Cod + 8086 4649 ES1371, ES1373 AudioPCI On Motherboard Fire Island + 8086 464a ES1371, ES1373 AudioPCI On Motherboard FJ440ZX + 8086 4d4f ES1371, ES1373 AudioPCI On Motherboard Montreal + 8086 4f43 ES1371, ES1373 AudioPCI On Motherboard OC440LX + 8086 5243 ES1371, ES1373 AudioPCI On Motherboard RC440BX + 8086 5352 ES1371, ES1373 AudioPCI On Motherboard SunRiver + 8086 5643 ES1371, ES1373 AudioPCI On Motherboard Vancouver + 8086 5753 ES1371, ES1373 AudioPCI On Motherboard WS440BX 5000 ES1370 [AudioPCI] + 5880 5880 AudioPCI + 1274 2000 Creative Sound Blaster AudioPCI128 + 1274 5880 Creative Sound Blaster AudioPCI128 + 1462 6880 5880 AudioPCI On Motherboard MS-6188 1.00 + 270f 2001 5880 AudioPCI On Motherboard 6CTR + 270f 2200 5880 AudioPCI On Motherboard 6WTX + 270f 7040 5880 AudioPCI On Motherboard 6ATA4 1275 Network Appliance Corporation 1276 Switched Network Technologies, Inc. 1277 Comstream @@ -2303,15 +2914,37 @@ 0295 Virtual Northbridge 127a Rockwell International 1002 HCF 56k V90 FaxModem + 127a 1002 HCF 56k V90 Modem 1003 HCF 56k V90 FaxModem + 127a 1003 PCI56RX Modem + 13df 1003 PCI56RX Modem 1004 HCF 56k V90 FaxModem 1005 HCF 56k V90 FaxModem 122d 4008 MDP3858SP-A SVD Modem 127a 1005 PCI56RVP Modem 13df 1005 PCI56RVP Modem 1436 1005 WS-5614PS3G + 1025 HCF 56k PCI Modem + 127a 1025 HCF 56k PCI Modem + 1026 HCF 56k PCI Speakerphone Modem + 127a 1026 HCF 56k PCI Speakerphone Modem + 1035 HCF 56k PCI Speakerphone Modem + 127a 1035 HCF 56k PCI Speakerphone Modem + 1085 Volcano HCF 56k PCI Modem + 127a 1085 Volcano HCF 56k PCI Modem 2005 HCF 56k V90 FaxModem + 127a 2005 Conexant SoftK56 Speakerphone Modem + 2015 Conexant SoftK56 Speakerphone Modem + 127a 2015 Conexant SoftK56 Speakerphone Modem + 14c8 2115 Conexant SoftK56 Speakerphone Modem + 4320 Riptide PCI Audio Controller + 1235 4320 Riptide PCI Audio Controller + 4321 Riptide HCF 56k PCI Modem + 1235 4321 Riptide HCF 56k PCI Modem + 4322 Riptide PCI Game Controller + 1235 4322 Riptide PCI Game Controller 8234 RapidFire 616X ATM155 Adapter + 108d 0027 RapidFire 616X ATM155 Adapter 127b Pixera Corporation 127c Crosspoint Solutions, Inc. 127d Vela Research @@ -2324,6 +2957,8 @@ 1283 Integrated Technology Express, Inc. 673a IT8330G 8330 IT8330G + 8888 IT8888F PCI to ISA Bridge with SMB + 8889 IT8889F PCI to ISA Bridge e886 IT8330G 1284 Sahara Networks, Inc. 1285 Platform Technologies, Inc. @@ -2374,6 +3009,7 @@ 12a9 Xiotech Corporation 12aa SDL Communications, Inc. 12ab Yuan Yuan Enterprise Co., Ltd. + 3000 MPG-200C PCI DVD Decoder Card 12ac Measurex Corporation 12ad Multidata GmbH 12ae Alteon Networks Inc. @@ -2390,7 +3026,23 @@ 12b8 Korg 12b9 US Robotics/3Com 1006 WinModem + 12b9 005c USR 56k Internal Voice WinModem (Model 3472) + 12b9 005e USR 56k Internal WinModem (Models 662975) + 12b9 0062 USR 56k Internal Voice WinModem (Model 662978) + 12b9 0068 USR 56k Internal Voice WinModem (Model 5690) + 12b9 007a USR 56k Internal Voice WinModem (Model 662974) + 12b9 007f USR 56k Internal WinModem (Models 5698, 5699) + 12b9 0080 USR 56k Internal WinModem (Models 2975, 3528) + 12b9 0081 USR 56k Internal Voice WinModem (Models 2974, 3529) + 12b9 0091 USR 56k Internal Voice WinModem (Model 2978) + 1007 USR 56k Internal WinModem + 12b9 00a3 USR 56k Internal WinModem (Model 3595) 1008 56K FaxModem Model 5610 + 12b9 00a2 USR 56k Internal FAX Modem (Model 2977) + 12b9 00aa USR 56k Internal Voice Modem (Model 2976) + 12b9 00ab USR 56k Internal Voice Modem (Model 5609) + 12b9 00ac USR 56k Internal Voice Modem (Model 3298) + 12b9 00ad USR 56k Internal FAX Modem (Model 5610) 12ba PMC Sierra 12bb Nippon Unisoft Corporation 12bc Array Microsystems @@ -2398,6 +3050,7 @@ 12be Anchor Chips Inc. 3041 AN3041Q CO-MEM 3042 AN3042Q CO-MEM Lite + 12be 3042 Anchor Chips Lite Evaluation Board 12bf Fujifilm Microdevices 12c0 Infimed 12c1 GMM Research Corp @@ -2436,12 +3089,13 @@ 10b4 222a STB Velocity 128 AGP 10b4 2230 STB Velocity 128 10b4 2235 STB Velocity 128 AGP + 2a15 54a3 3DVision-SAGP 0019 Riva128ZX 0020 TNT 0028 TNT2 0029 UTNT2 - 002C VTNT2 - 00A0 ITNT2 + 002c VTNT2 + 00a0 ITNT2 12d3 Vingmed Sound A/S 12d4 DGM&S 12d5 Equator Technologies @@ -2471,7 +3125,38 @@ 12ea Zuken 12eb Aureal Semiconductor 0001 Vortex 1 + 104d 8036 AU8820 Vortex Digital Audio Processor + 1092 2000 Sonic Impact A3D + 1092 2100 Sonic Impact A3D + 1092 2110 Sonic Impact A3D + 1092 2200 Sonic Impact A3D + 12eb 0001 AU8820 Vortex Digital Audio Processor + 5053 3355 Montego 0002 Vortex 2 + 104d 8049 AU8830 Vortex 3D Digital Audio Processor + 104d 807b AU8830 Vortex 3D Digital Audio Processor + 1092 3000 Monster Sound II + 1092 3001 Monster Sound II + 1092 3002 Monster Sound II + 1092 3003 Monster Sound II + 1092 3004 Monster Sound II + 12eb 0001 AU8830 Vortex 3D Digital Audio Processor + 12eb 0002 AU8830 Vortex 3D Digital Audio Processor + 12eb 0088 AU8830 Vortex 3D Digital Audio Processor + 144d 3510 AU8830 Vortex 3D Digital Audio Processor + 5053 3356 Montego II + 0003 AU8810 Vortex Digital Audio Processor + 104d 8049 AU8810 Vortex Digital Audio Processor + 104d 8077 AU8810 Vortex Digital Audio Processor + 109f 1000 AU8810 Vortex Digital Audio Processor + 12eb 0003 AU8810 Vortex Digital Audio Processor + 1462 6780 AU8810 Vortex Digital Audio Processor + 14a4 2073 AU8810 Vortex Digital Audio Processor + 14a4 2091 AU8810 Vortex Digital Audio Processor + 14a4 2104 AU8810 Vortex Digital Audio Processor + 14a4 2106 AU8810 Vortex Digital Audio Processor + 8803 Vortex 56k Software Modem + 12eb 8803 Vortex 56k Software Modem 12ec 3A International, Inc. 12ed Optivision Inc. 12ee Orange Micro @@ -2500,10 +3185,10 @@ 1306 Duet Technologies 1307 Computer Boards 0001 PCI-DAS1602/16 - 000C PCI-PDISO8 - 000D PCI-PDISO16 - 000B PCI-DIO48H - 000F PCI-DAS1200 + 000b PCI-DIO48H + 000c PCI-PDISO8 + 000d PCI-PDISO16 + 000f PCI-DAS1200 0010 PCI-DAS1602/12 0014 PCI-DIO24H 0015 PCI-DIO24H/CTR3 @@ -2511,12 +3196,12 @@ 0017 PCI-DIO96H 0018 PCI-CTR05 0019 PCI-DAS1200/JR - 001A PCI-DAS1001 - 001B PCI-DAS1002 - 001C PCI-DAS1602JR/16 - 001D PCI-DAS6402/16 - 001E PCI-DAS6402/12 - 001F PCI-DAS16/M1 + 001a PCI-DAS1001 + 001b PCI-DAS1002 + 001c PCI-DAS1602JR/16 + 001d PCI-DAS6402/16 + 001e PCI-DAS6402/12 + 001f PCI-DAS16/M1 0020 PCI-DDA02/12 0021 PCI-DDA04/12 0022 PCI-DDA08/12 @@ -2527,15 +3212,16 @@ 0027 PCI-DAC04/16-HS 0028 PCI-DIO24 0029 PCI-DAS08 - 002C PCI-INT32 + 002c PCI-INT32 0033 PCI-DUAL-AC5 0034 PCI-DAS-TC 0035 PCI-DAS64/M1/16 0036 PCI-DAS64/M2/16 0037 PCI-DAS64/M3/16 - 004C PCI-DAS1000 + 004c PCI-DAS1000 1308 Jato Technologies Inc. 0001 NetCelerator Adapter + 1308 0001 NetCelerator Adapter 1309 AB Semiconductor Ltd 130a Mitsubishi Electric Microcomputer 130b Colorgraphic Communications Corp @@ -2550,9 +3236,12 @@ 1316 Teradyne Inc 1317 Bridgecom, Inc 1318 Packet Engines Inc. + 0911 PCI Ethernet Adapter 1319 Fortemedia, Inc 0801 Xwave QS3000A [FM801] 0802 Xwave QS3000A [FM801 game port] + 1000 FM801 PCI Audio + 1001 FM801 PCI Joystick 131a Finisar Corp. 131c Nippon Electro-Sensory Devices Corp 131d Sysmic, Inc. @@ -2584,6 +3273,7 @@ 2020 CyberParallel (1-port) 2021 CyberParallel (2-port) 2030 CyberSerial (2-port) 16550 + 131f 2030 PCI Serial Card 2031 CyberSerial (2-port) 16650 2032 CyberSerial (2-port) 16850 2040 Trio 1S(16550)+2P @@ -2632,9 +3322,19 @@ 1349 Sumitomo Electric Industries, Ltd. 134a DTC Technology Corp. 0001 Domex 536 + 0002 Domex DMX3194UP SCSI Adapter 134b ARK Research Corp. 134c Chori Joho System Co. Ltd 134d PCTel Inc + 7890 HSP MicroModem 56 + 7891 HSP MicroModem 56 + 134d 0001 HSP MicroModem 56 + 7892 HSP MicroModem 56 + 7893 HSP MicroModem 56 + 7894 HSP MicroModem 56 + 7895 HSP MicroModem 56 + 7896 HSP MicroModem 56 + 7897 HSP MicroModem 56 134e CSTI 134f Algo System Co Ltd 1350 Systec Co. Ltd @@ -2656,6 +3356,7 @@ 7402 Four Port RS-422/485 Interface 7801 Eight Port RS-232 Interface 8001 8001 Digital I/O Adapter +135f I-Data International A-S 1360 Meinberg Funkuhren 1361 Soliton Systems K.K. 1362 Fujifacom Corporation @@ -2713,8 +3414,8 @@ 1396 Cipher Systems Inc 1397 Cologne Chip Designs GmbH 2bd0 ISDN network controller [HFC-PCI] - 1397 2bd0 ISDN Board - e4bf 1000 CI1-1-Harp + 1397 2bd0 ISDN Board + e4bf 1000 CI1-1-Harp 1398 Clarion co. Ltd 1399 Rios systems Co Ltd 139a Alacritech Inc @@ -2790,6 +3491,7 @@ 13de ABB Robotics Products AB 13df E-Tech Inc 0001 PCI56RVP Modem + 13df 0001 PCI56RVP Modem 13e0 GVC Corporation 13e1 Silicom Multimedia Systems Inc 13e2 Dynamics Research Corporation @@ -2814,8 +3516,11 @@ 13f5 Kansai Electric Co. Ltd 13f6 C-Media Electronics Inc 0100 CM8338A + 13f6 ffff CMI8338/C3DX PCI Audio Device 0101 CM8338B + 13f6 0101 CMI8338-031 PCI Audio Device 0111 CM8738 + 13f6 0111 CMI8738/C3DX PCI Audio Device 0211 CM8738 13f7 Wildfire Communications 13f8 Ad Lib Multimedia Inc @@ -2904,6 +3609,16 @@ 1448 Alesis Studio Electronics 1449 TUT Systems Inc 144a Adlink Technology + 7296 PCI-7296 + 7432 PCI-7432 + 7433 PCI-7433 + 7434 PCI-7434 + 7841 PCI-7841 + 8133 PCI-8133 + 8554 PCI-8554 + 9111 PCI-9111 + 9113 PCI-9113 + 9114 PCI-9114 144b Loronix Information Systems Inc 144c Catalina Research Inc 144d Samsung Electronics Co Ltd @@ -2986,7 +3701,7 @@ 149a ANDOR Technology Ltd 149b SEIKO Instruments Inc 149c OVISLINK Corp. -149D NEWTEK Inc +149d NEWTEK Inc 149e Mapletree Networks Inc. 149f LECTRON Co Ltd 14a0 SOFTING GmBH @@ -3084,7 +3799,27 @@ 14ef CARRY Computer ENG. CO Ltd 14f0 CANON RESEACH CENTRE FRANCE 14f1 CONEXANT + 1033 56K Winmodem + 13e0 02b0 56K Winmodem + 1035 PCI Modem Enumerator + 2003 SoftK56 Winmodem + 14f1 2003 SoftK56 Winmodem + 2004 SoftK56 RemoteTAM Winmodem + 14f1 2004 SoftK56 RemoteTAM Winmodem + 2005 SoftK56 Speakerphone Winmodem + 14f1 2005 SoftK56 Speakerphone Winmodem + 2006 SoftK56 Speakerphone Winmodem + 14f1 2006 SoftK56 Speakerphone Winmodem 2013 HSP MicroModem 56K + 14f1 2013 SoftK56 Winmodem + 2014 SoftK56 RemoteTAM Winmodem + 144f 101c SoftK56 RemoteTAM Winmodem + 144f 2014 SoftK56 RemoteTAM Winmodem + 2015 SoftK56 Speakerphone Winmodem + 14c8 2115 SoftK56 Speakerphone Winmodem + 14f1 2015 SoftK56 Speakerphone Winmodem + 2016 SoftK56 Speakerphone Winmodem + 14f1 2016 SoftK56 Speakerphone Winmodem 14f2 MOBILITY Electronics 14f3 BROADLOGIC 14f4 TOKYO Electronic Industry CO Ltd @@ -3109,6 +3844,16 @@ # 1507 HTEC Ltd # Commented out because there are no known HTEC chips and 1507 is already # used by mistake by Motorola (see vendor ID 1057) +1507 Motorola ?? / HTEC + 0001 MPC105 [Eagle] + 0002 MPC106 [Grackle] + 0003 MPC8240 [Kahlua] + 0100 MC145575 [HFC-PCI] + 0431 KTI829c 100VG + 4801 Raven + 4802 Falcon + 4803 Hawk + 4806 CPX8216 1508 HONDA CONNECTORS/MHOTRONICS Inc 1509 FIRST INTERNATIONAL Computer Inc 150a FORVUS RESEARCH Inc @@ -3195,7 +3940,189 @@ 1559 SI LOGIC Ltd 155a INNOMEDIA Inc 155b PROTAC INTERNATIONAL Corp +155c Cemax-Icon Inc +155d Mac System Co Ltd +155e LP Elektronik GmbH +155f Perle Systems Ltd +1560 Terayon Communications Systems +1561 Viewgraphics Inc +1562 Symbol Technologies +1563 A-Trend Technology Co Ltd +1564 Yamakatsu Electronics Industry Co Ltd +1565 Biostar Microtech Int'l Corp +1566 Ardent Technologies Inc +1567 Jungsoft +1568 DDK Electronics Inc +1569 Palit Microsystems Inc. +156a Avtec Systems +156b 2wire Inc +156c Vidac Electronics GmbH +156d Alpha-Top Corp +156e Alfa Inc +156f M-Systems Flash Disk Pioneers Ltd +1570 Lecroy Corp +1571 Contemporary Controls +1572 Otis Elevator Company +1573 Lattice - Vantis +1574 Fairchild Semiconductor +1575 Voltaire Advanced Data Security Ltd +1576 Viewcast COM +1578 HITT +1579 Dual Technology Corp +157a Japan Elecronics Ind Inc +157b Star Multimedia Corp +157c Eurosoft (UK) + 8001 Fix2000 PCI Y2K Compliance Card +157d Gemflex Networks +157e Transition Networks +157f PX Instruments Technology Ltd +1580 Primex Aerospace Co +1581 SEH Computertechnik GmbH +1582 Cytec Corp +1583 Inet Technologies Inc +1584 Uniwill Computer Corp +1585 Logitron +1586 Lancast Inc +1587 Konica Corp +1588 Solidum Systems Corp +1589 Atlantek Microsystems Pty Ltd +158a Digalog Systems Inc +158b Allied Data Technologies +158c Hitachi Semiconductor & Devices Sales Co Ltd +158d Point Multimedia Systems +158e Lara Technology Inc +158f Ditect Coop +1590 3pardata Inc +1591 ARN +1592 Syba Tech Ltd + 0781 Multi-IO Card + 0782 Parallel Port Card 2xEPP + 0783 Multi-IO Card + 0785 Multi-IO Card + 0786 Multi-IO Card + 0787 Multi-IO Card + 0788 Multi-IO Card + 078a Multi-IO Card +1593 Bops Inc +1594 Netgame Ltd +1595 Diva Systems Corp +1596 Folsom Research Inc +1597 Memec Design Services +1598 Granite Microsystems +1599 Delta Electronics Inc +159a General Instrument +159b Faraday Technology Corp +159c Stratus Computer Systems +159d Ningbo Harrison Electronics Co Ltd +159e A-Max Technology Co Ltd +159f Galea Network Security +15a0 Compumaster SRL +15a1 Geocast Network Systems +15a2 Catalyst Enterprises Inc +15a3 Italtel +15a4 X-Net OY +15a5 Toyota Macs Inc +15a6 Sunlight Ultrasound Technologies Ltd +15a7 SSE Telecom Inc +15a8 Shanghai Communications Technologies Center +15aa Moreton Bay +15ab Bluesteel Networks Inc +15ac North Atlantic Instruments +15ad VMWare Inc + 0710 Virtual SVGA +15ae Amersham Pharmacia Biotech +15b0 Zoltrix International Ltd +15b1 Source Technology Inc +15b2 Mosaid Technologies Inc +15b3 Mellanox Technology +15b4 CCI/TRIAD +15b5 Cimetrics Inc +15b6 Texas Memory Systems Inc +15b7 Sandisk Corp +15b8 ADDI-DATA GmbH +15b9 Maestro Digital Communications +15ba Impacct Technology Corp +15bb Portwell Inc +15bc Agilent Technologies +15bd DFI Inc +15be Sola Electronics +15bf High Tech Computer Corp (HTC) +15c0 BVM Ltd +15c1 Quantel +15c2 Newer Technology Inc +15c3 Taiwan Mycomp Co Ltd +15c4 EVSX Inc +15c5 Procomp Informatics Ltd +15c6 Technical University of Budapest +15c7 Tateyama Dystem Laboratory Co Ltd +15c8 Penta Media Co Ltd +15c9 Serome Technology Inc +15ca Bitboys OY +15cb AG Electronics Ltd +15cc Hotrail Inc +15cd Dreamtech Co Ltd +15ce Genrad Inc +15cf Hilscher GmbH +15d1 Infineon Technologies AG +15d2 FIC (First International Computer Inc) +15d3 NDS Technologies Israel Ltd +15d4 Iwill Corp +15d5 Tatung Co +15d6 Entridia Corp +15d7 Rockwell-Collins Inc +15d8 Cybernetics Technology Co Ltd +15d9 Super Micro Computer Inc +15da Cyberfirm Inc +15db Applied Computing Systems Inc +15dc Litronic Inc + 0001 Argus 300 PCI Cryptography Module +15dd Sigmatel Inc +15de Malleable Technologies Inc +15df Infinilink Corp +15e0 Cacheflow Inc +15e1 Voice Technologies Group Inc +15e2 Quicknet Technologies Inc +15e3 Networth Technologies Inc +15e4 VSN Systemen BV +15e5 Valley technologies Inc +15e6 Agere Inc +15e7 Get Engineering Corp +15e8 National Datacomm Corp +15e9 Pacific Digital Corp +15ea Tokyo Denshi Sekei K.K. +15eb Drsearch GmbH +15ec Beckhoff GmbH +15ed Macrolink Inc +15ee In Win Development Inc +15ef Intelligent Paradigm Inc +15f0 B-Tree Systems Inc +15f1 Times N Systems Inc +15f2 Diagnostic Instruments Inc +15f3 Digitmedia Corp +15f4 Valuesoft +15f5 Power Micro Research +15f6 Extreme Packet Device Inc +15f7 Banctec +15f8 Koga Electronics Co +15f9 Zenith Electronics Corp +15fa J.P. Axzam Corp +15fb Zilog Inc +15fc Techsan Electronics Co Ltd +15fd N-CUBED.NET +15fe Kinpo Electronics Inc +15ff Fastpoint Technologies Inc +1600 Northrop Grumman - Canada Ltd +1601 Tenta Technology +1602 Prosys-tec Inc +1603 Nokia Wireless Communications +1604 Central System Research Co Ltd +1605 Pairgain Technologies +1606 Europop AG +1607 Lava Semiconductor Manufacturing Inc +1608 Automated Wagering International +1609 Scimetric Instruments Inc 1668 Action Tec Electronics Inc +1813 Ambient Technologies Inc 1a08 Sierra semiconductor 0000 SC15064 1b13 Jaton Corp @@ -3216,13 +4143,19 @@ 270b Xantel Corporation 270f Chaintech Computer Co. Ltd 2711 AVID Technology Inc. +2a15 3D Vision(???) 3000 Hansol Electronics Inc. 3142 Post Impression Systems. 3388 Hint Corp 8011 VXPro II Chipset + 3388 8011 VXPro II Chipset CPU to PCI Bridge 8012 VXPro II Chipset + 3388 8012 VXPro II Chipset PCI to ISA Bridge 8013 VXPro II Chipset + 3388 8013 VXPro II Chipset EIDE Controller +3411 Quantum Designs (H.K.) Inc 3513 ARCOM Control Systems Ltd +38ef 4Links 3d3d 3DLabs 0001 GLINT 300SX 0002 GLINT 500TX @@ -3247,6 +4180,9 @@ 3d04 Permedia ffff Glint VGA 4005 Avance Logic Inc. + 0300 ALS300 PCI Audio Device + 0308 ALS300+ PCI Audio Device + 0309 PCI Input Controller 1064 ALG-2064 2064 ALG-2064i 2128 ALG-2364A GUI Accelerator @@ -3256,7 +4192,11 @@ 2364 ALG-2364A 2464 ALG-2464 2501 ALG-2564A/25128A + 4000 ALS4000 Audio Chipset + 4005 4000 ALS4000 Audio Chipset 4033 Addtron Technology Co, Inc. +4143 Digital Equipment Corp +416c Aladdin Knowledge Systems 4444 Internext Compression Inc 4468 Bridgeport machines 4594 Cogetec Informatique Inc @@ -3267,10 +4207,13 @@ 4978 Axil Computer Inc 4a14 NetVin 5000 NV5000SC + 4a14 5000 RT8029-Based Ethernet Adapter 4b10 Buslogic Inc. 4c48 LUNG HWA Electronics +4ca1 Seanix Technology Inc 4d51 MediaQ Inc. 0200 MQ-200 +4d54 Microtechnica Co Ltd 4ddc ILC Data Device Corp 5053 Voyetra Technologies 2010 Daytona Audio Adapter @@ -3314,7 +4257,9 @@ 88f2 86c968 [Vision 968 VRAM] rev 2 88f3 86c968 [Vision 968 VRAM] rev 3 8900 86c755 [Trio 64V2/DX] + 5333 8900 86C775 Trio64V2/DX 8901 Trio 64V2/DX or /GX + 5333 8901 86C775 Trio64V2/DX, 86C785 Trio64V2/GX 8902 Plato/PX 8903 Trio 3D business multimedia 8904 Trio 64 3D @@ -3341,7 +4286,9 @@ 8a13 86c368 [Trio 3D/2X] 5333 8a13 Trio3D/2X 8a20 86c794 [Savage 3D] + 5333 8a20 86C391 Savage3D 8a21 86c795 [Savage 3D/MV] + 5333 8a21 86C390 Savage3D/MV 8a22 Savage 4 105d 0018 SR9 8Mb SDRAM 105d 002a SR9 Pro 16Mb SDRAM @@ -3349,20 +4296,42 @@ 105d 092f SR9 Pro+ 16Mb SGRAM 1092 4207 Stealth III S540 1092 4800 Stealth III S540 + 1092 4807 SpeedStar A90 1092 4808 Stealth III S540 + 1092 4809 Stealth III S540 1092 480e Stealth III S540 1092 4904 Stealth III S520 + 1092 4905 SpeedStar A200 1092 4a09 Stealth III S540 1092 4a0b Stealth III S540 Xtreme 1092 4a0f Stealth III S540 1092 4e01 Stealth III S540 1102 101d 3d Blaster Savage 4 1102 101e 3d Blaster Savage 4 + 5333 8100 86C394-397 Savage4 SDRAM 100 + 5333 8110 86C394-397 Savage4 SDRAM 110 + 5333 8125 86C394-397 Savage4 SDRAM 125 + 5333 8143 86C394-397 Savage4 SDRAM 143 + 5333 8a22 86C394-397 Savage4 + 5333 8a2e 86C394-397 Savage4 32bit + 5333 9125 86C394-397 Savage4 SGRAM 125 + 5333 9143 86C394-397 Savage4 SGRAM 143 8a23 Savage 4 8c00 ViRGE/M3 8c01 ViRGE/MX 8c02 ViRGE/MX+ 8c03 ViRGE/MX+MV + 8c10 86C270-294 Savage/MX-/IX + 8c12 86C270-294 Savage/MX-/IX + 9102 86C410 Savage 2000 + 1092 5932 Viper II Z200 + 1092 5934 Viper II Z200 + 1092 5952 Viper II Z200 + 1092 5954 Viper II Z200 + 1092 5a35 Viper II Z200 + 1092 5a37 Viper II Z200 + 1092 5a55 Viper II Z200 + 1092 5a57 Viper II Z200 ca00 SonicVibes 544c Teralogic Inc 5455 Technische University Berlin @@ -3402,6 +4371,7 @@ 1014 0119 Netfinity Gigabit Ethernet SX Adapter 8086 1000 EtherExpress PRO/1000 Gigabit Server Adapter 1030 82559 InBusiness 10/100 + 1161 82806AA PCI64 Hub Advanced Programmable Interrupt Controller 1209 82559ER 1221 82092AA_0 1222 82092AA_1 @@ -3426,10 +4396,11 @@ 1033 8000 PC-9821X-B06 1033 8016 PK-UG-X006 1033 801f PK-UG-X006 - 103c 10C0 Ethernet Pro 10/100TX - 103c 10C3 Ethernet Pro 10/100TX + 103c 10c0 Ethernet Pro 10/100TX + 103c 10c3 Ethernet Pro 10/100TX 103c 1200 Ethernet Pro 10/100TX 10c3 1100 SmartEther100 SC1100 + 1179 0002 PCI FastEther LAN on Docker 1259 2560 AT-2560 100 1259 2561 AT-2560 100 FX Ethernet Adapter 1266 0001 NE10/100 Adapter @@ -3448,7 +4419,7 @@ 8086 000d EtherExpress PRO/100+ Alert On LAN II* Adapter 8086 000e EtherExpress PRO/100+ Management Adapter with Alert On LAN* 8086 1009 EtherExpress PRO/100+ Server Adapter - 8086 100C EtherExpress PRO/100+ Server Adapter (PILA8470B) + 8086 100c EtherExpress PRO/100+ Server Adapter (PILA8470B) 8086 10f0 EtherExpress PRO/100+ Dual Port Adapter 8086 200d EtherExpress PRO/100 Cardbus 8086 200e EtherExpress PRO/100 LAN+V90 Cardbus Modem @@ -3465,21 +4436,30 @@ 1239 82371FB 123b 82380PB 123c 82380AB + 123d 683053 Programmable Interrupt Device 1240 752 AGP 124b 82380FB 1250 430HX - 82439HX TXC [Triton II] + 1360 82806AA PCI64 Hub PCI Bridge + 1361 82806AA PCI64 Hub Controller (HRes) 1960 80960RP [i960RP Microprocessor] 101e 0438 MegaRaid 438 101e 0466 MegaRaid 466 - 103c 10C6 MegaRaid 438 - 103c 10C7 MegaRaid T5 + 103c 10c6 MegaRaid 438 + 103c 10c7 MegaRaid T5 1111 1111 MegaRaid 466 - 113c 03A2 MegaRaid + 113c 03a2 MegaRaid + 1a21 82840 840 (Carmel) Chipset Host Bridge (Hub A) + 1a23 82840 840 (Carmel) Chipset AGP Bridge + 1a24 82840 840 (Carmel) Chipset PCI Bridge (Hub B) 2410 82801AA 82810 Chipset ISA Bridge (LPC) 2411 82801AA 82810 Chipset IDE 2412 82801AA 82810 Chipset USB 2413 82801AA 82810 Chipset SMBus 2415 82801AA 82810 AC'97 Audio + 11d4 0040 SoundMAX Integrated Digital Audio + 11d4 0048 SoundMAX Integrated Digital Audio + 11d4 5340 SoundMAX Integrated Digital Audio 2416 82801AA 82810 AC'97 Modem 2418 82801AA 82810 PCI Bridge 2420 82801AB 82810 Chipset ISA Bridge (LPC) @@ -3487,10 +4467,21 @@ 2422 82801AB 82810 Chipset USB 2423 82801AB 82810 Chipset SMBus 2425 82801AB 82810 AC'97 Audio + 11d4 0040 SoundMAX Integrated Digital Audio + 11d4 0048 SoundMAX Integrated Digital Audio 2426 82801AB 82810 AC'97 Modem 2428 82801AB 82810 PCI Bridge + 2500 82820 820 (Camino) Chipset Host Bridge (MCH) + 1043 801c P3C-2000 system chipset + 2501 82820 820 (Camino) Chipset Host Bridge (MCH) + 1043 801c P3C-2000 system chipset + 250b 82820 820 (Camino) Chipset Host Bridge + 250f 82820 820 (Camino) Chipset PCI to AGP Bridge + 2520 82805AA MTH Memory Translator Hub + 2521 82804AA MRH-S Memory Repeater Hub for SDRAM 5200 EtherExpress PRO/100 5201 EtherExpress PRO/100 + 8086 0001 EtherExpress PRO/100 Server Ethernet Adapter 7000 82371SB PIIX3 ISA [Natoma/Triton II] 7010 82371SB PIIX3 IDE [Natoma/Triton II] 7020 82371SB PIIX3 USB [Natoma/Triton II] @@ -3506,6 +4497,7 @@ 7123 82810-DC100 CGC [Chipset Graphics Controller] 7124 82810E GMCH [Graphics Memory Controller Hub] 7125 82810E CGC [Chipset Graphics Controller] + 7126 82810 810 Chipset Host Bridge and Memory Controller Hub 7180 440LX/EX - 82443LX/EX Host bridge 7181 440LX/EX - 82443LX/EX AGP bridge 7190 440BX/ZX - 82443BX/ZX Host bridge @@ -3513,11 +4505,22 @@ 7191 440BX/ZX - 82443BX/ZX AGP bridge 7192 440BX/ZX - 82443BX/ZX Host bridge (AGP disabled) 0e11 0460 Armada 1700 Laptop System Chipset + 7194 82440MX I/O Controller + 7195 82440MX AC'97 Audio Controller + 10cf 1099 QSound_SigmaTel Stac97 PCI Audio + 11d4 0040 SoundMAX Integrated Digital Audio + 11d4 0048 SoundMAX Integrated Digital Audio + 7198 82440MX PCI to ISA Bridge + 7199 82440MX EIDE Controller + 719a 82440MX USB Universal Host Controller + 719b 82440MX Power Management Controller 71a0 440GX - 82443GX Host bridge 71a1 440GX - 82443GX AGP bridge 71a2 440GX - 82443GX Host bridge (AGP disabled) + 7600 82372FB PCI to ISA Bridge 7601 82372FB PIIX4 IDE 7602 82372FB [PCI-to-USB UHCI] + 7603 82372FB System Management Bus Controller 7800 i740 1092 0100 Stealth II G460 8086 0100 Intel740 Graphics Accelerator @@ -3542,6 +4545,7 @@ 3b78 AHA-4844W/4844UW 5075 AIC-755x 5078 AHA-7850 + 9004 7850 AHA-2904/Integrated AIC-7850 5175 AIC-755x 5178 AIC-7851 5275 AIC-755x @@ -3560,10 +4564,10 @@ 5900 ANA-5910/5930/5940 ATM155 & 25 LAN Adapter 5905 ANA-5910A/5930A/5940A ATM Adapter 6038 AIC-3860 -# FIXME: This is a cardbus card. The declaration may be duplicative. 6075 AIC-1480 / APA-1480 6078 AIC-7860 6178 AIC-7861 + 9004 7861 AHA-2940AU Single 6278 AIC-7860 6378 AIC-7860 6478 AIC-786 @@ -3593,6 +4597,9 @@ 7678 AHA-4944W/UW / 7876 7778 AIC-787x 7810 AIC-7810 + 7815 AIC-7815 RAID+Memory Controller IC + 9004 7815 ARO-1130U2 RAID Controller + 9004 7840 AIC-7815 RAID+Memory Controller IC 7850 AIC-7850 7855 AHA-2930 7860 AIC-7860 @@ -3608,16 +4615,20 @@ 7893 AIC-789x 7894 AIC-789x 7895 AHA-2940U/UW / AHA-39xx / AIC-7895 + 9004 7895 AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B 7896 AIC-789x 7897 AIC-789x 8078 AIC-7880U + 9004 7880 AIC-7880P Ultra/Ultra Wide SCSI Chipset 8178 AIC-7881U + 9004 7881 AHA-2940UW SCSI Host Adapter 8278 AHA-3940U/UW / AIC-7882U 8378 AHA-3940U/UW / AIC-7883U 8478 AHA-294x / AIC-7884U 8578 AHA-3944U / AHA-3944UWD / 7885 8678 AHA-4944UW / 7886 8778 AIC-788x + 9004 7887 2940UW Pro Ultra-Wide SCSI Controller 8878 7888 8b78 ABA-1030 ec78 AHA-4944W/UW @@ -3625,13 +4636,18 @@ 0010 AHA-2940U2/W 0011 2930U2 0013 78902 + 9005 0003 AAA-131U2 Array1000 1 Channel RAID Controller 001f AHA-2940U2/W / 7890 + 9005 000f 2940U2W SCSI Controller + 9005 a180 2940U2W SCSI Controller 0020 AIC-7890 002f AIC-7890 0030 AIC-7890 003f AIC-7890 0050 3940U2 0051 3950U2D + 0053 AIC-7896 SCSI Controller + 9005 ffff AIC-7896 SCSI Controller mainboard implementation 005f 7896 0080 7892A 0081 7892B @@ -3643,8 +4659,11 @@ 00cf 7899P 907f Atronics 2015 IDE-2015PL +919a Gigapixel Corp 9412 Holtek 6565 6565 +9699 Omni Media Technology Inc + 6565 6565 a0a0 AOPEN Inc. a0f1 UNISYS Corporation a200 NEC Corporation @@ -3653,14 +4672,17 @@ a304 Sony a727 3Com Corporation aa42 Scitex Digital Video +ac1e Digital Receiver Technology Inc b1b3 Shiva Europe Limited c001 TSI Telsys c0a9 Micron/Crucial Technology c0de Motorola c0fe Motion Engineering, Inc. +ca50 Varian Australia Pty Ltd cafe Chrysalis-ITS cccc Catapult Communications d4d4 Dy4 Systems Inc + 0601 PCI Mezzanine Card d84d Exsys e000 Winbond e000 W89C940 @@ -3669,6 +4691,7 @@ 0059 0001 128k ISDN-S/T Adapter 0059 0003 128k ISDN-U Adapter e4bf EKF Elektronik GmbH +ea01 Eagle Technology eabb Aashima Technology B.V. ecc0 Echo Corporation edd8 ARK Logic Inc @@ -3676,6 +4699,7 @@ a099 2000PV [Stingray] a0a1 2000MT a0a9 2000MI +fa57 Fast Search & Transfer ASA feda Epigram Inc fffe VMWare Inc 0710 Virtual SVGA @@ -3685,9 +4709,9 @@ # List of known device classes, subclasses and programming interfaces # Syntax: -# C class class_name -# subclass subclass_name <-- single tab -# prog-if prog-if_name <-- two tabs +# C class class_name +# subclass subclass_name <-- single tab +# prog-if prog-if_name <-- two tabs C 00 Unclassified device 00 Non-VGA unclassified device @@ -3750,7 +4774,7 @@ 01 BiDir 02 ECP 03 IEEE1284 - FE IEEE1284 Target + fe IEEE1284 Target 02 Multiport serial controller 03 Modem 00 Generic @@ -3788,10 +4812,10 @@ 00 Generic 10 Extended 80 Input device controller -C 0A Docking station +C 0a Docking station 00 Generic Docking Station 80 Docking Station -C 0B Processor +C 0b Processor 00 386 01 486 02 Pentium @@ -3799,7 +4823,7 @@ 20 Power PC 30 MIPS 40 Co-processor -C 0C Serial bus controller +C 0c Serial bus controller 00 FireWire (IEEE 1394) 00 Generic 10 OHCI @@ -3809,17 +4833,17 @@ 00 UHCI 10 OHCI 80 Unspecified - FE USB Device + Fe USB Device 04 Fiber Channel 05 SMBus -C 0D Wireless controller +C 0d Wireless controller 00 IRDA controller 01 Consumer IR controller 10 RF controller 80 Wireless controller -C 0E Intelligent controller +C 0e Intelligent controller 00 I2O -C 0F Satellite communications controller +C 0f Satellite communications controller 00 Satellite TV controller 01 Satellite audio communication controller 03 Satellite voice communication controller diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c --- v2.3.99-pre5/linux/drivers/pcmcia/ds.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/pcmcia/ds.c Fri Apr 21 13:33:00 2000 @@ -669,6 +669,7 @@ /*====================================================================*/ +/* No kernel lock - fine */ static u_int ds_poll(struct file *file, poll_table *wait) { socket_t i = MINOR(file->f_dentry->d_inode->i_rdev); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/jsflash.c linux/drivers/sbus/char/jsflash.c --- v2.3.99-pre5/linux/drivers/sbus/char/jsflash.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/sbus/char/jsflash.c Wed Apr 26 12:13:16 2000 @@ -3,11 +3,15 @@ * * Copyright (C) 1991, 1992 Linus Torvalds (drivers/char/mem.c) * Copyright (C) 1997 Eddie C. Dost (drivers/sbus/char/flash.c) - * Copyright (C) 1999 Pete Zaitcev + * Copyright (C) 1997-2000 Pavel Machek (drivers/block/nbd.c) + * Copyright (C) 1999-2000 Pete Zaitcev * * This driver is used to program OS into a Flash SIMM on * Krups and Espresso platforms. * + * TODO: do not allow erase/programming if file systems are mounted. + * TODO: Erase/program both banks of a 8MB SIMM. + * * It is anticipated that programming an OS Flash will be a routine * procedure. In the same time it is exeedingly dangerous because * a user can program its OBP flash with OS image and effectively @@ -31,23 +35,25 @@ #include #include #include -#if 0 /* P3 from mem.c */ -#include -#include -#include -#include -#include -#include -#endif + +/* + * is controlled from the outside with these definitions. + */ +#define MAJOR_NR JSFD_MAJOR + +#define DEVICE_NAME "jsfd" +#define DEVICE_REQUEST jsfd_do_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) +#define DEVICE_NO_RANDOM + +#include + #include #include #include -#if 0 /* P3 from mem.c */ -#include -#include -#include -#endif #include #include @@ -58,8 +64,23 @@ /* * Our device numbers have no business in system headers. * The only thing a user knows is the device name /dev/jsflash. + * + * Block devices are laid out like this: + * minor+0 - Bootstrap, for 8MB SIMM 0x20400000[0x800000] + * minor+1 - Filesystem to mount, normally 0x20400400[0x7ffc00] + * minor+2 - Whole flash area for any case... 0x20000000[0x01000000] + * Total 3 minors per flash device. + * + * It is easier to have static size vectors, so we define + * a total minor range JSF_MAX, which must cover all minors. */ -#define JSF_MINOR 178 +/* character device */ +#define JSF_MINOR 178 /* 178 is registered with hpa */ +/* block device */ +#define JSF_MAX 3 /* 3 minors wasted total so far. */ +#define JSF_NPART 3 /* 3 minors per flash device */ +#define JSF_PART_BITS 2 /* 2 bits of minors to cover JSF_NPART */ +#define JSF_PART_MASK 0x3 /* 2 bits mask */ /* * Access functions. @@ -86,11 +107,20 @@ /* * soft carrier */ + +struct jsfd_part { + unsigned long dbase; + unsigned long dsize; + int refcnt; +}; + struct jsflash { unsigned long base; unsigned long size; unsigned long busy; /* In use? */ struct jsflash_ident_arg id; + /* int mbase; */ /* Minor base, typically zero */ + struct jsfd_part dv[JSF_NPART]; }; /* @@ -103,6 +133,12 @@ #define JSF_BASE_JK 0x20400000 /* + */ +static int jsfd_blksizes[JSF_MAX]; +static int jsfd_sizes[JSF_MAX]; +static u64 jsfd_bytesizes[JSF_MAX]; + +/* * Let's pretend we may have several of these... */ static struct jsflash jsf0; @@ -112,7 +148,7 @@ * We use the Toggle bit DQ6 (0x40) because it does not * depend on the data value as /DATA bit DQ7 does. * - * XXX Do we need any timeout here? + * XXX Do we need any timeout here? So far it never hanged, beware broken hw. */ static void jsf_wait(unsigned long p) { unsigned int x1, x2; @@ -146,6 +182,73 @@ } /* + */ +static void jsfd_read(char *buf, unsigned long p, size_t togo) { + union byte4 { + char s[4]; + unsigned int n; + } b; + + while (togo >= 4) { + togo -= 4; + b.n = jsf_inl(p); + memcpy(buf, b.s, 4); + p += 4; + buf += 4; + } +} + +static void jsfd_do_request(request_queue_t *q) +{ + struct request *req; + int dev; + struct jsfd_part *jdp; + unsigned long offset; + size_t len; + + for (;;) { + INIT_REQUEST; /* if (QUEUE_EMPTY) return; */ + req = CURRENT; + + dev = MINOR(req->rq_dev); + if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { + end_request(0); + continue; + } + jdp = &jsf0.dv[dev & JSF_PART_MASK]; + + offset = req->sector << 9; + len = req->current_nr_sectors << 9; + if ((offset + len) > jdp->dsize) { + end_request(0); + continue; + } + + if (req->cmd == WRITE) { + printk(KERN_ERR "jsfd: write\n"); + end_request(0); + continue; + } + if (req->cmd != READ) { + printk(KERN_ERR "jsfd: bad req->cmd %d\n", req->cmd); + end_request(0); + continue; + } + + if ((jdp->dbase & 0xff000000) != 0x20000000) { + printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase); + end_request(0); + continue; + } + +/* printk("jsfd%d: read buf %p off %x len %x\n", dev, req->buffer, (int)offset, (int)len); */ /* P3 */ + jsfd_read(req->buffer, jdp->dbase + offset, len); + + end_request(1); + } +} + +/* * The memory devices use the full 32/64 bits of the offset, and so we cannot * check against negative addresses: they are ok. The return value is weird, * though, in that case (0). @@ -301,7 +404,7 @@ if (verify_area(VERIFY_READ, uptr, togo)) return -EFAULT; while (togo != 0) { - --togo; + togo -= 4; copy_from_user(&b.s[0], uptr, 4); jsf_write4(p, b.n); p += 4; @@ -316,6 +419,8 @@ { int error = -ENOTTY; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; switch (cmd) { case JSFLASH_IDENT: if (verify_area(VERIFY_WRITE, (void *)arg, JSFIDSZ)) @@ -334,6 +439,34 @@ return error; } +static int jsfd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int dev; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!inode) + return -EINVAL; + if ((dev = MINOR(inode->i_rdev)) >= JSF_MAX) return -ENODEV; + + switch (cmd) { + case BLKGETSIZE: + return put_user(jsfd_bytesizes[dev] >> 9, (long *) arg); + +#if 0 + case BLKROSET: + case BLKROGET: + case BLKSSZGET: + return blk_ioctl(inode->i_rdev, cmd, arg); +#endif + + /* case BLKFLSBUF: */ /* Program, then read, what happens? Stale? */ + default: ; + } + return -ENOTTY; +} + static int jsf_mmap(struct file * file, struct vm_area_struct * vma) { return -ENXIO; @@ -350,6 +483,26 @@ return 0; /* XXX What security? */ } +static int jsfd_open(struct inode *inode, struct file *file) +{ + struct jsfd_part *jdp; + int dev; + + if (!inode) + return -EINVAL; + dev = MINOR(inode->i_rdev); + if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { + printk(KERN_ALERT "jsfd_open: illegal minor %d\n", dev); + return -ENODEV; + } + + jdp = &jsf0.dv[dev]; + jdp->refcnt++; + + MOD_INC_USE_COUNT; + return 0; +} + static int jsf_release(struct inode *inode, struct file *file) { @@ -359,6 +512,30 @@ return 0; } +static int jsfd_release(struct inode *inode, struct file *file) +{ + struct jsfd_part *jdp; + int dev; + + if (!inode) + return -ENODEV; + dev = MINOR(inode->i_rdev); + if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { + printk(KERN_ALERT "jsfd_release: illegal minor %d\n", dev); + return -ENODEV; + } + + jdp = &jsf0.dv[dev]; + if (jdp->refcnt <= 0) { + printk(KERN_ALERT "jsfd_release: bad ref on minor %d\n", dev); + } else { + --jdp->refcnt; + } + /* N.B. Doesn't lo->file need an fput?? */ + MOD_DEC_USE_COUNT; + return 0; +} + static struct file_operations jsf_fops = { llseek: jsf_lseek, read: jsf_read, @@ -371,37 +548,90 @@ static struct miscdevice jsf_dev = { JSF_MINOR, "jsflash", &jsf_fops }; +static struct block_device_operations jsfd_fops = { + open: jsfd_open, + release: jsfd_release, + ioctl: jsfd_ioctl, +}; + EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int __init jsflash_init(void) -#endif +int jsflash_init(void) { int rc; + struct jsflash *jsf; + int node; char banner[128]; + struct linux_prom_registers reg0; - /* FIXME: Really autodetect things */ - prom_getproperty(prom_root_node, "banner-name", banner, 128); - if (strcmp (banner, "JavaStation-NC") && strcmp (banner, "JavaStation-E")) - return -ENXIO; - - /* extern enum sparc_cpu sparc_cpu_model; */ /* in */ - if (sparc_cpu_model == sun4m && jsf0.base == 0) { - /* XXX Autodetect */ + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "flash-memory"); + if (node != 0 && node != -1) { + if (prom_getproperty(node, "reg", + (char *)®0, sizeof(reg0)) == -1) { + printk("jsflash: no \"reg\" property\n"); + return -ENXIO; + } + if (reg0.which_io != 0) { + printk("jsflash: bus number nonzero: 0x%x:%x\n", + reg0.which_io, reg0.phys_addr); + return -ENXIO; + } /* - * We do not want to use PROM properties; - * They are faked by PROLL anyways. + * Flash may be somewhere else, for instance on Ebus. + * So, don't do the following check for IIep flash space. */ - jsf0.base = JSF_BASE_JK; - jsf0.size = 0x00800000; /* 8M */ +#if 0 + if ((reg0.phys_addr >> 24) != 0x20) { + printk("jsflash: suspicious address: 0x%x:%x\n", + reg0.which_io, reg0.phys_addr); + return -ENXIO; + } +#endif + if ((int)reg0.reg_size <= 0) { + printk("jsflash: bad size 0x%x\n", (int)reg0.reg_size); + return -ENXIO; + } + } else { + /* XXX Remove this code once PROLL ID12 got widespread */ + printk("jsflash: no /flash-memory node, use PROLL >= 12\n"); + prom_getproperty(prom_root_node, "banner-name", banner, 128); + if (strcmp (banner, "JavaStation-NC") != 0 && + strcmp (banner, "JavaStation-E") != 0) { + return -ENXIO; + } + reg0.which_io = 0; + reg0.phys_addr = 0x20400000; + reg0.reg_size = 0x00800000; + } + + /* Let us be really paranoid for modifications to probing code. */ + /* extern enum sparc_cpu sparc_cpu_model; */ /* in */ + if (sparc_cpu_model != sun4m) { + /* We must be on sun4m because we use MMU Bypass ASI. */ + return -ENXIO; + } + + if (jsf0.base == 0) { + jsf = &jsf0; + + jsf->base = reg0.phys_addr; + jsf->size = reg0.reg_size; - jsf0.id.off = JSF_BASE_ALL; - jsf0.id.size = 0x01000000; /* 16M - all segments */ - strcpy(jsf0.id.name, "Krups_all"); + /* XXX Redo the userland interface. */ + jsf->id.off = JSF_BASE_ALL; + jsf->id.size = 0x01000000; /* 16M - all segments */ + strcpy(jsf->id.name, "Krups_all"); + + jsf->dv[0].dbase = jsf->base; + jsf->dv[0].dsize = jsf->size; + jsf->dv[1].dbase = jsf->base + 1024; + jsf->dv[1].dsize = jsf->size - 1024; + jsf->dv[2].dbase = JSF_BASE_ALL; + jsf->dv[2].dsize = 0x01000000; - printk("Espresso Flash @0x%lx\n", jsf0.base); + printk("Espresso Flash @0x%lx [%d MB]\n", jsf->base, + (int) (jsf->size / (1024*1024))); } if ((rc = misc_register(&jsf_dev)) != 0) { @@ -410,12 +640,63 @@ jsf0.base = 0; return rc; } + + return 0; +} + +int jsfd_init(void) { + struct jsflash *jsf; + struct jsfd_part *jdp; + int i; + + if (jsf0.base == 0) { + printk("jsfd_init: no flash\n"); /* P3 */ + return -EIO; + } + + if (register_blkdev(JSFD_MAJOR, "jsfd", &jsfd_fops)) { + printk("jsfd_init: unable to get major number %d\n", + JSFD_MAJOR); + return -EIO; + } + + printk("jsfd0: at major %d\n", MAJOR_NR); /* P3 */ + + blksize_size[JSFD_MAJOR] = jsfd_blksizes; + blk_size[JSFD_MAJOR] = jsfd_sizes; + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + /* blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); */ + for (i = 0; i < JSF_MAX; i++) { + if ((i & JSF_PART_MASK) >= JSF_NPART) continue; + jsf = &jsf0; /* actually, &jsfv[i >> JSF_PART_BITS] */ + jdp = &jsf->dv[i&JSF_PART_MASK]; + + jdp->refcnt = 0; + + jsfd_blksizes[i] = 1024; + jsfd_bytesizes[i] = jdp->dsize; + jsfd_sizes[i] = jsfd_bytesizes[i] >> 10; + register_disk(NULL, MKDEV(JSFD_MAJOR, i), 1, &jsfd_fops, + jsfd_bytesizes[i] >> 9); + set_device_ro(MKDEV(JSFD_MAJOR, i), 1); + } return 0; } #ifdef MODULE -void cleanup_module(void) -{ + +int init_module(void) { + int rc; + + if ((rc = jsflash_init()) == 0) { + jsfd_init(); + return 0; + } + return rc; +} + +void cleanup_module(void) { /* for (all probed units) { } */ if (jsf0.busy) @@ -424,5 +705,7 @@ jsf0.busy = 0; misc_deregister(&jsf_dev); + if (unregister_blkdev(JSFD_MAJOR, "jsfd") != 0) + printk("jsfd: cleanup_module failed\n"); } #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c --- v2.3.99-pre5/linux/drivers/sbus/char/pcikbd.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/sbus/char/pcikbd.c Mon Apr 24 13:59:58 2000 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.44 2000/02/11 04:49:13 davem Exp $ +/* $Id: pcikbd.c,v 1.45 2000/04/24 06:10:19 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,8 @@ static volatile unsigned char acknowledge = 0; static volatile unsigned char resend = 0; +static spinlock_t pcikbd_lock = SPIN_LOCK_UNLOCKED; + unsigned char pckbd_read_mask = KBD_STAT_OBF; extern int pcikbd_init(void); @@ -71,26 +74,18 @@ #define pcikbd_inb(x) inb(x) #define pcikbd_outb(v,x) outb(v,x) -#if 0 /* deadwood */ -static __inline__ unsigned char pcikbd_inb(unsigned long port) -{ - return inb(port); -} - -static __inline__ void pcikbd_outb(unsigned char val, unsigned long port) -{ - outb(val, port); -} -#endif - -static inline void kb_wait(void) +/* Wait for keyboard controller input buffer to drain. + * Must be invoked under the pcikbd_lock. + */ +static void kb_wait(void) { - unsigned long start = jiffies; + unsigned long timeout = 250; do { if(!(pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG) & KBD_STAT_IBF)) return; - } while (jiffies - start < KBC_TIMEOUT); + mdelay(1); + } while (--timeout); } /* @@ -312,8 +307,11 @@ static void pcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; unsigned char status; + spin_lock_irqsave(&pcikbd_lock, flags); + kbd_pt_regs = regs; status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); do { @@ -327,27 +325,45 @@ status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); } while(status & KBD_STAT_OBF); tasklet_schedule(&keyboard_tasklet); + + spin_unlock_irqrestore(&pcikbd_lock, flags); } static int send_data(unsigned char data) { int retries = 3; - unsigned long start; + unsigned long flags; + + spin_lock_irqsave(&pcikbd_lock, flags); do { + unsigned long timeout = 1000; + kb_wait(); - acknowledge = resend = 0; + + acknowledge = 0; + resend = 0; reply_expected = 1; + pcikbd_outb(data, pcikbd_iobase + KBD_DATA_REG); - start = jiffies; do { - if(acknowledge) - return 1; - if(jiffies - start >= KBD_TIMEOUT) - return 0; - } while(!resend); - } while(retries-- > 0); + if (acknowledge) + goto out_ack; + if (resend) + break; + mdelay(1); + } while (--timeout); + if (timeout == 0) + goto out_timeout; + } while (retries-- > 0); + +out_timeout: + spin_unlock_irqrestore(&pcikbd_lock, flags); return 0; + +out_ack: + spin_unlock_irqrestore(&pcikbd_lock, flags); + return 1; } void pcikbd_leds(unsigned char leds) @@ -360,17 +376,23 @@ static int __init pcikbd_wait_for_input(void) { int status, data; - unsigned long start = jiffies; + unsigned long timeout = 1000; do { + mdelay(1); + status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); - if(!(status & KBD_STAT_OBF)) + if (!(status & KBD_STAT_OBF)) continue; + data = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG); - if(status & (KBD_STAT_GTO | KBD_STAT_PERR)) + if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) continue; + return (data & 0xff); - } while(jiffies - start < KBD_INIT_TIMEOUT); + + } while (--timeout > 0); + return -1; } @@ -573,27 +595,12 @@ }; static struct aux_queue *queue; -static int aux_ready = 0; static int aux_count = 0; static int aux_present = 0; #define pcimouse_inb(x) inb(x) #define pcimouse_outb(v,x) outb(v,x) -#if 0 - -static __inline__ unsigned char pcimouse_inb(unsigned long port) -{ - return inb(port); -} - -static __inline__ void pcimouse_outb(unsigned char val, unsigned long port) -{ - outb(val, port); -} - -#endif - /* * Shared subroutines */ @@ -603,11 +610,11 @@ unsigned int result; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&pcikbd_lock, flags); result = queue->buf[queue->tail]; queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - restore_flags(flags); + spin_unlock_irqrestore(&pcikbd_lock, flags); + return result; } @@ -645,17 +652,17 @@ static int poll_aux_status(void) { - int retries=0; + int retries = 0; while ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) { if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) pcimouse_inb(pcimouse_iobase + KBD_DATA_REG); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((5*HZ + 99) / 100); + mdelay(5); retries++; } + return (retries < MAX_RETRIES); } @@ -699,51 +706,38 @@ } /* - * AUX handler critical section start and end. - * - * Only one process can be in the critical section and all keyboard sends are - * deferred as long as we're inside. This is necessary as we may sleep when - * waiting for the keyboard controller and other processes / BH's can - * preempt us. Please note that the input buffer must be flushed when - * aux_end_atomic() is called and the interrupt is no longer enabled as not - * doing so might cause the keyboard driver to ignore all incoming keystrokes. - */ - -static DECLARE_MUTEX(aux_sema4); - -static inline void aux_start_atomic(void) -{ - down(&aux_sema4); - tasklet_disable_nosync(&keyboard_tasklet); - tasklet_unlock_wait(&keyboard_tasklet); -} - -static inline void aux_end_atomic(void) -{ - tasklet_enable(&keyboard_tasklet); - up(&aux_sema4); -} - -/* * Interrupt from the auxiliary device: a character * is waiting in the keyboard/aux controller. */ void pcimouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - int head = queue->head; - int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1); + unsigned long flags; + int head, maxhead; + unsigned char val; - if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF) + spin_lock_irqsave(&pcikbd_lock, flags); + + head = queue->head; + maxhead = (queue->tail - 1) & (AUX_BUF_SIZE - 1); + + if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) != + AUX_STAT_OBF) { + spin_unlock_irqrestore(&pcikbd_lock, flags); return; + } - add_mouse_randomness(queue->buf[head] = pcimouse_inb(pcimouse_iobase + KBD_DATA_REG)); + val = pcimouse_inb(pcimouse_iobase + KBD_DATA_REG); + queue->buf[head] = val; + add_mouse_randomness(val); if (head != maxhead) { head++; - head &= AUX_BUF_SIZE-1; + head &= AUX_BUF_SIZE - 1; } queue->head = head; - aux_ready = 1; + + spin_unlock_irqrestore(&pcikbd_lock, flags); + if (queue->fasync) kill_fasync(queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); @@ -751,10 +745,13 @@ static int aux_release(struct inode * inode, struct file * file) { + unsigned long flags; + aux_fasync(-1, file, 0); if (--aux_count) return 0; - aux_start_atomic(); + + spin_lock_irqsave(&pcikbd_lock, flags); /* Disable controller ints */ aux_write_cmd(AUX_INTS_OFF); @@ -763,7 +760,8 @@ /* Disable Aux device */ pcimouse_outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG); poll_aux_status(); - aux_end_atomic(); + + spin_unlock_irqrestore(&pcikbd_lock, flags); MOD_DEC_USE_COUNT; return 0; @@ -776,17 +774,19 @@ static int aux_open(struct inode * inode, struct file * file) { + unsigned long flags; + if (!aux_present) return -ENODEV; - aux_start_atomic(); - if (aux_count++) { - aux_end_atomic(); + if (aux_count++) return 0; - } - if (!poll_aux_status()) { /* FIXME: Race condition */ + + spin_lock_irqsave(&pcikbd_lock, flags); + + if (!poll_aux_status()) { aux_count--; - aux_end_atomic(); + spin_unlock_irqrestore(&pcikbd_lock, flags); return -EBUSY; } queue->head = queue->tail = 0; /* Flush input queue */ @@ -798,9 +798,10 @@ aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */ aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */ poll_aux_status(); - aux_end_atomic(); - aux_ready = 0; + spin_unlock_irqrestore(&pcikbd_lock, flags); + + return 0; } @@ -812,23 +813,35 @@ size_t count, loff_t *ppos) { ssize_t retval = 0; + unsigned long flags; if (count) { ssize_t written = 0; - aux_start_atomic(); + spin_lock_irqsave(&pcikbd_lock, flags); + do { char c; + + spin_unlock_irqrestore(&pcikbd_lock, flags); + + get_user(c, buffer++); + + spin_lock_irqsave(&pcikbd_lock, flags); + if (!poll_aux_status()) break; - pcimouse_outb(KBD_CCMD_WRITE_MOUSE, pcimouse_iobase + KBD_CNTL_REG); + pcimouse_outb(KBD_CCMD_WRITE_MOUSE, + pcimouse_iobase + KBD_CNTL_REG); if (!poll_aux_status()) break; - get_user(c, buffer++); + pcimouse_outb(c, pcimouse_iobase + KBD_DATA_REG); written++; } while (--count); - aux_end_atomic(); + + spin_unlock_irqrestore(&pcikbd_lock, flags); + retval = -EIO; if (written) { retval = written; @@ -872,7 +885,6 @@ put_user(c, buffer++); i--; } - aux_ready = !queue_empty(); if (count-i) { file->f_dentry->d_inode->i_atime = CURRENT_TIME; return count-i; @@ -885,7 +897,7 @@ static unsigned int aux_poll(struct file *file, poll_table * wait) { poll_wait(file, &queue->proc_list, wait); - if (aux_ready) + if (!queue_empty()) return POLLIN | POLLRDNORM; return 0; } @@ -972,7 +984,9 @@ pckbd_read_mask = AUX_STAT_OBF; misc_register(&psaux_mouse); - aux_start_atomic(); + + spin_lock_irq(&pcikbd_lock); + pcimouse_outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase + KBD_CNTL_REG); aux_write_ack(AUX_RESET); aux_write_ack(AUX_SET_SAMPLE); @@ -987,7 +1001,8 @@ poll_aux_status(); pcimouse_outb(AUX_INTS_OFF, pcimouse_iobase + KBD_DATA_REG); poll_aux_status(); - aux_end_atomic(); + + spin_unlock_irq(&pcikbd_lock); return 0; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c --- v2.3.99-pre5/linux/drivers/sbus/char/sab82532.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/sbus/char/sab82532.c Wed Apr 26 12:13:16 2000 @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.41 2000/03/13 03:54:17 davem Exp $ +/* $Id: sab82532.c,v 1.44 2000/04/26 09:36:32 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -176,12 +176,22 @@ #define NR_EBRG_VALUES (sizeof(ebrg_table)/sizeof(struct ebrg_struct)) -#define SAB82532_MAX_TEC_DELAY 2000 /* 2 ms */ +#define SAB82532_MAX_TEC_TIMEOUT 200000 /* 1 character time (at 50 baud) */ +#define SAB82532_MAX_CEC_TIMEOUT 50000 /* 2.5 TX CLKs (at 50 baud) */ static __inline__ void sab82532_tec_wait(struct sab82532 *info) { - int count = SAB82532_MAX_TEC_DELAY; - while ((readb(&info->regs->r.star) & SAB82532_STAR_TEC) && --count) + int timeout = info->tec_timeout; + + while ((readb(&info->regs->r.star) & SAB82532_STAR_TEC) && --timeout) + udelay(1); +} + +static __inline__ void sab82532_cec_wait(struct sab82532 *info) +{ + int timeout = info->cec_timeout; + + while ((readb(&info->regs->r.star) & SAB82532_STAR_CEC) && --timeout) udelay(1); } @@ -209,8 +219,7 @@ } /* Issue a Transmit Frame command. */ - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_XF, &info->regs->w.cmdr); out: @@ -277,8 +286,7 @@ tmp = readb(&info->regs->rw.rfc); tmp &= ~(SAB82532_RFC_RFDF); writeb(tmp, &info->regs->rw.rfc); - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr); #ifndef __sparc_v9__ @@ -293,8 +301,7 @@ * Reset FIFO to character + status mode. */ writeb(saved_rfc, &info->regs->w.rfc); - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr); } @@ -345,16 +352,19 @@ free_fifo++; } - if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { - count = readb(&info->regs->r.rbcl) & (info->recv_fifo_size - 1); - free_fifo++; - } - /* Issue a FIFO read command in case we where idle. */ if (stat->sreg.isr0 & SAB82532_ISR0_TIME) { - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_RFRD, &info->regs->w.cmdr); + /* Wait for command execution, to catch the TCD below. */ + sab82532_cec_wait(info); + } + + if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { + count = readb(&info->regs->r.rbcl) & (info->recv_fifo_size - 1); + if (count == 0) + count = info->recv_fifo_size; + free_fifo++; } if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { @@ -370,8 +380,7 @@ /* Issue Receive Message Complete command. */ if (free_fifo) { - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_RMC, &info->regs->w.cmdr); } @@ -451,8 +460,7 @@ } /* Issue a Transmit Frame command. */ - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_XF, &info->regs->w.cmdr); if (info->xmit_cnt < WAKEUP_CHARS) @@ -709,18 +717,14 @@ /* * Wait for any commands or immediate characters */ - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); sab82532_tec_wait(info); /* * Clear the FIFO buffers. */ - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr); - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); writeb(SAB82532_CMDR_XRES, &info->regs->w.cmdr); /* @@ -997,10 +1001,15 @@ ebrg |= (ebrg_table[i].m << 6); info->baud = ebrg_table[i].baud; - if (info->baud) + if (info->baud) { info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud; - else + info->tec_timeout = (10 * 1000000) / info->baud; + info->cec_timeout = info->tec_timeout >> 2; + } else { info->timeout = 0; + info->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; + info->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; + } info->timeout += HZ / 50; /* Add .02 seconds of slop */ /* CTS flow control flags */ @@ -1037,8 +1046,7 @@ SAB82532_ISR0_TIME; save_flags(flags); cli(); - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); sab82532_tec_wait(info); writeb(dafo, &info->regs->w.dafo); writeb(ebrg & 0xff, &info->regs->w.bgr); @@ -2092,7 +2100,7 @@ done: if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -2163,7 +2171,7 @@ static inline void __init show_serial_version(void) { - char *revision = "$Revision: 1.41 $"; + char *revision = "$Revision: 1.44 $"; char *version, *p; version = strchr(revision, ' '); @@ -2196,7 +2204,11 @@ memset(&serial_driver, 0, 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 + su_num_ports; serial_driver.num = NR_PORTS; @@ -2267,6 +2279,8 @@ info->custom_divisor = 16; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; + info->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; + info->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; info->x_char = 0; info->event = 0; info->blocked_open = 0; @@ -2550,8 +2564,7 @@ info->flags |= ASYNC_CHECK_CD; save_flags(flags); cli(); - if (readb(&info->regs->r.star) & SAB82532_STAR_CEC) - udelay(1); + sab82532_cec_wait(info); sab82532_tec_wait(info); writeb(dafo, &info->regs->w.dafo); writeb(ebrg & 0xff, &info->regs->w.bgr); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c --- v2.3.99-pre5/linux/drivers/sbus/char/su.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/sbus/char/su.c Mon Apr 24 13:59:58 2000 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.37 2000/03/13 03:54:15 davem Exp $ +/* $Id: su.c,v 1.38 2000/04/22 00:45:16 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2204,7 +2204,7 @@ done: if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -2223,7 +2223,7 @@ */ static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.37 $"; + char *revision = "$Revision: 1.38 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.3.99-pre5/linux/drivers/sbus/char/sunkbd.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/sbus/char/sunkbd.c Mon Apr 24 13:59:58 2000 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -90,6 +91,8 @@ return 0; } +static spinlock_t sunkbd_lock = SPIN_LOCK_UNLOCKED; + /* * global state includes the following, and various static variables * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next. @@ -255,6 +258,7 @@ static void nop_kbd_put_char(unsigned char c) { } static void (*kbd_put_char)(unsigned char) = nop_kbd_put_char; +/* Must be invoked under sunkbd_lock. */ static inline void send_cmd(unsigned char c) { kbd_put_char(c); @@ -429,6 +433,7 @@ e0_keys[scancode - 128]; } +static void __sunkbd_inchar(unsigned char ch, struct pt_regs *regs); void sunkbd_inchar(unsigned char ch, struct pt_regs *regs); static void keyboard_timer (unsigned long ignored); @@ -443,16 +448,17 @@ { unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&sunkbd_lock, flags); /* Auto repeat: send regs = 0 to indicate autorepeat */ - sunkbd_inchar (last_keycode, 0); + __sunkbd_inchar (last_keycode, 0); del_timer (&auto_repeat_timer); if (kbd_rate_ticks) { auto_repeat_timer.expires = jiffies + kbd_rate_ticks; add_timer (&auto_repeat_timer); } - restore_flags(flags); + + spin_unlock_irqrestore(&sunkbd_lock, flags); } #ifndef CONFIG_PCI @@ -460,8 +466,10 @@ #endif /* #define SKBD_DEBUG */ -/* This is our keyboard 'interrupt' routine. */ -void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) +/* This is our keyboard 'interrupt' routine. + * Must run under sunkbd_lock. + */ +static void __sunkbd_inchar(unsigned char ch, struct pt_regs *regs) { unsigned char keycode; char up_flag; /* 0 or SUNKBD_UBIT */ @@ -612,6 +620,15 @@ tasklet_schedule(&keyboard_tasklet); } +void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) +{ + unsigned long flags; + + spin_lock_irqsave(&sunkbd_lock, flags); + __sunkbd_inchar(ch, regs); + spin_unlock_irqrestore(&sunkbd_lock, flags); +} + static void put_queue(int ch) { wake_up(&keypress_wait); @@ -1164,15 +1181,21 @@ static unsigned char sunkbd_ledstate = 0xff; /* undefined */ void sun_kbd_bh(unsigned long dummy) { - unsigned char leds = getleds(); - unsigned char kbd_leds = vcleds_to_sunkbd(leds); + unsigned long flags; + unsigned char leds, kbd_leds; + + spin_lock_irqsave(&sunkbd_lock, flags); + leds = getleds(); + kbd_leds = vcleds_to_sunkbd(leds); if (kbd_leds != sunkbd_ledstate) { ledstate = leds; sunkbd_ledstate = kbd_leds; send_cmd(SKBDCMD_SETLED); send_cmd(kbd_leds); } + + spin_unlock_irqrestore(&sunkbd_lock, flags); } /* Support for keyboard "beeps". */ @@ -1180,7 +1203,11 @@ /* Timer routine to turn off the beep after the interval expires. */ static void sunkbd_kd_nosound(unsigned long __unused) { + unsigned long flags; + + spin_lock_irqsave(&sunkbd_lock, flags); send_cmd(SKBDCMD_BELLOFF); + spin_unlock_irqrestore(&sunkbd_lock, flags); } /* @@ -1195,8 +1222,7 @@ static struct timer_list sound_timer = { NULL, NULL, 0, 0, sunkbd_kd_nosound }; - save_flags(flags); - cli(); + spin_lock_irqsave(&sunkbd_lock, flags); del_timer(&sound_timer); @@ -1209,7 +1235,7 @@ } else send_cmd(SKBDCMD_BELLOFF); - restore_flags(flags); + spin_unlock_irqrestore(&sunkbd_lock, flags); } extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); @@ -1260,6 +1286,7 @@ #define KBD_QSIZE 32 static Firm_event kbd_queue [KBD_QSIZE]; static int kbd_head, kbd_tail; +static spinlock_t kbd_queue_lock = SPIN_LOCK_UNLOCKED; char kbd_opened; static int kbd_active = 0; static DECLARE_WAIT_QUEUE_HEAD(kbd_wait); @@ -1268,16 +1295,22 @@ void push_kbd (int scan) { - int next = (kbd_head + 1) % KBD_QSIZE; + unsigned long flags; + int next; if (scan == KBD_IDLE) return; + + spin_lock_irqsave(&kbd_queue_lock, flags); + next = (kbd_head + 1) % KBD_QSIZE; if (next != kbd_tail){ kbd_queue [kbd_head].id = scan & KBD_KEYMASK; kbd_queue [kbd_head].value=scan & KBD_UP ? VKEY_UP : VKEY_DOWN; kbd_queue [kbd_head].time = xtime; kbd_head = next; } + spin_unlock_irqrestore(&kbd_queue_lock, flags); + if (kb_fasync) kill_fasync (kb_fasync, SIGIO, POLL_IN); wake_up_interruptible (&kbd_wait); @@ -1287,6 +1320,7 @@ kbd_read (struct file *f, char *buffer, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); + unsigned long flags; char *end, *p; /* Return EWOULDBLOCK, because this is what the X server expects */ @@ -1294,9 +1328,11 @@ if (f->f_flags & O_NONBLOCK) return -EWOULDBLOCK; add_wait_queue (&kbd_wait, &wait); - while (kbd_head == kbd_tail && !signal_pending(current)) { - current->state = TASK_INTERRUPTIBLE; - schedule (); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (kbd_head == kbd_tail && !signal_pending(current)) { + schedule(); + goto repeat; } current->state = TASK_RUNNING; remove_wait_queue (&kbd_wait, &wait); @@ -1304,29 +1340,40 @@ /* There is data in the keyboard, fill the user buffer */ end = buffer+count; p = buffer; + spin_lock_irqsave(&kbd_queue_lock, flags); for (; p < end && kbd_head != kbd_tail;){ + Firm_event this_event = kbd_queue[kbd_tail]; + + kbd_tail = (kbd_tail + 1) % KBD_QSIZE; + + spin_unlock_irqrestore(&kbd_queue_lock, flags); + #ifdef CONFIG_SPARC32_COMPAT if (current->thread.flags & SPARC_FLAG_32BIT) { - copy_to_user_ret((Firm_event *)p, &kbd_queue [kbd_tail], - sizeof(Firm_event)-sizeof(struct timeval), -EFAULT); + copy_to_user_ret((Firm_event *)p, &this_event, + sizeof(Firm_event)-sizeof(struct timeval), + -EFAULT); p += sizeof(Firm_event)-sizeof(struct timeval); - __put_user_ret(kbd_queue[kbd_tail].time.tv_sec, (u32 *)p, -EFAULT); + __put_user_ret(this_event.time.tv_sec, (u32 *)p, -EFAULT); p += sizeof(u32); - __put_user_ret(kbd_queue[kbd_tail].time.tv_usec, (u32 *)p, -EFAULT); + __put_user_ret(this_event.time.tv_usec, (u32 *)p, -EFAULT); p += sizeof(u32); } else #endif { - copy_to_user_ret((Firm_event *)p, &kbd_queue [kbd_tail], + copy_to_user_ret((Firm_event *)p, &this_event, sizeof(Firm_event), -EFAULT); p += sizeof (Firm_event); } #ifdef KBD_DEBUG - printk ("[%s]", kbd_queue [kbd_tail].value == VKEY_UP ? "UP" : "DOWN"); + printk ("[%s]", this_event.value == VKEY_UP ? "UP" : "DOWN"); #endif - kbd_tail++; - kbd_tail %= KBD_QSIZE; + + spin_lock_irqsave(&kbd_queue_lock, flags); } + + spin_unlock_irqrestore(&kbd_queue_lock, flags); + return p-buffer; } @@ -1387,7 +1434,9 @@ switch (c) { case SKBDCMD_CLICK: case SKBDCMD_NOCLICK: + spin_lock_irq(&sunkbd_lock); send_cmd(c); + spin_unlock_irq(&sunkbd_lock); return 0; case SKBDCMD_BELLON: kd_mksound(1,0); @@ -1469,7 +1518,11 @@ return 0; kbd_opened = fg_console + 1; + + spin_lock_irq(&kbd_queue_lock); kbd_head = kbd_tail = 0; + spin_unlock_irq(&kbd_queue_lock); + return 0; } @@ -1537,6 +1590,8 @@ if(sunkbd_type == SUNKBD_TYPE2) sunkbd_clickp = 0; + spin_lock_irq(&sunkbd_lock); + if(sunkbd_clickp) { send_cmd(SKBDCMD_CLICK); printk("with keyclick\n"); @@ -1548,6 +1603,8 @@ /* Dork with led lights, then turn them all off */ send_cmd(SKBDCMD_SETLED); send_cmd(0xf); /* All on */ send_cmd(SKBDCMD_SETLED); send_cmd(0x0); /* All off */ + + spin_unlock_irq(&sunkbd_lock); /* Register the /dev/kbd interface */ devfs_register (NULL, "kbd", 0, DEVFS_FL_NONE, diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c --- v2.3.99-pre5/linux/drivers/sbus/char/sunmouse.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/sbus/char/sunmouse.c Mon Apr 24 13:59:58 2000 @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -69,13 +70,13 @@ unsigned char prev_state; /* Previous button state */ int delta_x; /* Current delta-x */ int delta_y; /* Current delta-y */ - int ready; /* set if there if data is available */ int active; /* set if device is open */ int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */ wait_queue_head_t proc_list; struct fasync_struct *fasync; /* The event/stream queue */ + spinlock_t lock; unsigned int head; unsigned int tail; union { @@ -96,14 +97,22 @@ static int push_event (Firm_event *ev) { - int next = (sunmouse.head + 1) % EV_SIZE; + unsigned long flags; + int next, ret; - if (next != sunmouse.tail){ + spin_lock_irqsave(&sunmouse.lock, flags); + + next = (sunmouse.head + 1) % EV_SIZE; + ret = 0; + if (next != sunmouse.tail) { sunmouse.queue.ev [sunmouse.head] = *ev; sunmouse.head = next; - return 1; + ret = 1; } - return 0; + + spin_unlock_irqrestore(&sunmouse.lock, flags); + + return ret; } static int @@ -112,29 +121,32 @@ return sunmouse.head == sunmouse.tail; } -static Firm_event * -get_from_queue (void) +/* Must be invoked under the sunmouse.lock */ +static void get_from_queue (Firm_event *p) { - Firm_event *result; - - result = &sunmouse.queue.ev [sunmouse.tail]; + *p = sunmouse.queue.ev [sunmouse.tail]; sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE; - return result; } static void push_char (char c) { - int next = (sunmouse.head + 1) % STREAM_SIZE; + unsigned long flags; + int next; - if (next != sunmouse.tail){ + spin_lock_irqsave(&sunmouse.lock, flags); + + next = (sunmouse.head + 1) % STREAM_SIZE; + if (next != sunmouse.tail) { #ifdef SMOUSE_DEBUG printk("P<%02x>\n", (unsigned char)c); #endif sunmouse.queue.stream [sunmouse.head] = c; sunmouse.head = next; } - sunmouse.ready = 1; + + spin_unlock_irqrestore(&sunmouse.lock, flags); + if (sunmouse.fasync) kill_fasync (sunmouse.fasync, SIGIO, POLL_IN); wake_up_interruptible (&sunmouse.proc_list); @@ -325,24 +337,26 @@ sunmouse.byte = 69; /* What could cause this? */ return; }; - if (!gen_events){ + + if (!gen_events) { push_char (~sunmouse.button_state & 0x87); push_char (sunmouse.delta_x); push_char (sunmouse.delta_y); return; } + d = bstate ^ pstate; pstate = bstate; - if (d){ - if (d & BUTTON_LEFT){ + if (d) { + if (d & BUTTON_LEFT) { ev.id = MS_LEFT; ev.value = bstate & BUTTON_LEFT; } - if (d & BUTTON_RIGHT){ + if (d & BUTTON_RIGHT) { ev.id = MS_RIGHT; ev.value = bstate & BUTTON_RIGHT; } - if (d & BUTTON_MIDDLE){ + if (d & BUTTON_MIDDLE) { ev.id = MS_MIDDLE; ev.value = bstate & BUTTON_MIDDLE; } @@ -350,25 +364,24 @@ ev.value = ev.value ? VKEY_DOWN : VKEY_UP; pushed += push_event (&ev); } - if (sunmouse.delta_x){ + if (sunmouse.delta_x) { ev.id = LOC_X_DELTA; ev.time = xtime; ev.value = sunmouse.delta_x; pushed += push_event (&ev); sunmouse.delta_x = 0; } - if (sunmouse.delta_y){ + if (sunmouse.delta_y) { ev.id = LOC_Y_DELTA; ev.time = xtime; ev.value = sunmouse.delta_y; pushed += push_event (&ev); } - if(pushed != 0) { + if (pushed != 0) { /* We just completed a transaction, wake up whoever is awaiting * this event. */ - sunmouse.ready = 1; if (sunmouse.fasync) kill_fasync (sunmouse.fasync, SIGIO, POLL_IN); wake_up_interruptible(&sunmouse.proc_list); @@ -379,9 +392,9 @@ static int sun_mouse_open(struct inode * inode, struct file * file) { - if(sunmouse.active++) + if (sunmouse.active++) return 0; - sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0; + sunmouse.delta_x = sunmouse.delta_y = 0; sunmouse.button_state = 0x80; sunmouse.vuid_mode = VUID_NATIVE; return 0; @@ -401,9 +414,7 @@ sun_mouse_close(struct inode *inode, struct file *file) { sun_mouse_fasync (-1, file, 0); - if (--sunmouse.active) - return 0; - sunmouse.ready = 0; + sunmouse.active--; return 0; } @@ -419,49 +430,57 @@ size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); + unsigned long flags; - if (queue_empty ()){ + if (queue_empty ()) { if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; add_wait_queue (&sunmouse.proc_list, &wait); - while (queue_empty () && !signal_pending(current)) { - current->state = TASK_INTERRUPTIBLE; - schedule (); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; } current->state = TASK_RUNNING; remove_wait_queue (&sunmouse.proc_list, &wait); } - if (gen_events){ + if (gen_events) { char *p = buffer, *end = buffer+count; + spin_lock_irqsave(&sunmouse.lock, flags); while (p < end && !queue_empty ()){ + Firm_event this_event; + + get_from_queue(&this_event); + spin_unlock_irqrestore(&sunmouse.lock, flags); + #ifdef CONFIG_SPARC32_COMPAT if (current->thread.flags & SPARC_FLAG_32BIT) { - Firm_event *q = get_from_queue(); - if ((end - p) < ((sizeof(Firm_event) - sizeof(struct timeval) + (sizeof(u32) * 2)))) break; - copy_to_user_ret((Firm_event *)p, q, + copy_to_user_ret((Firm_event *)p, &this_event, sizeof(Firm_event)-sizeof(struct timeval), -EFAULT); p += sizeof(Firm_event)-sizeof(struct timeval); - __put_user_ret(q->time.tv_sec, (u32 *)p, -EFAULT); + __put_user_ret(this_event.time.tv_sec, (u32 *)p, -EFAULT); p += sizeof(u32); - __put_user_ret(q->time.tv_usec, (u32 *)p, -EFAULT); + __put_user_ret(this_event.time.tv_usec, (u32 *)p, -EFAULT); p += sizeof(u32); } else #endif { if ((end - p) < sizeof(Firm_event)) break; - copy_to_user_ret((Firm_event *)p, get_from_queue(), + copy_to_user_ret((Firm_event *)p, &this_event, sizeof(Firm_event), -EFAULT); p += sizeof (Firm_event); } + spin_lock_irqsave(&sunmouse.lock, flags); } - sunmouse.ready = !queue_empty (); + spin_unlock_irqrestore(&sunmouse.lock, flags); file->f_dentry->d_inode->i_atime = CURRENT_TIME; return p-buffer; } else { @@ -470,9 +489,24 @@ if (count < limit) limit = count; for (c = 0; c < limit; c++) { - put_user(sunmouse.queue.stream[sunmouse.tail], buffer); + unsigned char val; + int empty = 0; + + spin_lock_irqsave(&sunmouse.lock, flags); + if (queue_empty()) { + empty = 1; + val = 0; + } else { + val = sunmouse.queue.stream[sunmouse.tail]; + sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE; + } + spin_unlock_irqrestore(&sunmouse.lock, flags); + + if (empty) + break; + + put_user(val, buffer); buffer++; - sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE; } while (c < count) { if (c >= 5) @@ -481,7 +515,6 @@ buffer++; c++; } - sunmouse.ready = !queue_empty(); file->f_dentry->d_inode->i_atime = CURRENT_TIME; return c; } @@ -494,7 +527,7 @@ static unsigned int sun_mouse_poll(struct file *file, poll_table *wait) { poll_wait(file, &sunmouse.proc_list, wait); - if(sunmouse.ready) + if(!queue_empty()) return POLLIN | POLLRDNORM; return 0; } @@ -516,8 +549,11 @@ int value; get_user_ret(value, (int *)arg, -EFAULT); + + spin_lock_irq(&sunmouse.lock); sunmouse.vuid_mode = value; sunmouse.head = sunmouse.tail = 0; + spin_unlock_irq(&sunmouse.lock); } else return -EINVAL; break; @@ -556,10 +592,11 @@ { printk("Sun Mouse-Systems mouse driver version 1.00\n"); - sunmouse.ready = sunmouse.active = 0; + sunmouse.active = 0; misc_register (&sun_mouse_mouse); sunmouse.delta_x = sunmouse.delta_y = 0; sunmouse.button_state = 0x80; init_waitqueue_head(&sunmouse.proc_list); + spin_lock_init(&sunmouse.lock); sunmouse.byte = 69; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c --- v2.3.99-pre5/linux/drivers/sbus/char/zs.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/sbus/char/zs.c Wed Apr 26 12:13:16 2000 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.56 2000/03/12 04:02:11 davem Exp $ +/* $Id: zs.c,v 1.57 2000/04/26 09:36:32 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1928,7 +1928,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.56 $"; + char *revision = "$Revision: 1.57 $"; char *version, *p; version = strchr(revision, ' '); @@ -2415,7 +2415,11 @@ memset(&serial_driver, 0, 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 = NUM_CHANNELS; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v2.3.99-pre5/linux/drivers/scsi/53c7,8xx.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/scsi/53c7,8xx.c Wed Apr 12 09:33:55 2000 @@ -3145,7 +3145,7 @@ save_flags(flags); cli(); for (bp = (struct NCR53c7x0_break *) host->breakpoints; - bp; bp = (struct NCR53c7x0_break *) bp->next); { + bp; bp = (struct NCR53c7x0_break *) bp->next) { sprintf (buf, "scsi%d : bp : success : at %08x, replaces %08x %08x", bp->addr, bp->old[0], bp->old[1]); len = strlen(buf); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.3.99-pre5/linux/drivers/scsi/ChangeLog.ncr53c8xx Tue Apr 11 15:09:18 2000 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Mon Apr 24 16:16:08 2000 @@ -1,3 +1,9 @@ +Mon Apr 24 12:00 2000 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2i + - Return value 1 (instead of 0) from the driver setup routine. + - Let the driver also attach controllers that have been set to + OFF in the NVRAM as it did prior to revision 3.2g. + Sat Apr 1 12:00 2000 Gerard Roudier (groudier@club-internet.fr) * revision 3.2h - Fix a compilation problem on Alpha introduced in version 3.2g. diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx --- v2.3.99-pre5/linux/drivers/scsi/ChangeLog.sym53c8xx Tue Apr 11 15:09:18 2000 +++ linux/drivers/scsi/ChangeLog.sym53c8xx Mon Apr 24 16:16:13 2000 @@ -1,5 +1,11 @@ +Mon Apr 24 12:00 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5m + - Return value 1 (instead of 0) from the driver setup routine. + - Donnot enable PCI DAC cycles. This just broke support for + SYM534C896 on sparc64. Problem fixed by David S. Miller. + Sat Apr 1 12:00 2000 Gerard Roudier (groudier@club-internet.fr) - * revision 1.5l + * version sym53c8xx-1.5l - Tiny change for __sparc__ appeared in 2.3.99-pre4.1 that applies to cache line size (? Probably from David S Miller). - Make sure no data transfer will happen for Scsi_Cmnd requests diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c --- v2.3.99-pre5/linux/drivers/scsi/NCR53C9x.c Tue Nov 23 22:42:21 1999 +++ linux/drivers/scsi/NCR53C9x.c Fri Apr 21 16:08:45 2000 @@ -3542,7 +3542,7 @@ esp->dma_irq_exit(esp); } -#ifndef __SMP__ +#ifndef CONFIG_SMP void esp_intr(int irq, void *dev_id, struct pt_regs *pregs) { struct NCR_ESP *esp; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/README.st linux/drivers/scsi/README.st --- v2.3.99-pre5/linux/drivers/scsi/README.st Tue Mar 14 19:10:40 2000 +++ linux/drivers/scsi/README.st Mon Apr 24 13:54:22 2000 @@ -2,7 +2,7 @@ The driver is currently maintained by Kai M{kisara (email Kai.Makisara@metla.fi) -Last modified: Sat Mar 11 10:34:44 2000 by makisara@kai.makisara.local +Last modified: Sat Apr 22 14:50:25 2000 by makisara@kai.makisara.local BASICS @@ -115,8 +115,8 @@ at the next tape operation. Buffered writes and asynchronous writes may in some rare cases cause -problems in multivolume operations if there is not enough space after -the early-warning mark to flush the driver buffer. +problems in multivolume operations if there is not enough space on the +tape after the early-warning mark to flush the driver buffer. Read ahead for fixed block mode (ST_READ_AHEAD). Filling the buffer is attempted even if the user does not want to get all of the data at @@ -124,11 +124,11 @@ a filemark to truncate a read request or that don't like backspacing. The buffer size is defined (in 1024 byte units) by ST_BUFFER_BLOCKS or -at boot time. If this size is not enough, the driver tries to allocate -a large enough temporary buffer that is released when the device is -closed. Buffer allocation uses chunks of memory having sizes -2^n * (page size). Because of this the actual buffer size may be -larger than the buffer size specified with ST_BUFFER_BLOCKS. +at boot time. If this size is not large enough, the driver tries to +temporarily enlarge the buffer. Buffer allocation uses chunks of +memory having sizes 2^n * (page size). Because of this the actual +buffer size may be larger than the buffer size specified with +ST_BUFFER_BLOCKS. A small number of buffers are allocated at driver initialisation. The maximum number of these buffers is defined by ST_MAX_BUFFERS. The diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.3.99-pre5/linux/drivers/scsi/ide-scsi.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/scsi/ide-scsi.c Thu Apr 13 22:50:32 2000 @@ -547,6 +547,7 @@ idescsi_open, /* open */ idescsi_ide_release, /* release */ NULL, /* media_change */ + NULL, /* revalidate */ NULL, /* pre_reset */ NULL, /* capacity */ NULL, /* special */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c --- v2.3.99-pre5/linux/drivers/scsi/megaraid.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/megaraid.c Mon Apr 24 13:39:34 2000 @@ -2,14 +2,14 @@ * * Linux MegaRAID device driver * - * Copyright 1998 American Megatrends Inc. + * Copyright 1999 American Megatrends Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version : 1.05 + * Version : 1.07b * * Description: Linux device driver for AMI MegaRAID controller * @@ -120,6 +120,14 @@ * also enables the driver to handle large amount of I/O requests for * long duration of time. * + * Version 1.07 + * Removed the usage of uaccess.h file for kernel versions less than + * 2.0.36, as this file is not present in those versions. + * + * Version 1.07b + * The MegaRAID 466 cards with 3.00 firmware lockup and seem to very + * occasionally hang. We check such cards and report them. You can + * get firmware upgrades to flash the board to 3.10 for free. * * BUGS: * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that @@ -135,7 +143,7 @@ #define CRLFSTR "\n" #define IOCTL_CMD_NEW 0x81 -#define MEGARAID_VERSION "v1.05 (October 27, 1999)" +#define MEGARAID_VERSION "v107 (December 22, 1999)" #include @@ -169,7 +177,9 @@ #include #include +#if LINUX_VERSION_CODE > 0x020024 #include +#endif #include "sd.h" #include "scsi.h" @@ -523,7 +533,6 @@ } SCpnt = pScb->SCpnt; - /*freeSCB(megaCfg, pScb);*/ /*delay this to the end of this func.*/ pthru = &pScb->pthru; mbox = (mega_mailbox *) &pScb->mboxData; @@ -638,13 +647,11 @@ if ( islogical ) { lun = (SCpnt->target * 8) + lun; -#if 1 if ( lun > FC_MAX_LOGICAL_DRIVES ){ SCpnt->result = (DID_BAD_TARGET << 16); callDone (SCpnt); return NULL; } -#endif } /*----------------------------------------------------- * @@ -808,7 +815,6 @@ return NULL; } - mboxdata = (u8 *) & pScb->mboxData; mbox = (mega_ioctl_mbox *) & pScb->mboxData; mailbox = (mega_mailbox *) & pScb->mboxData; @@ -843,6 +849,14 @@ } /* else normal (nonpassthru) command */ +#if LINUX_VERSION_CODE > 0x020024 +/* + * usage of the function copy from user is used in case of data more than + * 4KB. This is used only with adapters which supports more than 8 logical + * drives. This feature is disabled on kernels earlier or same as 2.0.36 + * as the uaccess.h file is not available with those kernels. + */ + if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) { /* use external data area for large xfers */ /* If cmnd[0] is set to IOCTL_CMD_NEW then * @@ -868,6 +882,7 @@ copy_from_user(kern_area,user_area,xfer_size); pScb->kern_area = kern_area; } +#endif mbox->cmd = data[0]; mbox->channel = data[1]; @@ -928,7 +943,9 @@ *--------------------------------------------------------------------*/ static void megaraid_isr (int irq, void *devp, struct pt_regs *regs) { +#if LINUX_VERSION_CODE >= 0x20100 IO_LOCK_T +#endif mega_host_config *megaCfg; u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE]; u32 dword=0; @@ -958,10 +975,6 @@ if (dword != 0x10001234) { /* Spurious interrupt */ megaCfg->flag &= ~IN_ISR; -//#if LINUX_VERSION_CODE >= 0x20100 -// IO_UNLOCK; -//#endif -// break; return; } } @@ -970,10 +983,6 @@ if ((byte & VALID_INTR_BYTE) == 0) { /* Spurious interrupt */ megaCfg->flag &= ~IN_ISR; -//#if LINUX_VERSION_CODE >= 0x20100 -// IO_UNLOCK; -//#endif -// break; return; } WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); @@ -1035,9 +1044,6 @@ */ if (pScb->state == SCB_ABORTED) { SCpnt = pScb->SCpnt; -#if DEBUG -printk("megaraid_isr:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt); -#endif } if (pScb->state == SCB_RESET) { SCpnt = pScb->SCpnt; @@ -1135,9 +1141,6 @@ #endif /* Wait until mailbox is free */ -#if 0 - while (mega_busyWaitMbox (megaCfg)) -#endif if (mega_busyWaitMbox (megaCfg)) { printk("Blocked mailbox......!!\n"); udelay(1000); @@ -1190,7 +1193,6 @@ if (pScb) { mega_cmd_done (megaCfg, pScb, mbox->status); -// mega_rundoneq (megaCfg); } WRINDOOR (megaCfg, phys_mbox | 0x2); @@ -1209,7 +1211,6 @@ if (pScb) { mega_cmd_done (megaCfg, pScb, mbox->status); -// mega_rundoneq (megaCfg); } else { TRACE (("Error: NULL pScb!\n")); @@ -1348,7 +1349,6 @@ u32 paddr; u8 retval; - /* Initialize adapter inquiry mailbox*/ paddr = virt_to_bus (megaCfg->mega_buffer); mbox = (mega_mailbox *) mboxData; @@ -1420,25 +1420,6 @@ megaCfg->host->can_queue = MAX_COMMANDS-1; } -#if 0 - int i; - printk (KERN_DEBUG "---- Logical drive info from enquiry3 struct----\n"); - for (i = 0; i < megaCfg->numldrv; i++) { - printk ("%d: size: %d prop: %x state: %x\n", i, - enquiry3Pnt->lDrvSize[i], - enquiry3Pnt->lDrvProp[i], - enquiry3Pnt->lDrvState[i]); - } - - printk (KERN_DEBUG "---- Physical drive info ----\n"); - for (i = 0; i < FC_MAX_PHYSICAL_DEVICES; i++) { - if (i && !(i % 8)) - printk ("\n"); - printk ("%d: %x ", i, enquiry3Pnt->pDrvState[i]); - } - printk ("\n"); -#endif - #ifdef HP /* use HP firmware and bios version encoding */ sprintf (megaCfg->fwVer, "%c%d%d.%d%d", megaCfg->productInfo.FwVer[2], @@ -1584,10 +1565,43 @@ mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox64)); mega_i_query_adapter (megaCfg); - + + if (flag == BOARD_QUARTZ) { + /* Check to see if this is a Dell PERC RAID controller model 466 */ + u16 subsysid, subsysvid; +#if LINUX_VERSION_CODE < 0x20100 + pcibios_read_config_word (pciBus, pciDevFun, + PCI_SUBSYSTEM_VENDOR_ID, + &subsysvid); + pcibios_read_config_word (pciBus, pciDevFun, + PCI_SUBSYSTEM_ID, + &subsysid); +#else + pci_read_config_word (pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid); + pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subsysid); +#endif + if ( (subsysid == 0x1111) && (subsysvid == 0x1111) && + (!strcmp(megaCfg->fwVer,"3.00") || !strcmp(megaCfg->fwVer,"3.01"))) { + printk(KERN_WARNING +"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n" +"megaraid: 3.00 or 3.01. This driver is known to have corruption issues\n" +"megaraid: with those firmware versions on this specific card. In order\n" +"megaraid: to protect your data, please upgrade your firmware to version\n" +"megaraid: 3.10 or later, available from the Dell Technical Support web\n" +"megaraid: site at\n" +"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2489\n"); + megaraid_release (host); +#ifdef MODULE + continue; +#else + while(1) schedule_timeout(1 * HZ); +#endif + } + } + /* Initialize SCBs */ if (mega_initSCB (megaCfg)) { - scsi_unregister (host); + megaraid_release (host); continue; } @@ -1723,9 +1737,6 @@ /* If driver in abort or reset.. cancel this command */ if (megaCfg->flag & IN_ABORT) { -#if DEBUG -printk("mq: got a request while in abort\n"); -#endif SCpnt->result = (DID_ABORT << 16); /* Add Scsi_Command to end of completed queue */ if( megaCfg->qCompletedH == NULL ) { @@ -1742,9 +1753,6 @@ return 0; } else if (megaCfg->flag & IN_RESET) { -#if DEBUG -printk("mq: got a request while in reset\n"); -#endif SCpnt->result = (DID_RESET << 16); /* Add Scsi_Command to end of completed queue */ if( megaCfg->qCompletedH == NULL ) { @@ -1777,16 +1785,9 @@ megaCfg->qPendingT->next = NULL; megaCfg->qPcnt++; - - /* Issue any pending command to the card if not in ISR */ -// if (!(megaCfg->flag & IN_ISR)) { mega_runpendq(megaCfg); -// } -/* - * try running the pend queue, irrespective of the driver's context. - * -cn - */ +#if LINUX_VERSION_CODE > 0x020024 if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW ) { /* user data from external user buffer */ char *user_area; @@ -1804,6 +1805,7 @@ mega_freeSCB(megaCfg, pScb); } +#endif } megaCfg->flag &= ~IN_QUEUE; @@ -1858,9 +1860,6 @@ megaCfg->flag |= IN_ABORT; -#if DEBUG -printk("ma:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt); -#endif for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) { if (pScb->SCpnt == SCpnt) { /* Found an aborting command */ @@ -1912,20 +1911,6 @@ } } -#if 0 - TRACE (("ABORT!!! %.08lx %.02x <%d.%d.%d>\n", - SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, - SCpnt->lun)); - for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) { - if (pScb->SCpnt == SCpnt) { - ser_printk("** %d<%x> %c\n", pScb->SCpnt->pid, pScb->idx+1, - pScb->state == SCB_ACTIVE ? 'A' : 'I'); -#if DEBUG - showMbox(pScb); -#endif - } - } -#endif megaCfg->flag &= ~IN_ABORT; #if DEBUG @@ -1943,12 +1928,11 @@ megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble; megaCfg->qCcnt--; - SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14 + SCpnt->host_scribble = (unsigned char *) NULL ; /* Callback */ callDone (SCpnt); } mega_rundoneq(megaCfg); - return rc; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.3.99-pre5/linux/drivers/scsi/ncr53c8xx.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/scsi/ncr53c8xx.c Mon Apr 24 16:16:13 2000 @@ -73,7 +73,7 @@ */ /* -** March 6 2000, version 3.2g +** April 24 2000, version 3.2i ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -104,7 +104,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2h" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2i" #define SCSI_NCR_DEBUG_FLAGS (0) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c --- v2.3.99-pre5/linux/drivers/scsi/pci2000.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/scsi/pci2000.c Fri Apr 21 16:46:32 2000 @@ -29,8 +29,11 @@ * Revisions 1.12 Mar-26-1999 * - Fixed spinlock and PCI configuration. * + * Revisions 1.20 Mar-27-2000 + * - Added support for dynamic DMA + * ****************************************************************************/ -#define PCI2000_VERSION "1.12" +#define PCI2000_VERSION "1.20" #include @@ -67,32 +70,37 @@ typedef struct { - ULONG address; - ULONG length; + unsigned int address; + unsigned int length; } SCATGATH, *PSCATGATH; typedef struct { - Scsi_Cmnd *SCpnt; - SCATGATH scatGath[16]; - UCHAR tag; + Scsi_Cmnd *SCpnt; + PSCATGATH scatGath; + dma_addr_t scatGathDma; + UCHAR *cdb; + dma_addr_t cdbDma; + UCHAR tag; } DEV2000, *PDEV2000; typedef struct { - USHORT basePort; - USHORT mb0; - USHORT mb1; - USHORT mb2; - USHORT mb3; - USHORT mb4; - USHORT cmd; - USHORT tag; - ULONG irqOwned; - DEV2000 dev[MAX_BUS][MAX_UNITS]; + ULONG basePort; + ULONG mb0; + ULONG mb1; + ULONG mb2; + ULONG mb3; + ULONG mb4; + ULONG cmd; + ULONG tag; + ULONG irqOwned; + struct pci_dev *pdev; + DEV2000 dev[MAX_BUS][MAX_UNITS]; } ADAPTER2000, *PADAPTER2000; #define HOSTDATA(host) ((PADAPTER2000)&host->hostdata) +#define consistentLen (MAX_BUS * MAX_UNITS * (16 * sizeof (SCATGATH) + MAX_COMMAND_SIZE)) static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter @@ -193,20 +201,31 @@ ****************************************************************/ static int BuildSgList (Scsi_Cmnd *SCpnt, PADAPTER2000 padapter, PDEV2000 pdev) { - int z; + int z; + int zc; + struct scatterlist *sg; if ( SCpnt->use_sg ) { - for ( z = 0; z < SCpnt->use_sg; z++ ) + sg = (struct scatterlist *)SCpnt->request_buffer; + zc = pci_map_sg (padapter->pdev, sg, SCpnt->use_sg, scsi_to_pci_dma_dir (SCpnt->sc_data_direction)); + for ( z = 0; z < zc; z++ ) { - pdev->scatGath[z].address = virt_to_bus (((struct scatterlist *)SCpnt->request_buffer)[z].address); - pdev->scatGath[z].length = ((struct scatterlist *)SCpnt->request_buffer)[z].length; + pdev->scatGath[z].address = cpu_to_le32 (sg_dma_address (sg)); + pdev->scatGath[z].length = cpu_to_le32 (sg_dma_len (sg++)); } - outl (virt_to_bus (pdev->scatGath), padapter->mb2); - outl ((SCpnt->use_sg << 24) | SCpnt->request_bufflen, padapter->mb3); + outl (pdev->scatGathDma, padapter->mb2); + outl ((zc << 24) | SCpnt->request_bufflen, padapter->mb3); return FALSE; } - outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2); + if ( !SCpnt->request_bufflen) + { + outl (0, padapter->mb2); + outl (0, padapter->mb3); + return TRUE; + } + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction)); + outl (SCpnt->SCp.have_data_in, padapter->mb2); outl (SCpnt->request_bufflen, padapter->mb3); return TRUE; } @@ -254,23 +273,13 @@ int pun; int bus; int z; -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - int flags; -#else /* version >= v2.1.95 */ unsigned long flags; -#endif /* version >= v2.1.95 */ -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - /* Disable interrupts, if they aren't already disabled. */ - save_flags (flags); - cli (); -#else /* version >= v2.1.95 */ /* * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ spin_lock_irqsave (&io_request_lock, flags); -#endif /* version >= v2.1.95 */ DEB(printk ("\npci2000 recieved interrupt ")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process @@ -306,14 +315,39 @@ { pdev->tag = 0; SCpnt = pdev->SCpnt; - goto irqProceed; + goto unmapProceed; } } } outb_p (0xFF, padapter->tag); // clear the op interrupt outb_p (CMD_DONE, padapter->cmd); // complete the op - goto irq_return;; // done, but, with what? + goto irq_return;; // done, but, with what? + +unmapProceed:; + if ( !bus ) + { + switch ( SCpnt->cmnd[0] ) + { + case SCSIOP_TEST_UNIT_READY: + pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, sizeof (SCpnt->sense_buffer), PCI_DMA_FROMDEVICE); + goto irqProceed; + case SCSIOP_READ_CAPACITY: + pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, 8, PCI_DMA_FROMDEVICE); + goto irqProceed; + case SCSIOP_VERIFY: + case SCSIOP_START_STOP_UNIT: + case SCSIOP_MEDIUM_REMOVAL: + goto irqProceed; + } + } + if ( SCpnt->SCp.have_data_in ) + pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + else + { + if ( SCpnt->use_sg ) + pci_unmap_sg (padapter->pdev, (struct scatterlist *)SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + } irqProceed:; if ( tag & ERR08_TAGGED ) // is there an error here? @@ -359,20 +393,12 @@ OpDone (SCpnt, DID_OK << 16); irq_return:; -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - /* - * Restore the original flags which will enable interrupts - * if and only if they were enabled on entry. - */ - restore_flags (flags); -#else /* version >= v2.1.95 */ /* * Release the I/O spinlock and restore the original flags * which will enable interrupts if and only if they were * enabled on entry. */ spin_unlock_irqrestore (&io_request_lock, flags); -#endif /* version >= v2.1.95 */ } /**************************************************************** * Name: Pci2000_QueueCommand @@ -403,6 +429,7 @@ } SCpnt->scsi_done = done; + SCpnt->SCp.have_data_in = 0; pdev->SCpnt = SCpnt; // Save this command data if ( WaitReady (padapter) ) @@ -428,7 +455,9 @@ outw_p (pun | (lun << 8), padapter->mb0); outw_p (SCpnt->cmd_len << 8, padapter->mb0 + 2); - outl (virt_to_bus (cdb), padapter->mb1); + memcpy (pdev->cdb, cdb, MAX_COMMAND_SIZE); + + outl (pdev->cdbDma, padapter->mb1); if ( BuildSgList (SCpnt, padapter, pdev) ) cmd = CMD_SCSI_THRU; else @@ -469,7 +498,11 @@ goto finished; } else - outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2); + { + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + outl (SCpnt->SCp.have_data_in, padapter->mb2); + } outl (cdb[5], padapter->mb0); outl (cdb[3], padapter->mb3); cmd = CMD_DASD_RAID_RQ; @@ -480,31 +513,35 @@ if ( SCpnt->use_sg ) { - outl (virt_to_bus (((struct scatterlist *)(SCpnt->request_buffer))->address), padapter->mb2); + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, ((struct scatterlist *)SCpnt->request_buffer)->address, + SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction)); } else { - outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2); + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, + SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction)); } + outl (SCpnt->SCp.have_data_in, padapter->mb2); outl (SCpnt->request_bufflen, padapter->mb3); cmd = CMD_DASD_SCSI_INQ; break; case SCSIOP_TEST_UNIT_READY: // test unit ready CDB - outl (virt_to_bus (SCpnt->sense_buffer), padapter->mb2); + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->sense_buffer, sizeof (SCpnt->sense_buffer), PCI_DMA_FROMDEVICE); + outl (SCpnt->SCp.have_data_in, padapter->mb2); outl (sizeof (SCpnt->sense_buffer), padapter->mb3); cmd = CMD_TEST_READY; break; - case SCSIOP_READ_CAPACITY: // read capctiy CDB + case SCSIOP_READ_CAPACITY: // read capacity CDB if ( SCpnt->use_sg ) { - outl (virt_to_bus (((struct scatterlist *)(SCpnt->request_buffer))->address), padapter->mb2); + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, ((struct scatterlist *)(SCpnt->request_buffer))->address, + 8, PCI_DMA_FROMDEVICE); } else - { - outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2); - } + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, 8, PCI_DMA_FROMDEVICE); + outl (SCpnt->SCp.have_data_in, padapter->mb2); outl (8, padapter->mb3); cmd = CMD_DASD_CAP; break; @@ -629,37 +666,23 @@ PADAPTER2000 padapter; int z, zz; int setirq; -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) struct pci_dev *pdev = NULL; -#else - UCHAR pci_bus, pci_device_fn; -#endif + UCHAR *consistent; + dma_addr_t consistentDma; + -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) if ( !pci_present () ) -#else - if ( !pcibios_present () ) -#endif { printk ("pci2000: PCI BIOS not present\n"); return 0; } -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_ROY_1, pdev)) != NULL ) -#else - while ( !pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, found, &pci_bus, &pci_device_fn) ) -#endif { pshost = scsi_register (tpnt, sizeof(ADAPTER2000)); padapter = HOSTDATA(pshost); -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) - padapter->basePort = pci_resource_start (pdev, 1); -#else - pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort); - padapter->basePort &= 0xFFFE; -#endif + padapter->basePort = pdev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4; @@ -668,6 +691,7 @@ padapter->mb4 = padapter->basePort + RTR_MAILBOX + 16; padapter->cmd = padapter->basePort + RTR_LOCAL_DOORBELL; // command register padapter->tag = padapter->basePort + RTR_PCI_DOORBELL; // tag/response register + padapter->pdev = pdev; if ( WaitReady (padapter) ) goto unregister; @@ -676,11 +700,14 @@ if ( WaitReady (padapter) ) goto unregister; -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + consistent = pci_alloc_consistent (pdev, consistentLen, &consistentDma); + if ( !consistent ) + { + printk ("Unable to allocate DMA memory for PCI-2000 controller.\n"); + goto unregister; + } + pshost->irq = pdev->irq; -#else - pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq); -#endif setirq = 1; padapter->irqOwned = 0; for ( z = 0; z < installed; z++ ) // scan for shared interrupts @@ -695,6 +722,7 @@ if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2000", padapter) < 0 ) { printk ("Unable to allocate IRQ for PCI-2000 controller.\n"); + pci_free_consistent (pdev, consistentLen, consistent, consistentDma); goto unregister; } } @@ -710,9 +738,19 @@ for ( zz = 0; zz < MAX_BUS; zz++ ) for ( z = 0; z < MAX_UNITS; z++ ) + { padapter->dev[zz][z].tag = 0; + padapter->dev[zz][z].scatGath = (PSCATGATH)consistent; + padapter->dev[zz][z].scatGathDma = consistentDma; + consistent += 16 * sizeof (SCATGATH); + consistentDma += 16 * sizeof (SCATGATH); + padapter->dev[zz][z].cdb = (UCHAR *)consistent; + padapter->dev[zz][z].cdbDma = consistentDma; + consistent += MAX_COMMAND_SIZE; + consistentDma += MAX_COMMAND_SIZE; + } - printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %X IRQ = %d\n", padapter->basePort, pshost->irq); + printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %lX IRQ = %d\n", padapter->basePort, pshost->irq); printk("Version %s, Compiled %s %s\n\n", PCI2000_VERSION, __DATE__, __TIME__); found++; if ( ++installed < MAXADAPTER ) @@ -774,12 +812,9 @@ PADAPTER2000 padapter = HOSTDATA (pshost); if ( padapter->irqOwned ) -#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70) - free_irq (pshost->irq); -#else /* version >= v1.3.70 */ free_irq (pshost->irq, padapter); -#endif /* version >= v1.3.70 */ - release_region (pshost->io_port, pshost->n_io_port); + pci_free_consistent (padapter->pdev, consistentLen, padapter->dev[0][0].scatGath, padapter->dev[0][0].scatGathDma); + release_region (pshost->io_port, pshost->n_io_port); scsi_unregister(pshost); return 0; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.3.99-pre5/linux/drivers/scsi/pci2220i.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/scsi/pci2220i.c Fri Apr 21 16:46:32 2000 @@ -29,6 +29,9 @@ * - Added code for ATAPI devices. * - Double buffer for scatter/gather support * + * Revision 2.10 March-27-2000 + * - Added support for dynamic DMA + * ****************************************************************************/ //#define DEBUG 1 @@ -57,7 +60,7 @@ #include "psi_dale.h" -#define PCI2220I_VERSION "2.00" +#define PCI2220I_VERSION "2.10" #define READ_CMD IDE_CMD_READ_MULTIPLE #define WRITE_CMD IDE_CMD_WRITE_MULTIPLE #define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master @@ -99,32 +102,33 @@ { USHORT bigD; // identity is a PCI-2240I if true, otherwise a PCI-2220I USHORT atapi; // this interface is for ATAPI devices only - USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer - USHORT regDmaCmdStat; // Byte #1 of DMA command status register - USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA - USHORT regDmaAddrLoc; // 32 bit register for local bus address of DMA - USHORT regDmaCount; // 32 bit register for DMA transfer count - USHORT regDmaMode; // 32 bit register for DMA mode control - USHORT regRemap; // 32 bit local space remap - USHORT regDesc; // 32 bit local region descriptor - USHORT regRange; // 32 bit local range - USHORT regIrqControl; // 16 bit Interrupt enable/disable and status - USHORT regScratchPad; // scratch pad I/O base address - USHORT regBase; // Base I/O register for data space - USHORT regData; // data register I/O address - USHORT regError; // error register I/O address - USHORT regSectCount; // sector count register I/O address - USHORT regLba0; // least significant byte of LBA - USHORT regLba8; // next least significant byte of LBA - USHORT regLba16; // next most significan byte of LBA - USHORT regLba24; // head and most 4 significant bits of LBA - USHORT regStatCmd; // status on read and command on write register - USHORT regStatSel; // board status on read and spigot select on write register - USHORT regFail; // fail bits control register - USHORT regAltStat; // alternate status and drive control register - USHORT basePort; // PLX base I/O port + ULONG regDmaDesc; // address of the DMA discriptor register for direction of transfer + ULONG regDmaCmdStat; // Byte #1 of DMA command status register + ULONG regDmaAddrPci; // 32 bit register for PCI address of DMA + ULONG regDmaAddrLoc; // 32 bit register for local bus address of DMA + ULONG regDmaCount; // 32 bit register for DMA transfer count + ULONG regDmaMode; // 32 bit register for DMA mode control + ULONG regRemap; // 32 bit local space remap + ULONG regDesc; // 32 bit local region descriptor + ULONG regRange; // 32 bit local range + ULONG regIrqControl; // 16 bit Interrupt enable/disable and status + ULONG regScratchPad; // scratch pad I/O base address + ULONG regBase; // Base I/O register for data space + ULONG regData; // data register I/O address + ULONG regError; // error register I/O address + ULONG regSectCount; // sector count register I/O address + ULONG regLba0; // least significant byte of LBA + ULONG regLba8; // next least significant byte of LBA + ULONG regLba16; // next most significan byte of LBA + ULONG regLba24; // head and most 4 significant bits of LBA + ULONG regStatCmd; // status on read and command on write register + ULONG regStatSel; // board status on read and spigot select on write register + ULONG regFail; // fail bits control register + ULONG regAltStat; // alternate status and drive control register + ULONG basePort; // PLX base I/O port USHORT timingMode; // timing mode currently set for adapter USHORT timingPIO; // TRUE if PIO timing is active + struct pci_dev *pcidev; ULONG timingAddress; // address to use on adapter for current timing mode ULONG irqOwned; // owned IRQ or zero if shared UCHAR numberOfDrives; // saved number of drives on this controller @@ -151,6 +155,7 @@ struct timer_list reconTimer; struct timer_list timer; UCHAR *kBuffer; + dma_addr_t kBufferDma; UCHAR reqSense; UCHAR atapiCdb[16]; UCHAR atapiSpecial; @@ -520,7 +525,7 @@ } outl (padapter->timingAddress, padapter->regDmaAddrLoc); - outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci); + outl (padapter->kBufferDma, padapter->regDmaAddrPci); outl (zl, padapter->regDmaCount); outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear } @@ -539,7 +544,7 @@ static void AtapiBusMaster (PADAPTER2220I padapter, UCHAR datain, ULONG length) { outl (padapter->timingAddress, padapter->regDmaAddrLoc); - outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci); + outl (padapter->kBufferDma, padapter->regDmaAddrPci); outl (length, padapter->regDmaCount); if ( datain ) { @@ -1017,10 +1022,6 @@ UCHAR error; padapter->expectingIRQ = 0; -#ifdef DEBUG - printk (" @@@@@@ status: %X @@@@@@@ ", status); - STOP_HERE(); -#endif if ( status & IDE_STATUS_WRITE_FAULT ) { return DID_PARITY << 16; @@ -1154,23 +1155,13 @@ POUR_DEVICE pdev = padapter->pdev; UCHAR status = IDE_STATUS_BUSY; UCHAR temp, temp1; -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - int flags; -#else /* version >= v2.1.95 */ unsigned long flags; -#endif /* version >= v2.1.95 */ -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - /* Disable interrupts, if they aren't already disabled. */ - save_flags (flags); - cli (); -#else /* version >= v2.1.95 */ /* * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ spin_lock_irqsave (&io_request_lock, flags); -#endif /* version >= v2.1.95 */ DEB (printk ("\nPCI2220I: Timeout expired ")); if ( padapter->failinprog ) @@ -1299,20 +1290,12 @@ OpDone (padapter, DecodeError (padapter, status)); timerExpiryDone:; -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - /* - * Restore the original flags which will enable interrupts - * if and only if they were enabled on entry. - */ - restore_flags (flags); -#else /* version >= v2.1.95 */ /* * Release the I/O spinlock and restore the original flags * which will enable interrupts if and only if they were * enabled on entry. */ spin_unlock_irqrestore (&io_request_lock, flags); -#endif /* version >= v2.1.95 */ } /**************************************************************** * Name: SetReconstruct :LOCAL @@ -1353,23 +1336,13 @@ ULONG zl; UCHAR zc; USHORT z; -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - int flags; -#else /* version >= v2.1.95 */ unsigned long flags; -#endif /* version >= v2.1.95 */ -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - /* Disable interrupts, if they aren't already disabled. */ - save_flags (flags); - cli (); -#else /* version >= v2.1.95 */ /* * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ spin_lock_irqsave (&io_request_lock, flags); -#endif /* version >= v2.1.95 */ padapter = (PADAPTER2220I)data; if ( padapter->SCpnt ) @@ -1589,20 +1562,12 @@ padapter->reconPhase = RECON_PHASE_LAST; reconTimerExpiry:; -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - /* - * Restore the original flags which will enable interrupts - * if and only if they were enabled on entry. - */ - restore_flags (flags); -#else /* version >= v2.1.95 */ /* * Release the I/O spinlock and restore the original flags * which will enable interrupts if and only if they were * enabled on entry. */ spin_unlock_irqrestore (&io_request_lock, flags); -#endif /* version >= v2.1.95 */ } /**************************************************************** * Name: Irq_Handler :LOCAL @@ -1629,23 +1594,13 @@ ATAPI_ERROR errora; int z; ULONG zl; -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - int flags; -#else /* version >= v2.1.95 */ unsigned long flags; -#endif /* version >= v2.1.95 */ -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - /* Disable interrupts, if they aren't already disabled. */ - save_flags (flags); - cli (); -#else /* version >= v2.1.95 */ /* * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ spin_lock_irqsave (&io_request_lock, flags); -#endif /* version >= v2.1.95 */ // DEB (printk ("\npci2220i recieved interrupt\n")); @@ -1833,7 +1788,7 @@ } else outl (padapter->timingAddress, padapter->regDmaAddrLoc); - outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci); + outl (padapter->kBufferDma, padapter->regDmaAddrPci); outl (padapter->reconSize * BYTES_PER_SECTOR, padapter->regDmaCount); outb_p (8, padapter->regDmaDesc); // read operation if ( padapter->bigD ) @@ -2069,20 +2024,12 @@ OpDone (padapter, zl); irq_return:; -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - /* - * Restore the original flags which will enable interrupts - * if and only if they were enabled on entry. - */ - restore_flags (flags); -#else /* version >= v2.1.95 */ /* * Release the I/O spinlock and restore the original flags * which will enable interrupts if and only if they were * enabled on entry. */ spin_unlock_irqrestore (&io_request_lock, flags); -#endif /* version >= v2.1.95 */ } /**************************************************************** * Name: Pci2220i_QueueCommand @@ -2421,30 +2368,26 @@ * Parameters: pshost - Pointer to SCSI host data structure. * bigd - PCI-2240I identifier * pcidev - Pointer to device data structure. - * pci_bus - PCI bus number. - * pci_device_fn - PCI device and function number. * * Returns: TRUE if failure to install. * ****************************************************************/ -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, struct pci_dev *pcidev) -#else -static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, UCHAR pci_bus, UCHAR pci_device_fn) -#endif { PADAPTER2220I padapter; int setirq; int z; USHORT zr, zl; + UCHAR *consistent; + dma_addr_t consistentDma; padapter = HOSTDATA(pshost); memset (padapter, 0, sizeof (ADAPTER2220I)); memset (&DaleSetup, 0, sizeof (DaleSetup)); memset (DiskMirror, 0, sizeof (DiskMirror)); - zr = pci_resource_start (pcidev, 1); - zl = pci_resource_start (pcidev, 2); + zr = pcidev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; + zl = pcidev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK; padapter->basePort = zr; padapter->regRemap = zr + RTR_LOCAL_REMAP; // 32 bit local space remap @@ -2465,6 +2408,7 @@ padapter->regStatSel = zl + REG_STAT_SEL; // board status on read and spigot select on write register padapter->regFail = zl + REG_FAIL; padapter->regAltStat = zl + REG_ALT_STAT; + padapter->pcidev = pcidev; if ( bigd ) { @@ -2490,11 +2434,7 @@ if ( !bigd && !padapter->numberOfDrives ) // if no devices on this board return TRUE; -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) pshost->irq = pcidev->irq; -#else - pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq); -#endif setirq = 1; for ( z = 0; z < Installed; z++ ) // scan for shared interrupts { @@ -2513,23 +2453,21 @@ } padapter->irqOwned = pshost->irq; // set IRQ as owned } + if ( padapter->numberOfDrives ) - padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC); + consistent = pci_alloc_consistent (pcidev, SECTORSXFER * BYTES_PER_SECTOR, &consistentDma); else - padapter->kBuffer = kmalloc (ATAPI_TRANSFER, GFP_DMA | GFP_ATOMIC); - if ( !padapter->kBuffer ) + consistent = pci_alloc_consistent (pcidev, ATAPI_TRANSFER, &consistentDma); + if ( !consistent ) { printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n"); -#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70) - free_irq (pshost->irq); -#else /* version >= v1.3.70 */ free_irq (pshost->irq, padapter); -#endif /* version >= v1.3.70 */ return TRUE; } + padapter->kBuffer = consistent; + padapter->kBufferDma = consistentDma; PsiHost[Installed] = pshost; // save SCSI_HOST pointer - pshost->io_port = padapter->basePort; pshost->n_io_port = 0xFF; pshost->unique_id = padapter->regBase; @@ -2571,7 +2509,7 @@ init_timer (&padapter->reconTimer); padapter->reconTimer.function = ReconTimerExpiry; padapter->reconTimer.data = (unsigned long)padapter; - printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", str, padapter->basePort, padapter->regBase, irq); + printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %lX/%lX IRQ = %ld\n", str, padapter->basePort, padapter->regBase, irq); printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__); } /**************************************************************** @@ -2594,38 +2532,20 @@ USHORT raidon; UCHAR spigot1, spigot2; UCHAR device; -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) struct pci_dev *pcidev = NULL; -#else - int found; - UCHAR pci_bus, pci_device_fn; -#endif -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) if ( !pci_present () ) -#else - if ( !pcibios_present () ) -#endif { printk ("pci2220i: PCI BIOS not present\n"); return 0; } -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pcidev)) != NULL ) -#else - found = 0; - while ( !pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, found++, &pci_bus, &pci_device_fn) ) -#endif { pshost = scsi_register (tpnt, sizeof(ADAPTER2220I)); padapter = HOSTDATA(pshost); -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) if ( GetRegs (pshost, FALSE, pcidev) ) -#else - if ( GetRegs (pshost, FALSE, pci_bus, pci_device_fn) ) -#endif goto unregister; pshost->max_id = padapter->numberOfDrives; @@ -2720,21 +2640,12 @@ scsi_unregister (pshost); } -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_BIGD_1, pcidev)) != NULL ) -#else - found = 0; - while ( !pcibios_find_device (VENDOR_PSI, DEVICE_BIGD_1, found++, &pci_bus, &pci_device_fn) ) -#endif { pshost = scsi_register (tpnt, sizeof(ADAPTER2220I)); padapter = HOSTDATA(pshost); -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) if ( GetRegs (pshost, TRUE, pcidev) ) -#else - if ( GetRegs (pshost, TRUE, pci_bus, pci_device_fn) ) -#endif goto unregister1; for ( z = 0; z < BIGD_MAXDRIVES; z++ ) @@ -2966,13 +2877,12 @@ } if ( padapter->irqOwned ) -#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70) - free_irq (pshost->irq); -#else /* version >= v1.3.70 */ free_irq (pshost->irq, padapter); -#endif /* version >= v1.3.70 */ release_region (pshost->io_port, pshost->n_io_port); - kfree (padapter->kBuffer); + if ( padapter->numberOfDrives ) + pci_free_consistent (padapter->pcidev, SECTORSXFER * BYTES_PER_SECTOR, padapter->kBuffer, padapter->kBufferDma); + else + pci_free_consistent (padapter->pcidev, ATAPI_TRANSFER, padapter->kBuffer, padapter->kBufferDma); scsi_unregister(pshost); return 0; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.3.99-pre5/linux/drivers/scsi/scsi.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/scsi/scsi.c Mon Apr 24 18:59:07 2000 @@ -478,6 +478,7 @@ SCpnt->result = 0; SCpnt->underflow = 0; /* Do not flag underflow conditions */ + SCpnt->old_underflow = 0; SCpnt->resid = 0; SCpnt->state = SCSI_STATE_INITIALIZING; SCpnt->owner = SCSI_OWNER_HIGHLEVEL; @@ -906,6 +907,7 @@ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); SCpnt->old_cmd_len = SCpnt->cmd_len; SCpnt->sc_old_data_direction = SCpnt->sc_data_direction; + SCpnt->old_underflow = SCpnt->underflow; /* Start the timer ticking. */ @@ -1011,6 +1013,7 @@ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); SCpnt->old_cmd_len = SCpnt->cmd_len; SCpnt->sc_old_data_direction = SCpnt->sc_data_direction; + SCpnt->old_underflow = SCpnt->underflow; /* Start the timer ticking. */ @@ -1271,6 +1274,7 @@ SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; + SCpnt->underflow = SCpnt->old_underflow; /* * Zero the sense information from the last time we tried @@ -1435,6 +1439,7 @@ SCpnt->old_use_sg = 0; SCpnt->old_cmd_len = 0; SCpnt->underflow = 0; + SCpnt->old_underflow = 0; SCpnt->transfersize = 0; SCpnt->resid = 0; SCpnt->serial_number = 0; @@ -1895,7 +1900,12 @@ } #endif -#ifdef CONFIG_MODULES /* a big #ifdef block... */ +/* + * Some host adapters that are plugging into other subsystems register + * their hosts through the modules entrypoints, and don't use the big + * list in hosts.c. + */ +#if defined(CONFIG_MODULES) || defined(CONFIG_BLK_DEV_IDESCSI) || defined(CONFIG_USB_STORAGE) /* a big #ifdef block... */ /* * This entry point should be called by a loadable module if it is trying diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.3.99-pre5/linux/drivers/scsi/scsi.h Tue Mar 14 19:10:40 2000 +++ linux/drivers/scsi/scsi.h Wed Apr 26 15:30:44 2000 @@ -105,7 +105,7 @@ */ #define ASSERT_LOCK(_LOCK, _COUNT) -#if defined(__SMP__) && defined(CONFIG_USER_DEBUG) +#if defined(CONFIG_SMP) && defined(CONFIG_USER_DEBUG) #undef ASSERT_LOCK #define ASSERT_LOCK(_LOCK,_COUNT) \ { if( (_LOCK)->lock != _COUNT ) \ @@ -756,6 +756,8 @@ unsigned underflow; /* Return error if less than this amount is transfered */ + unsigned old_underflow; /* save underflow here when reusing the + * command for error handling */ unsigned transfersize; /* How much we are guaranteed to transfer with each SCSI transfer diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.3.99-pre5/linux/drivers/scsi/scsi_error.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/scsi_error.c Wed Apr 12 09:47:26 2000 @@ -409,6 +409,7 @@ SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; + SCpnt->underflow = SCpnt->old_underflow; scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command); @@ -466,6 +467,7 @@ SCpnt->use_sg = 0; SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); SCpnt->sc_data_direction = SCSI_DATA_READ; + SCpnt->underflow = 0; scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); @@ -489,6 +491,7 @@ SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; + SCpnt->underflow = SCpnt->old_underflow; /* * Hey, we are done. Let's look to see what happened. @@ -533,9 +536,11 @@ SCpnt->request_bufflen = 256; SCpnt->use_sg = 0; SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); - scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); + SCpnt->underflow = 0; SCpnt->sc_data_direction = SCSI_DATA_NONE; + scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); + /* Last chance to have valid sense data */ if (!scsi_sense_valid(SCpnt)) memcpy((void *) SCpnt->sense_buffer, @@ -556,6 +561,7 @@ SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; + SCpnt->underflow = SCpnt->old_underflow; /* * Hey, we are done. Let's look to see what happened. @@ -736,6 +742,7 @@ */ SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; + SCpnt->underflow = SCpnt->old_underflow; *SClist = SCpnt; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- v2.3.99-pre5/linux/drivers/scsi/scsi_lib.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/scsi/scsi_lib.c Wed Apr 12 09:47:26 2000 @@ -232,6 +232,7 @@ SCpnt->old_use_sg = SCpnt->use_sg; SCpnt->old_cmd_len = SCpnt->cmd_len; SCpnt->sc_old_data_direction = SCpnt->sc_data_direction; + SCpnt->old_underflow = SCpnt->underflow; memcpy((void *) SCpnt->data_cmnd, (const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd)); SCpnt->buffer = SCpnt->request_buffer; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c --- v2.3.99-pre5/linux/drivers/scsi/scsi_merge.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/scsi/scsi_merge.c Mon Apr 24 18:59:07 2000 @@ -282,7 +282,7 @@ * This can come up if you get a MEDIUM_ERROR, for example, * as we will have "completed" all of the sectors up to and * including the bad sector, and the leftover bit is what - * we have to do now. This tends to be a rare occurence, so + * we have to do now. This tends to be a rare occurrence, so * we aren't busting our butts to instantiate separate versions * of this function for the 4 different flag values. We * probably should, however. @@ -320,7 +320,7 @@ * scsi.c allocates for this purpose * min(64,sg_tablesize) entries. */ - if (req->nr_segments >= max_segments && + if (req->nr_segments >= max_segments || req->nr_segments >= SHpnt->sg_tablesize) return 0; req->nr_segments++; @@ -339,8 +339,7 @@ * check if things fit into sg_tablesize. */ if (req->nr_hw_segments >= SHpnt->sg_tablesize || - (req->nr_segments >= max_segments && - req->nr_segments >= SHpnt->sg_tablesize)) + req->nr_segments >= SHpnt->sg_tablesize) return 0; if (req->nr_segments >= max_segments) return 0; @@ -609,7 +608,7 @@ /* If it would not fit into prepared memory space for sg chain, * then don't allow the merge. */ - if (req->nr_segments + next->nr_segments - 1 > max_segments && + if (req->nr_segments + next->nr_segments - 1 > max_segments || req->nr_segments + next->nr_segments - 1 > SHpnt->sg_tablesize) { return 0; } @@ -674,7 +673,7 @@ } dont_combine: #ifdef DMA_CHUNK_SIZE - if (req->nr_segments + next->nr_segments > max_segments && + if (req->nr_segments + next->nr_segments > max_segments || req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) { return 0; } @@ -697,7 +696,7 @@ * Make sure we can fix something that is the sum of the two. * A slightly stricter test than we had above. */ - if (req->nr_segments + next->nr_segments > max_segments && + if (req->nr_segments + next->nr_segments > max_segments || req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) { return 0; } else { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.3.99-pre5/linux/drivers/scsi/scsi_obsolete.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/scsi_obsolete.c Wed Apr 12 09:47:26 2000 @@ -377,6 +377,7 @@ SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; + SCpnt->underflow = SCpnt->old_underflow; } switch (host_byte(result)) { case DID_OK: @@ -637,6 +638,7 @@ SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; + SCpnt->underflow = SCpnt->old_underflow; SCpnt->result = 0; /* * Ugly, ugly. The newer interfaces all @@ -664,6 +666,7 @@ SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; + SCpnt->underflow = SCpnt->old_underflow; /* * The upper layers assume the lock isn't held. We mustn't * disappoint them. When the new error handling code is in diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.3.99-pre5/linux/drivers/scsi/sd.c Tue Apr 11 15:09:18 2000 +++ linux/drivers/scsi/sd.c Thu Apr 13 22:54:26 2000 @@ -166,6 +166,37 @@ return -EFAULT; return 0; } + case HDIO_GETGEO_BIG: + { + struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; + + if(!loc) + return -EINVAL; + + host = rscsi_disks[DEVICE_NR(dev)].device->host; + + /* default to most commonly used values */ + + diskinfo[0] = 0x40; + diskinfo[1] = 0x20; + diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11; + + /* override with calculated, extended default, or driver values */ + + if(host->hostt->bios_param != NULL) + host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)], + dev, + &diskinfo[0]); + else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)], + dev, &diskinfo[0]); + + if (put_user(diskinfo[0], &loc->heads) || + put_user(diskinfo[1], &loc->sectors) || + put_user(diskinfo[2], (unsigned int *) &loc->cylinders) || + put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start)) + return -EFAULT; + return 0; + } case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.3.99-pre5/linux/drivers/scsi/st.c Mon Mar 27 08:08:27 2000 +++ linux/drivers/scsi/st.c Mon Apr 24 13:54:22 2000 @@ -12,7 +12,7 @@ Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Sun Mar 19 22:06:54 2000 by makisara@kai.makisara.local + Last modified: Sun Apr 23 23:41:32 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch Devfs support @@ -791,15 +791,6 @@ (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7], STp->drv_buffer)); } - - if (STp->block_size > (STp->buffer)->buffer_size && - !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) { - printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", - dev, STp->block_size); - scsi_release_request(SRpnt); - retval = (-EIO); - goto err_out; - } STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; } scsi_release_request(SRpnt); @@ -1032,7 +1023,8 @@ { struct inode *inode = filp->f_dentry->d_inode; ssize_t total; - ssize_t i, do_count, blks, retval, transfer; + ssize_t i, do_count, blks, transfer; + ssize_t retval = 0; int write_threshold; int doing_write = 0; static unsigned char cmd[MAX_COMMAND_SIZE]; @@ -1047,6 +1039,9 @@ STp = scsi_tapes[dev]; read_unlock(&st_dev_arr_lock); + if (down_interruptible(&STp->lock)) + return -ERESTARTSYS; + /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it @@ -1054,59 +1049,86 @@ * access to the device is prohibited. */ if (!scsi_block_when_processing_errors(STp->device)) { - return -ENXIO; + retval = (-ENXIO); + goto out; } if (ppos != &filp->f_pos) { /* "A request was outside the capabilities of the device." */ - return -ENXIO; + retval = (-ENXIO); + goto out; } if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) - return (-ENOMEDIUM); + retval = (-ENOMEDIUM); else - return (-EIO); + retval = (-EIO); + goto out; } STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) - return (-ENXIO); + if (!STm->defined) { + retval = (-ENXIO); + goto out; + } if (count == 0) - return 0; + goto out; /* * If there was a bus reset, block further access * to this device. */ - if (STp->device->was_reset) - return (-EIO); + if (STp->device->was_reset) { + retval = (-EIO); + goto out; + } DEB( if (!STp->in_use) { printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); - return (-EIO); + retval = (-EIO); + goto out; } ) /* end DEB */ /* Write must be integral number of blocks */ if (STp->block_size != 0 && (count % STp->block_size) != 0) { printk(KERN_WARNING "st%d: Write not multiple of tape block size.\n", dev); - return (-EIO); + retval = (-EINVAL); + goto out; } if (STp->can_partitions && (retval = update_partition(STp)) < 0) - return retval; + goto out; STps = &(STp->ps[STp->partition]); - if (STp->write_prot) - return (-EACCES); + if (STp->write_prot) { + retval = (-EACCES); + goto out; + } - if (STp->block_size == 0 && - count > (STp->buffer)->buffer_size && - !enlarge_buffer(STp->buffer, count, STp->restr_dma)) - return (-EOVERFLOW); + if (STp->block_size == 0) { + if (STp->max_block > 0 && + (count < STp->min_block || count > STp->max_block)) { + retval = (-EINVAL); + goto out; + } + if (count > (STp->buffer)->buffer_size && + !enlarge_buffer(STp->buffer, count, STp->restr_dma)) { + retval = (-EOVERFLOW); + goto out; + } + } + if ((STp->buffer)->buffer_blocks < 1) { + /* Fixed block mode with too small buffer */ + if (!enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) { + retval = (-EOVERFLOW); + goto out; + } + (STp->buffer)->buffer_blocks = 1; + } if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !st_int_ioctl(STp, MTLOCK, 0)) @@ -1115,19 +1137,21 @@ if (STps->rw == ST_READING) { retval = flush_buffer(STp, 0); if (retval) - return retval; + goto out; STps->rw = ST_WRITING; } else if (STps->rw != ST_WRITING && STps->drv_file == 0 && STps->drv_block == 0) { if ((retval = set_mode_densblk(STp, STm)) < 0) - return retval; + goto out; if (STm->default_compression != ST_DONT_TOUCH && !(STp->compression_changed)) { if (st_compression(STp, (STm->default_compression == ST_YES))) { printk(KERN_WARNING "st%d: Can't set default compression.\n", dev); - if (modes_defined) - return (-EINVAL); + if (modes_defined) { + retval = (-EINVAL); + goto out; + } } } } @@ -1144,22 +1168,30 @@ } } - if (STps->eof == ST_EOM_OK) - return (-ENOSPC); - else if (STps->eof == ST_EOM_ERROR) - return (-EIO); + if (STps->eof == ST_EOM_OK) { + retval = (-ENOSPC); + goto out; + } + else if (STps->eof == ST_EOM_ERROR) { + retval = (-EIO); + goto out; + } /* Check the buffer readability in cases where copy_user might catch the problems after some tape movement. */ if (STp->block_size != 0 && (copy_from_user(&i, buf, 1) != 0 || - copy_from_user(&i, buf + count - 1, 1) != 0)) - return (-EFAULT); + copy_from_user(&i, buf + count - 1, 1) != 0)) { + retval = (-EFAULT); + goto out; + } if (!STm->do_buffer_writes) { #if 0 - if (STp->block_size != 0 && (count % STp->block_size) != 0) - return (-EIO); /* Write must be integral number of blocks */ + if (STp->block_size != 0 && (count % STp->block_size) != 0) { + retval = (-EINVAL); /* Write must be integral number of blocks */ + goto out; + } #endif write_threshold = 1; } else @@ -1191,11 +1223,8 @@ i = append_to_buffer(b_point, STp->buffer, do_count); if (i) { - if (SRpnt != NULL) { - scsi_release_request(SRpnt); - SRpnt = NULL; - } - return i; + retval = i; + goto out; } if (STp->block_size == 0) @@ -1211,8 +1240,10 @@ SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE, STp->timeout, MAX_WRITE_RETRIES, TRUE); - if (!SRpnt) - return (STp->buffer)->syscall_result; + if (!SRpnt) { + retval = (STp->buffer)->syscall_result; + goto out; + } if ((STp->buffer)->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev)); @@ -1267,9 +1298,8 @@ (STp->buffer)->buffer_bytes = 0; STp->dirty = 0; if (count < total) - return total - count; - else - return retval; + retval = total - count; + goto out; } filp->f_pos += do_count; b_point += do_count; @@ -1287,20 +1317,16 @@ STp->dirty = 1; i = append_to_buffer(b_point, STp->buffer, count); if (i) { - if (SRpnt != NULL) { - scsi_release_request(SRpnt); - SRpnt = NULL; - } - return i; + retval = i; + goto out; } filp->f_pos += count; count = 0; } if (doing_write && (STp->buffer)->syscall_result != 0) { - scsi_release_request(SRpnt); - SRpnt = NULL; - return (STp->buffer)->syscall_result; + retval = (STp->buffer)->syscall_result; + goto out; } if (STm->do_async_writes && @@ -1328,18 +1354,24 @@ SRpnt = st_do_scsi(SRpnt, STp, cmd, (STp->buffer)->writing, SCSI_DATA_WRITE, STp->timeout, MAX_WRITE_RETRIES, FALSE); - if (SRpnt == NULL) - return (STp->buffer)->syscall_result; + if (SRpnt == NULL) { + retval = (STp->buffer)->syscall_result; + goto out; + } + SRpnt = NULL; /* Prevent releasing this request! */ - } else if (SRpnt != NULL) { - scsi_release_request(SRpnt); - SRpnt = NULL; } STps->at_sm &= (total == 0); if (total > 0) STps->eof = ST_NOEOF; + retval = total; + + out: + if (SRpnt != NULL) + scsi_release_request(SRpnt); + up(&STp->lock); - return (total); + return retval; } /* Read data from the tape. Returns zero in the normal case, one if the @@ -1516,6 +1548,7 @@ { struct inode *inode = filp->f_dentry->d_inode; ssize_t total; + ssize_t retval = 0; ssize_t i, transfer; int special; Scsi_Request *SRpnt = NULL; @@ -1528,6 +1561,9 @@ STp = scsi_tapes[dev]; read_unlock(&st_dev_arr_lock); + if (down_interruptible(&STp->lock)) + return -ERESTARTSYS; + /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it @@ -1535,41 +1571,65 @@ * access to the device is prohibited. */ if (!scsi_block_when_processing_errors(STp->device)) { - return -ENXIO; + retval = (-ENXIO); + goto out; } if (ppos != &filp->f_pos) { /* "A request was outside the capabilities of the device." */ - return -ENXIO; + retval = (-ENXIO); + goto out; } if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) - return (-ENOMEDIUM); + retval = (-ENOMEDIUM); else - return (-EIO); + retval = (-EIO); + goto out; } STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) - return (-ENXIO); + if (!STm->defined) { + retval = (-ENXIO); + goto out; + } DEB( if (!STp->in_use) { printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); - return (-EIO); + retval = (-EIO); + goto out; } ) /* end DEB */ if (STp->can_partitions && - (total = update_partition(STp)) < 0) - return total; + (retval = update_partition(STp)) < 0) + goto out; - if (STp->block_size == 0 && - count > (STp->buffer)->buffer_size && - !enlarge_buffer(STp->buffer, count, STp->restr_dma)) - return (-EOVERFLOW); + if (STp->block_size == 0) { + if (STp->max_block > 0 && + (count < STp->min_block || count > STp->max_block)) { + retval = (-EINVAL); + goto out; + } + if (count > (STp->buffer)->buffer_size && + !enlarge_buffer(STp->buffer, count, STp->restr_dma)) { + retval = (-EOVERFLOW); + goto out; + } + } + if ((STp->buffer)->buffer_blocks < 1) { + /* Fixed block mode with too small buffer */ + if (!enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) { + retval = (-EOVERFLOW); + goto out; + } + (STp->buffer)->buffer_blocks = 1; + } if (!(STm->do_read_ahead) && STp->block_size != 0 && - (count % STp->block_size) != 0) - return (-EIO); /* Read must be integral number of blocks */ + (count % STp->block_size) != 0) { + retval = (-EINVAL); /* Read must be integral number of blocks */ + goto out; + } if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !st_int_ioctl(STp, MTLOCK, 0)) @@ -1577,9 +1637,9 @@ STps = &(STp->ps[STp->partition]); if (STps->rw == ST_WRITING) { - transfer = flush_buffer(STp, 0); - if (transfer) - return transfer; + retval = flush_buffer(STp, 0); + if (retval) + goto out; STps->rw = ST_READING; } DEB( @@ -1592,9 +1652,11 @@ STps->eof >= ST_EOD_1) { if (STps->eof < ST_EOD) { STps->eof += 1; - return 0; + retval = 0; + goto out; } - return (-EIO); /* EOM or Blank Check */ + retval = (-EIO); /* EOM or Blank Check */ + goto out; } /* Check the buffer writability before any tape movement. Don't alter @@ -1602,8 +1664,10 @@ if (copy_from_user(&i, buf, 1) != 0 || copy_to_user(buf, &i, 1) != 0 || copy_from_user(&i, buf + count - 1, 1) != 0 || - copy_to_user(buf + count - 1, &i, 1) != 0) - return (-EFAULT); + copy_to_user(buf + count - 1, &i, 1) != 0) { + retval = (-EFAULT); + goto out; + } STps->rw = ST_READING; @@ -1615,10 +1679,8 @@ if ((STp->buffer)->buffer_bytes == 0) { special = read_tape(STp, count - total, &SRpnt); if (special < 0) { /* No need to continue read */ - if (SRpnt != NULL) { - scsi_release_request(SRpnt); - } - return special; + retval = special; + goto out; } } @@ -1635,11 +1697,8 @@ (STp->buffer)->buffer_bytes : count - total; i = from_buffer(STp->buffer, buf, transfer); if (i) { - if (SRpnt != NULL) { - scsi_release_request(SRpnt); - SRpnt = NULL; - } - return i; + retval = i; + goto out; } filp->f_pos += transfer; buf += transfer; @@ -1652,11 +1711,6 @@ } /* for (total = 0, special = 0; total < count && !special; ) */ - if (SRpnt != NULL) { - scsi_release_request(SRpnt); - SRpnt = NULL; - } - /* Change the eof state if no data from tape or buffer */ if (total == 0) { if (STps->eof == ST_FM_HIT) { @@ -1673,8 +1727,16 @@ STps->eof = ST_EOD; } else if (STps->eof == ST_FM) STps->eof = ST_NOEOF; + retval = total; + + out: + if (SRpnt != NULL) { + scsi_release_request(SRpnt); + SRpnt = NULL; + } + up(&STp->lock); - return total; + return retval; } @@ -2236,9 +2298,9 @@ return (-EIO); /* Not allowed if data in buffer */ if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && (arg & MT_ST_BLKSIZE_MASK) != 0 && + STp->max_block > 0 && ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block || - (arg & MT_ST_BLKSIZE_MASK) > STp->max_block || - (arg & MT_ST_BLKSIZE_MASK) > st_buffer_size)) { + (arg & MT_ST_BLKSIZE_MASK) > STp->max_block)) { printk(KERN_WARNING "st%d: Illegal block size.\n", dev); return (-EINVAL); } @@ -2745,6 +2807,7 @@ unsigned int cmd_in, unsigned long arg) { int i, cmd_nr, cmd_type, bt; + int retval = 0; unsigned int blk; Scsi_Tape *STp; ST_mode *STm; @@ -2755,10 +2818,14 @@ STp = scsi_tapes[dev]; read_unlock(&st_dev_arr_lock); + if (down_interruptible(&STp->lock)) + return -ERESTARTSYS; + DEB( if (debugging && !STp->in_use) { printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); - return (-EIO); + retval = (-EIO); + goto out; } ) /* end DEB */ STm = &(STp->modes[STp->current_mode]); @@ -2771,7 +2838,8 @@ * access to the device is prohibited. */ if (!scsi_block_when_processing_errors(STp->device)) { - return -ENXIO; + retval = (-ENXIO); + goto out; } cmd_type = _IOC_TYPE(cmd_in); cmd_nr = _IOC_NR(cmd_in); @@ -2779,21 +2847,29 @@ if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { struct mtop mtc; - if (_IOC_SIZE(cmd_in) != sizeof(mtc)) - return (-EINVAL); + if (_IOC_SIZE(cmd_in) != sizeof(mtc)) { + retval = (-EINVAL); + goto out; + } i = copy_from_user((char *) &mtc, (char *) arg, sizeof(struct mtop)); - if (i) - return (-EFAULT); + if (i) { + retval = (-EFAULT); + goto out; + } if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { printk(KERN_WARNING "st%d: MTSETDRVBUFFER only allowed for root.\n", dev); - return (-EPERM); + retval = (-EPERM); + goto out; } if (!STm->defined && - (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) - return (-ENXIO); + (mtc.mt_op != MTSETDRVBUFFER && + (mtc.mt_count & MT_ST_OPTIONS) == 0)) { + retval = (-ENXIO); + goto out; + } if (!(STp->device)->was_reset) { @@ -2822,8 +2898,10 @@ mtc.mt_op == MTCOMPRESSION; } i = flush_buffer(STp, i); - if (i < 0) - return i; + if (i < 0) { + retval = i; + goto out; + } } else { /* * If there was a bus reset, block further access @@ -2835,8 +2913,10 @@ mtc.mt_op != MTRETEN && mtc.mt_op != MTERASE && mtc.mt_op != MTSEEK && - mtc.mt_op != MTEOM) - return (-EIO); + mtc.mt_op != MTEOM) { + retval = (-EIO); + goto out; + } STp->device->was_reset = 0; if (STp->door_locked != ST_UNLOCKED && STp->door_locked != ST_LOCK_FAILS) { @@ -2858,8 +2938,10 @@ st_int_ioctl(STp, MTUNLOCK, 0); /* Ignore result! */ if (mtc.mt_op == MTSETDRVBUFFER && - (mtc.mt_count & MT_ST_OPTIONS) != 0) - return st_set_options(STp, mtc.mt_count); + (mtc.mt_count & MT_ST_OPTIONS) != 0) { + retval = st_set_options(STp, mtc.mt_count); + goto out; + } if (mtc.mt_op == MTSETPART) { if (!STp->can_partitions || @@ -2871,7 +2953,8 @@ if (mtc.mt_count >= STp->nbr_partitions) return (-EINVAL); STp->new_partition = mtc.mt_count; - return 0; + retval = 0; + goto out; } if (mtc.mt_op == MTMKPART) { @@ -2888,39 +2971,52 @@ STp->partition = STp->new_partition = 0; STp->nbr_partitions = 1; /* Bad guess ?-) */ STps->drv_block = STps->drv_file = 0; - return 0; + retval = 0; + goto out; } if (mtc.mt_op == MTSEEK) { i = set_location(STp, mtc.mt_count, STp->new_partition, 0); if (!STp->can_partitions) STp->ps[0].rw = ST_IDLE; - return i; + retval = i; + goto out; } if (STp->can_partitions && STp->ready == ST_READY && - (i = update_partition(STp)) < 0) - return i; + (i = update_partition(STp)) < 0) { + retval = i; + goto out; + } if (mtc.mt_op == MTCOMPRESSION) - return st_compression(STp, (mtc.mt_count & 1)); + retval = st_compression(STp, (mtc.mt_count & 1)); else - return st_int_ioctl(STp, mtc.mt_op, mtc.mt_count); + retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count); + goto out; + } + if (!STm->defined) { + retval = (-ENXIO); + goto out; } - if (!STm->defined) - return (-ENXIO); - if ((i = flush_buffer(STp, FALSE)) < 0) - return i; + if ((i = flush_buffer(STp, FALSE)) < 0) { + retval = i; + goto out; + } if (STp->can_partitions && - (i = update_partition(STp)) < 0) - return i; + (i = update_partition(STp)) < 0) { + retval = i; + goto out; + } if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { struct mtget mt_status; - if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) - return (-EINVAL); + if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) { + retval = (-EINVAL); + goto out; + } mt_status.mt_type = STp->tape_type; mt_status.mt_dsreg = @@ -2972,25 +3068,37 @@ i = copy_to_user((char *) arg, (char *) &(mt_status), sizeof(struct mtget)); - if (i) - return (-EFAULT); + if (i) { + retval = (-EFAULT); + goto out; + } STp->recover_reg = 0; /* Clear after read */ - return 0; + retval = 0; + goto out; } /* End of MTIOCGET */ if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { struct mtpos mt_pos; - if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) - return (-EINVAL); - if ((i = get_location(STp, &blk, &bt, 0)) < 0) - return i; + if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) { + retval = (-EINVAL); + goto out; + } + if ((i = get_location(STp, &blk, &bt, 0)) < 0) { + retval = i; + goto out; + } mt_pos.mt_blkno = blk; i = copy_to_user((char *) arg, (char *) (&mt_pos), sizeof(struct mtpos)); if (i) - return (-EFAULT); - return 0; + retval = (-EFAULT); + goto out; } + up(&STp->lock); return scsi_ioctl(STp->device, cmd_in, (void *) arg); + + out: + up(&STp->lock); + return retval; } @@ -3469,6 +3577,7 @@ tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE; + init_MUTEX(&tpnt->lock); st_template.nr_dev++; write_unlock_irqrestore(&st_dev_arr_lock, flags); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v2.3.99-pre5/linux/drivers/scsi/st.h Tue Mar 14 19:10:40 2000 +++ linux/drivers/scsi/st.h Mon Apr 24 13:54:22 2000 @@ -66,7 +66,8 @@ typedef struct { kdev_t devt; Scsi_Device *device; - struct semaphore sem; + struct semaphore lock; /* For serialization */ + struct semaphore sem; /* For SCSI commands */ ST_buffer *buffer; /* Drive characteristics */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/st_options.h linux/drivers/scsi/st_options.h --- v2.3.99-pre5/linux/drivers/scsi/st_options.h Tue Mar 14 19:10:40 2000 +++ linux/drivers/scsi/st_options.h Mon Apr 24 13:54:22 2000 @@ -3,7 +3,7 @@ Copyright 1995-2000 Kai Makisara. - Last modified: Sat Mar 11 10:32:00 2000 by makisara@kai.makisara.local + Last modified: Sat Apr 22 14:47:02 2000 by makisara@kai.makisara.local */ #ifndef _ST_OPTIONS_H @@ -30,7 +30,7 @@ SENSE. */ #define ST_DEFAULT_BLOCK 0 -/* The tape driver buffer size in kilobytes. */ +/* The tape driver buffer size in kilobytes. Must be non-zero. */ #define ST_BUFFER_BLOCKS 32 /* The number of kilobytes of data in the buffer that triggers an diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c --- v2.3.99-pre5/linux/drivers/scsi/sym53c8xx.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/scsi/sym53c8xx.c Mon Apr 24 16:16:13 2000 @@ -55,7 +55,7 @@ */ /* -** March 6 2000, sym53c8xx 1.5k +** April 24 2000, sym53c8xx 1.5m ** ** Supported SCSI features: ** Synchronous data transfers @@ -84,7 +84,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5l" +#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5m" /* #define DEBUG_896R1 */ #define SCSI_NCR_OPTIMIZE_896 @@ -5241,7 +5241,7 @@ ** 64 bit (53C895A or 53C896) ? */ if (np->features & FE_64BIT) -#if BITS_PER_LONG > 32 +#ifdef SCSI_NCR_USE_64BIT_DAC np->rv_ccntl1 |= (XTIMOD | EXTIBMV); #else np->rv_ccntl1 |= (DDAC); @@ -11152,7 +11152,7 @@ ** code will get more complex later). */ -#if BITS_PER_LONG > 32 +#ifdef SCSI_NCR_USE_64BIT_DAC #define SCATTER_ONE(data, badd, len) \ (data)->addr = cpu_to_scr(badd); \ (data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len); @@ -11845,7 +11845,7 @@ ++cur; } #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */ - return 0; + return 1; } #if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h --- v2.3.99-pre5/linux/drivers/scsi/sym53c8xx_comm.h Tue Apr 11 15:09:19 2000 +++ linux/drivers/scsi/sym53c8xx_comm.h Mon Apr 24 16:16:13 2000 @@ -2178,7 +2178,7 @@ ++cur; } #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */ - return 0; + return 1; } /*=================================================================== @@ -2817,10 +2817,12 @@ if (!ncr_attach (tpnt, attach_count, devp)) attach_count++; } +#if 0 /* Restore previous behaviour of ncr53c8xx driver */ else if (!(driver_setup.use_nvram & 0x80)) printk(KERN_INFO NAME53C8XX ": 53c%s state OFF thus not attached\n", devp->chip.name); +#endif else continue; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h --- v2.3.99-pre5/linux/drivers/scsi/sym53c8xx_defs.h Tue Jan 11 22:31:41 2000 +++ linux/drivers/scsi/sym53c8xx_defs.h Wed Apr 26 15:30:47 2000 @@ -182,6 +182,13 @@ #endif /* + * Should we enable DAC cycles on sparc64 platforms? + * Until further investigation we do not enable it + * anywhere at the moment. + */ +#undef SCSI_NCR_USE_64BIT_DAC + +/* * Sync transfer frequency at startup. * Allow from 5Mhz to 40Mhz default 20 Mhz. */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c --- v2.3.99-pre5/linux/drivers/scsi/tmscsim.c Thu Nov 11 20:11:49 1999 +++ linux/drivers/scsi/tmscsim.c Fri Apr 21 16:08:45 2000 @@ -212,7 +212,7 @@ # if USE_SPINLOCKS == 3 /* both */ -# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 +# if defined (CONFIG_SMP) || DEBUG_SPINLOCKS > 0 # define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; # else # define DC390_LOCKA_INIT @@ -241,7 +241,7 @@ # if USE_SPINLOCKS == 2 /* adapter specific locks */ -# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 +# if defined (CONFIG_SMP) || DEBUG_SPINLOCKS > 0 # define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; # else # define DC390_LOCKA_INIT diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h --- v2.3.99-pre5/linux/drivers/scsi/tmscsim.h Fri Dec 25 16:41:39 1998 +++ linux/drivers/scsi/tmscsim.h Fri Apr 21 16:08:45 2000 @@ -8,6 +8,8 @@ #ifndef _TMSCSIM_H #define _TMSCSIM_H +#include + #define IRQ_NONE 255 #define MAX_ADAPTER_NUM 4 @@ -210,7 +212,7 @@ UCHAR msgin123[4]; UCHAR DCBmap[MAX_SCSI_ID]; -#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0) +#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0) spinlock_t lock; #endif UCHAR sel_timeout; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.3.99-pre5/linux/drivers/sound/Config.in Tue Mar 14 19:10:40 2000 +++ linux/drivers/sound/Config.in Fri Apr 21 16:08:45 2000 @@ -17,6 +17,7 @@ bool ' Separate rear out jack' CONFIG_SOUND_CMPCI_REAR fi fi +dep_tristate ' Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND @@ -97,6 +98,7 @@ bool ' 16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_SOUND_GUS16 bool ' GUS MAX support' CONFIG_SOUND_GUSMAX fi + dep_tristate ' Intel ICH audio support' CONFIG_SOUND_ICH $CONFIG_SOUND_OSS dep_tristate ' Loopback MIDI device support' CONFIG_SOUND_VMIDI $CONFIG_SOUND_OSS dep_tristate ' MediaTrix AudioTrix Pro support' CONFIG_SOUND_TRIX $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_TRIX" = "y" ]; then diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.3.99-pre5/linux/drivers/sound/Makefile Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/Makefile Fri Apr 21 16:08:45 2000 @@ -10,8 +10,7 @@ SUB_DIRS := MOD_SUB_DIRS := MOD_IN_SUB_DIRS := -ALL_SUB_DIRS := $(SUB_DIRS) - +ALL_SUB_DIRS := $(SUB_DIRS) emu10k1 # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. @@ -72,6 +71,7 @@ obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_VWSND) += vwsnd.o obj-$(CONFIG_SOUND_NM256) += nm256_audio.o ac97.o +obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97.o obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o obj-$(CONFIG_SOUND_CMPCI) += cmpci.o obj-$(CONFIG_SOUND_ES1370) += es1370.o @@ -80,6 +80,15 @@ obj-$(CONFIG_SOUND_MAESTRO) += maestro.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o +ifeq ($(CONFIG_SOUND_EMU10K1),y) + SUB_DIRS += emu10k1 + obj-y += emu10k1/emu10k1.o +else + ifeq ($(CONFIG_SOUND_EMU10K1),m) + MOD_SUB_DIRS += emu10k1 + endif +endif + ifeq ($(CONFIG_DMASOUND),y) SUB_DIRS += dmasound MOD_SUB_DIRS += dmasound @@ -138,8 +147,7 @@ # Translate to Rules.make lists. O_TARGET := sounddrivers.o -# This is a nice idea but needs depmod altering -#MOD_LIST_NAME := SOUND_MODULES +MOD_LIST_NAME := SOUND_MODULES O_OBJS := $(filter-out $(export-objs), $(obj-y)) OX_OBJS := $(filter $(export-objs), $(obj-y)) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.3.99-pre5/linux/drivers/sound/ad1848.c Fri Mar 10 16:40:44 2000 +++ linux/drivers/sound/ad1848.c Wed Apr 12 09:47:26 2000 @@ -27,6 +27,7 @@ * Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free * of irqs. Use dev_id. * Christoph Hellwig : adapted to module_init/module_exit + * Aki Laukkanen : added power management support * * Status: * Tested. Believed fully functional. @@ -36,6 +37,7 @@ #include #include #include +#include #include "soundmodule.h" @@ -52,6 +54,7 @@ int irq; int dma1, dma2; int dual_dma; /* 1, when two DMA channels allocated */ + int subtype; unsigned char MCE_bit; unsigned char saved_regs[32]; int debug_flag; @@ -87,6 +90,9 @@ int irq_ok; mixer_ents *mix_devices; int mixer_output_port; + + /* Power management */ + struct pm_dev *pmdev; } ad1848_info; typedef struct ad1848_port_info @@ -100,7 +106,9 @@ } ad1848_port_info; +static struct address_info cfg; static int nr_ad1848_devs = 0; + int deskpro_xl = 0; int deskpro_m = 0; int soundpro = 0; @@ -163,11 +171,11 @@ static void ad1848_halt_input(int dev); static void ad1848_halt_output(int dev); static void ad1848_trigger(int dev, int bits); +static int ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data); #ifndef EXCLUDE_TIMERS static int ad1848_tmr_install(int dev); static void ad1848_tmr_reprogram(int dev); - #endif static int ad_read(ad1848_info * devc, int reg) @@ -1415,7 +1423,7 @@ if (devc->model == MD_IWAVE) ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ - if (devc-> model != MD_1845_SSCAPE) + if (devc->model != MD_1845_SSCAPE) for (i = 16; i < 32; i++) ad_write(devc, i, init_values[i]); @@ -1849,7 +1857,6 @@ * The actually used IRQ is ABS(irq). */ - int my_dev; char dev_name[100]; int e; @@ -1863,6 +1870,7 @@ devc->timer_ticks = 0; devc->dma1 = dma_playback; devc->dma2 = dma_capture; + devc->subtype = cfg.card_subtype; devc->audio_flags = DMA_AUTOMODE; devc->playback_dev = devc->record_dev = 0; if (name != NULL) @@ -1915,6 +1923,10 @@ nr_ad1848_devs++; + devc->pmdev = pm_register(PM_ISA_DEV, my_dev, ad1848_pm_callback); + if (devc->pmdev) + devc->pmdev->data = devc; + ad1848_init_hw(devc); if (irq > 0) @@ -1950,7 +1962,7 @@ devc->irq_ok = 1; } #else - devc->irq_ok=1; + devc->irq_ok = 1; #endif } else @@ -2076,6 +2088,9 @@ if(mixer>=0) sound_unload_mixerdev(mixer); + if (devc->pmdev) + pm_unregister(devc->pmdev); + nr_ad1848_devs--; for ( ; i < nr_ad1848_devs ; i++) adev_info[i] = adev_info[i+1]; @@ -2507,7 +2522,8 @@ hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, hw_config->irq, hw_config->dma, - hw_config->dma2, 0, hw_config->osp); + hw_config->dma2, 0, + hw_config->osp); request_region(hw_config->io_base, 4, "WSS config"); return; } @@ -2562,10 +2578,9 @@ outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ - hw_config->slots[0] = ad1848_init("MSS audio codec", hw_config->io_base + 4, + hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, hw_config->irq, - dma, - dma2, 0, + dma, dma2, 0, hw_config->osp); request_region(hw_config->io_base, 4, "WSS config"); } @@ -2692,6 +2707,83 @@ } #endif /* EXCLUDE_TIMERS */ +static int ad1848_suspend(ad1848_info *devc) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + ad_mute(devc); + + restore_flags(flags); + return 0; +} + +static int ad1848_resume(ad1848_info *devc) +{ + unsigned long flags; + int mixer_levels[32], i; + + save_flags(flags); + cli(); + + /* store old mixer levels */ + memcpy(mixer_levels, devc->levels, sizeof (mixer_levels)); + ad1848_init_hw(devc); + + /* restore mixer levels */ + for (i = 0; i < 32; i++) + ad1848_mixer_set(devc, devc->dev_no, mixer_levels[i]); + + if (!devc->subtype) { + static signed char interrupt_bits[12] = { -1, -1, -1, -1, -1, 0x00, -1, 0x08, -1, 0x10, 0x18, 0x20 }; + static char dma_bits[4] = { 1, 2, 0, 3 }; + + signed char bits; + char dma2_bit = 0; + + int config_port = devc->base + 0; + + bits = interrupt_bits[devc->irq]; + if (bits == -1) { + printk(KERN_ERR "MSS: Bad IRQ %d\n", devc->irq); + return -1; + } + + outb((bits | 0x40), config_port); + + if (devc->dma2 != -1 && devc->dma2 != devc->dma1) + if ( (devc->dma1 == 0 && devc->dma2 == 1) || + (devc->dma1 == 1 && devc->dma2 == 0) || + (devc->dma1 == 3 && devc->dma2 == 0)) + dma2_bit = 0x04; + + outb((bits | dma_bits[devc->dma1] | dma2_bit), config_port); + } + + restore_flags(flags); + return 0; +} + +static int ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + ad1848_info *devc = dev->data; + if (devc) { + DEB(printk("ad1848: pm event received: 0x%x\n", rqst)); + + switch (rqst) { + case PM_SUSPEND: + ad1848_suspend(devc); + break; + case PM_RESUME: + ad1848_resume(devc); + break; + } + } + return 0; +} + EXPORT_SYMBOL(ad1848_detect); EXPORT_SYMBOL(ad1848_init); @@ -2707,8 +2799,6 @@ static int __initdata dma = -1; static int __initdata dma2 = -1; static int __initdata type = 0; - -static struct address_info cfg; MODULE_PARM(io, "i"); /* I/O for a raw AD1848 card */ MODULE_PARM(irq, "i"); /* IRQ to use */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c --- v2.3.99-pre5/linux/drivers/sound/cmpci.c Thu Feb 10 17:11:14 2000 +++ linux/drivers/sound/cmpci.c Fri Apr 21 13:23:56 2000 @@ -1364,6 +1364,7 @@ return ret; } +/* No kernel lock - fine (we have our own spinlock) */ static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait) { struct cm_state *s = (struct cm_state *)file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v2.3.99-pre5/linux/drivers/sound/dmabuf.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/sound/dmabuf.c Fri Apr 21 13:24:59 2000 @@ -1218,6 +1218,7 @@ } } +/* No kernel lock - DMAbuf_activate_recording protected by global cli/sti */ static unsigned int poll_input(struct file * file, int dev, poll_table *wait) { struct audio_operations *adev = audio_devs[dev]; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound.h linux/drivers/sound/dmasound/dmasound.h --- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound.h Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/dmasound/dmasound.h Tue Apr 25 17:58:46 2000 @@ -1,6 +1,6 @@ /* - * linux/drivers/sound/dmasound.h + * linux/drivers/sound/dmasound/dmasound.h * * * Minor numbers for the sound driver. @@ -89,7 +89,11 @@ */ extern int dmasound_init(void); +#ifdef MODULE extern void dmasound_deinit(void); +#else +#define dmasound_deinit() do { } while (0) +#endif /* @@ -106,7 +110,7 @@ int (*irqinit)(void); #ifdef MODULE void (*irqcleanup)(void); -#endif /* MODULE */ +#endif void (*init)(void); void (*silence)(void); int (*setFormat)(int); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_atari.c linux/drivers/sound/dmasound/dmasound_atari.c --- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_atari.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/dmasound/dmasound_atari.c Tue Apr 25 17:58:46 2000 @@ -1,10 +1,10 @@ /* - * linux/drivers/sound/dmasound_atari.c + * linux/drivers/sound/dmasound/dmasound_atari.c * - * Atari DMA Sound Driver + * Atari TT and Falcon DMA Sound Driver * - * See linux/drivers/sound/dmasound_core.c for copyright and credits + * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_awacs.c linux/drivers/sound/dmasound/dmasound_awacs.c --- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_awacs.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/dmasound/dmasound_awacs.c Tue Apr 25 17:58:46 2000 @@ -1,10 +1,10 @@ /* - * linux/drivers/sound/dmasound_awacs.c + * linux/drivers/sound/dmasound/dmasound_awacs.c * - * PowerMac DMA Sound Driver + * PowerMac `AWACS' and `Burgundy' DMA Sound Driver * - * See linux/drivers/sound/dmasound_core.c for copyright and credits + * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_core.c linux/drivers/sound/dmasound/dmasound_core.c --- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_core.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/dmasound/dmasound_core.c Tue Apr 25 17:58:46 2000 @@ -1,6 +1,6 @@ /* - * linux/drivers/sound/dmasound.c + * linux/drivers/sound/dmasound/dmasound_core.c * * * OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for @@ -1193,8 +1193,10 @@ int __init dmasound_init(void) { +#ifdef MODULE if (irq_installed) return -EBUSY; +#endif /* Set up sound queue, /dev/audio and /dev/dsp. */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_paula.c linux/drivers/sound/dmasound/dmasound_paula.c --- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_paula.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/dmasound/dmasound_paula.c Tue Apr 25 17:58:46 2000 @@ -1,14 +1,15 @@ /* - * linux/drivers/sound/dmasound_paula.c + * linux/drivers/sound/dmasound/dmasound_paula.c * - * Amiga DMA Sound Driver + * Amiga `Paula' DMA Sound Driver * - * See linux/drivers/sound/dmasound_core.c for copyright and credits + * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits */ #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include "dmasound.h" @@ -76,6 +78,38 @@ static void AmiPlay(void); static void AmiInterrupt(int irq, void *dummy, struct pt_regs *fp); +#ifdef CONFIG_HEARTBEAT + + /* + * Heartbeat interferes with sound since the 7 kHz low-pass filter and the + * power LED are controlled by the same line. + */ + +#ifdef CONFIG_APUS +#define mach_heartbeat ppc_md.heartbeat +#endif + +static void (*saved_heartbeat)(int) = NULL; + +static inline void disable_heartbeat(void) +{ + if (mach_heartbeat) { + saved_heartbeat = mach_heartbeat; + mach_heartbeat = NULL; + } + AmiSetTreble(dmasound.treble); +} + +static inline void enable_heartbeat(void) +{ + if (saved_heartbeat) + mach_heartbeat = saved_heartbeat; +} +#else /* !CONFIG_HEARTBEAT */ +#define disable_heartbeat() do { } while (0) +#define enable_heartbeat() do { } while (0) +#endif /* !CONFIG_HEARTBEAT */ + /*** Mid level stuff *********************************************************/ @@ -285,6 +319,7 @@ custom.aud[0].audvol = custom.aud[1].audvol = 0; custom.aud[2].audvol = custom.aud[3].audvol = 0; custom.dmacon = AMI_AUDIO_OFF; + enable_heartbeat(); } static void *AmiAlloc(unsigned int size, int flags) @@ -350,8 +385,6 @@ for (i = 0; i < 4; i++) custom.aud[i].audper = period; amiga_audio_period = period; - - AmiSetTreble(50); /* recommended for newer amiga models */ } @@ -453,6 +486,7 @@ ch1 = start; } + disable_heartbeat(); custom.aud[0].audvol = dmasound.volume_left; custom.aud[1].audvol = dmasound.volume_right; if (dmasound.hard.size == 8) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_q40.c linux/drivers/sound/dmasound/dmasound_q40.c --- v2.3.99-pre5/linux/drivers/sound/dmasound/dmasound_q40.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/dmasound/dmasound_q40.c Tue Apr 25 17:58:46 2000 @@ -1,10 +1,10 @@ /* - * linux/drivers/sound/dmasound_q40.c + * linux/drivers/sound/dmasound/dmasound_q40.c * * Q40 DMA Sound Driver * - * See linux/drivers/sound/dmasound_core.c for copyright and credits + * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/8010.h linux/drivers/sound/emu10k1/8010.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/8010.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/8010.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,662 @@ +/* + ********************************************************************** + * 8010.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox Cleaned of 8bit chars, DOS + * line endings + * December 8, 1999 Jon Taylor Added lots of new register info + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * + ********************************************************************** + */ + + +#ifndef _8010_H +#define _8010_H + +/* ------------------- DEFINES -------------------- */ + +#define EMUPAGESIZE 4096 /* don't change */ +#define RESERVED 0 +#define NUM_G 64 /* use all channels */ +#define NUM_FXSENDS 4 /* don't change */ +#define MAXPAGES (32768 * NUM_G / EMUPAGESIZE) /* WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE */ + +#define TMEMSIZE 256*1024 +#define TMEMSIZEREG 4 + +#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL)) + +/************************************************************************************************/ +/* PCI function 0 registers, address = + PCIBASE0 */ +/************************************************************************************************/ + +#define PTR 0x00 /* Indexed register set pointer register */ + /* NOTE: The CHANNELNUM and ADDRESS words can */ + /* be modified independently of each other. */ +#define PTR_CHANNELNUM_MASK 0x0000003f /* For each per-channel register, indicates the */ + /* channel number of the register to be */ + /* accessed. For non per-channel registers the */ + /* value should be set to zero. */ +#define PTR_ADDRESS_MASK 0x07ff0000 /* Register index */ + +#define DATA 0x04 /* Indexed register set data register */ + +#define IPR 0x08 /* Global interrupt pending register */ + /* Clear pending interrupts by writing a 1 to */ + /* the relevant bits and zero to the other bits */ +#define IPR_SAMPLERATETRACKER 0x01000000 /* Sample rate tracker lock status change */ +#define IPR_FXDSP 0x00800000 /* Enable FX DSP interrupts */ +#define IPR_FORCEINT 0x00400000 /* Force Sound Blaster interrupt */ +#define IPR_PCIERROR 0x00200000 /* PCI bus error */ +#define IPR_VOLINCR 0x00100000 /* Volume increment button pressed */ +#define IPR_VOLDECR 0x00080000 /* Volume decrement button pressed */ +#define IPR_MUTE 0x00040000 /* Mute button pressed */ +#define IPR_MICBUFFULL 0x00020000 /* Microphone buffer full */ +#define IPR_MICBUFHALFFULL 0x00010000 /* Microphone buffer half full */ +#define IPR_ADCBUFFULL 0x00008000 /* ADC buffer full */ +#define IPR_ADCBUFHALFFULL 0x00004000 /* ADC buffer half full */ +#define IPR_EFXBUFFULL 0x00002000 /* Effects buffer full */ +#define IPR_EFXBUFHALFFULL 0x00001000 /* Effects buffer half full */ +#define IPR_GPSPDIFSTATUSCHANGE 0x00000800 /* GPSPDIF channel status change */ +#define IPR_CDROMSTATUSCHANGE 0x00000400 /* CD-ROM channel status change */ +#define IPR_INTERVALTIMER 0x00000200 /* Interval timer terminal count */ +#define IPR_MIDITRANSBUFEMPTY 0x00000100 /* MIDI UART transmit buffer empty */ +#define IPR_MIDIRECVBUFEMPTY 0x00000080 /* MIDI UART receive buffer empty */ +#define IPR_CHANNELLOOP 0x00000040 /* One or more channel loop interrupts pending */ +#define IPR_CHANNELNUMBERMASK 0x0000003f /* When IPR_CHANNELLOOP is set, indicates the */ + /* Highest set channel in CLIPL or CLIPH. When */ + /* IP is written with CL set, the bit in CLIPL */ + /* or CLIPH corresponding to the CIN value */ + /* written will be cleared. */ + +#define INTE 0x0c /* Interrupt enable register */ +#define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */ +#define INTE_VIRTUALSB_220 0x00000000 /* Capture at I/O base address 0x220-0x22f */ +#define INTE_VIRTUALSB_240 0x40000000 /* Capture at I/O base address 0x240 */ +#define INTE_VIRTUALSB_260 0x80000000 /* Capture at I/O base address 0x260 */ +#define INTE_VIRTUALSB_280 0xc0000000 /* Capture at I/O base address 0x280 */ +#define INTE_VIRTUALMPU_MASK 0x30000000 /* Virtual MPU I/O port capture */ +#define INTE_VIRTUALMPU_300 0x00000000 /* Capture at I/O base address 0x300-0x301 */ +#define INTE_VIRTUALMPU_310 0x10000000 /* Capture at I/O base address 0x310 */ +#define INTE_VIRTUALMPU_320 0x20000000 /* Capture at I/O base address 0x320 */ +#define INTE_VIRTUALMPU_330 0x30000000 /* Capture at I/O base address 0x330 */ +#define INTE_MASTERDMAENABLE 0x08000000 /* Master DMA emulation at 0x000-0x00f */ +#define INTE_SLAVEDMAENABLE 0x04000000 /* Slave DMA emulation at 0x0c0-0x0df */ +#define INTE_MASTERPICENABLE 0x02000000 /* Master PIC emulation at 0x020-0x021 */ +#define INTE_SLAVEPICENABLE 0x01000000 /* Slave PIC emulation at 0x0a0-0x0a1 */ +#define INTE_VSBENABLE 0x00800000 /* Enable virtual Soundblaster */ +#define INTE_ADLIBENABLE 0x00400000 /* Enable AdLib emulation at 0x388-0x38b */ +#define INTE_MPUENABLE 0x00200000 /* Enable virtual MPU */ +#define INTE_FORCEINT 0x00100000 /* Continuously assert INTAN */ + +#define INTE_MRHANDENABLE 0x00080000 /* Enable the "Mr. Hand" logic */ + /* NOTE: There is no reason to use this under */ + /* Linux, and it will cause odd hardware */ + /* behavior and possibly random segfaults and */ + /* lockups if enabled. */ + +#define INTE_SAMPLERATETRACKER 0x00002000 /* Enable sample rate tracker interrupts */ + /* NOTE: This bit must always be enabled */ +#define INTE_FXDSPENABLE 0x00001000 /* Enable FX DSP interrupts */ +#define INTE_PCIERRORENABLE 0x00000800 /* Enable PCI bus error interrupts */ +#define INTE_VOLINCRENABLE 0x00000400 /* Enable volume increment button interrupts */ +#define INTE_VOLDECRENABLE 0x00000200 /* Enable volume decrement button interrupts */ +#define INTE_MUTEENABLE 0x00000100 /* Enable mute button interrupts */ +#define INTE_MICBUFENABLE 0x00000080 /* Enable microphone buffer interrupts */ +#define INTE_ADCBUFENABLE 0x00000040 /* Enable ADC buffer interrupts */ +#define INTE_EFXBUFENABLE 0x00000020 /* Enable Effects buffer interrupts */ +#define INTE_GPSPDIFENABLE 0x00000010 /* Enable GPSPDIF status interrupts */ +#define INTE_CDSPDIFENABLE 0x00000008 /* Enable CDSPDIF status interrupts */ +#define INTE_INTERVALTIMERENB 0x00000004 /* Enable interval timer interrupts */ +#define INTE_MIDITXENABLE 0x00000002 /* Enable MIDI transmit-buffer-empty interrupts */ +#define INTE_MIDIRXENABLE 0x00000001 /* Enable MIDI receive-buffer-empty interrupts */ + +#define WC 0x10 /* Wall Clock register */ +#define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */ +#define WC_SAMPLECOUNTER 0x14060010 +#define WC_CURRENTCHANNEL 0x0000003F /* Channel [0..63] currently being serviced */ + /* NOTE: Each channel takes 1/64th of a sample */ + /* period to be serviced. */ + +#define HCFG 0x14 /* Hardware config register */ + /* NOTE: There is no reason to use the legacy */ + /* SoundBlaster emulation stuff described below */ + /* under Linux, and all kinds of weird hardware */ + /* behavior can result if you try. Don't. */ +#define HCFG_LEGACYFUNC_MASK 0xe0000000 /* Legacy function number */ +#define HCFG_LEGACYFUNC_MPU 0x00000000 /* Legacy MPU */ +#define HCFG_LEGACYFUNC_SB 0x40000000 /* Legacy SB */ +#define HCFG_LEGACYFUNC_AD 0x60000000 /* Legacy AD */ +#define HCFG_LEGACYFUNC_MPIC 0x80000000 /* Legacy MPIC */ +#define HCFG_LEGACYFUNC_MDMA 0xa0000000 /* Legacy MDMA */ +#define HCFG_LEGACYFUNC_SPCI 0xc0000000 /* Legacy SPCI */ +#define HCFG_LEGACYFUNC_SDMA 0xe0000000 /* Legacy SDMA */ +#define HCFG_IOCAPTUREADDR 0x1f000000 /* The 4 LSBs of the captured I/O address. */ +#define HCFG_LEGACYWRITE 0x00800000 /* 1 = write, 0 = read */ +#define HCFG_LEGACYWORD 0x00400000 /* 1 = word, 0 = byte */ +#define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */ + /* NOTE: The rest of the bits in this register */ + /* _are_ relevant under Linux. */ +#define HCFG_CODECFORMAT_MASK 0x00070000 /* CODEC format */ +#define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */ +#define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */ +#define HCFG_GPINPUT0 0x00004000 /* External pin112 */ +#define HCFG_GPINPUT1 0x00002000 /* External pin110 */ +#define HCFG_GPOUTPUT_MASK 0x00001c00 /* External pins which may be controlled */ +#define HCFG_JOYENABLE 0x00000200 /* Internal joystick enable */ +#define HCFG_PHASETRACKENABLE 0x00000100 /* Phase tracking enable */ + /* 1 = Force all 3 async digital inputs to use */ + /* the same async sample rate tracker (ZVIDEO) */ +#define HCFG_AC3ENABLE_MASK 0x0x0000e0 /* AC3 async input control - Not implemented */ +#define HCFG_AC3ENABLE_ZVIDEO 0x00000080 /* Channels 0 and 1 replace ZVIDEO */ +#define HCFG_AC3ENABLE_CDSPDIF 0x00000040 /* Channels 0 and 1 replace CDSPDIF */ +#define HCFG_AUTOMUTE 0x00000010 /* When set, the async sample rate convertors */ + /* will automatically mute their output when */ + /* they are not rate-locked to the external */ + /* async audio source */ +#define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */ + /* NOTE: This should generally never be used. */ +#define HCFG_LOCKTANKCACHE 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */ + /* NOTE: This should generally never be used. */ +#define HCFG_MUTEBUTTONENABLE 0x00000002 /* 1 = Master mute button sets AUDIOENABLE = 0. */ + /* NOTE: This is a 'cheap' way to implement a */ + /* master mute function on the mute button, and */ + /* in general should not be used unless a more */ + /* sophisticated master mute function has not */ + /* been written. */ +#define HCFG_AUDIOENABLE 0x00000001 /* 0 = CODECs transmit zero-valued samples */ + /* Should be set to 1 when the EMU10K1 is */ + /* completely initialized. */ + +#define MUDATA 0x18 /* MPU401 data register (8 bits) */ + +#define MUCMD 0x19 /* MPU401 command register (8 bits) */ +#define MUCMD_RESET 0xff /* RESET command */ +#define MUCMD_ENTERUARTMODE 0x3f /* Enter_UART_mode command */ + /* NOTE: All other commands are ignored */ + +#define MUSTAT MUCMD /* MPU401 status register (8 bits) */ +#define MUSTAT_IRDYN 0x80 /* 0 = MIDI data or command ACK */ +#define MUSTAT_ORDYN 0x40 /* 0 = MUDATA can accept a command or data */ + +#define TIMER 0x1a /* Timer terminal count register */ + /* NOTE: After the rate is changed, a maximum */ + /* of 1024 sample periods should be allowed */ + /* before the new rate is guaranteed accurate. */ +#define TIMER_RATE_MASK 0x000003ff /* Timer interrupt rate in sample periods */ + /* 0 == 1024 periods, [1..4] are not useful */ +#define TIMER_RATE 0x0a00001a + +#define AC97DATA 0x1c /* AC97 register set data register (16 bit) */ + +#define AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */ +#define AC97ADDRESS_READY 0x80 /* Read-only bit, reflects CODEC READY signal */ +#define AC97ADDRESS_ADDRESS 0x7f /* Address of indexed AC97 register */ + +/************************************************************************************************/ +/* PCI function 1 registers, address = + PCIBASE1 */ +/************************************************************************************************/ + +#define JOYSTICK1 0x00 /* Analog joystick port register */ +#define JOYSTICK2 0x01 /* Analog joystick port register */ +#define JOYSTICK3 0x02 /* Analog joystick port register */ +#define JOYSTICK4 0x03 /* Analog joystick port register */ +#define JOYSTICK5 0x04 /* Analog joystick port register */ +#define JOYSTICK6 0x05 /* Analog joystick port register */ +#define JOYSTICK7 0x06 /* Analog joystick port register */ +#define JOYSTICK8 0x07 /* Analog joystick port register */ + +/* When writing, any write causes JOYSTICK_COMPARATOR output enable to be pulsed on write. */ +/* When reading, use these bitfields: */ +#define JOYSTICK_BUTTONS 0x0f /* Joystick button data */ +#define JOYSTICK_COMPARATOR 0xf0 /* Joystick comparator data */ + + +/********************************************************************************************************/ +/* AC97 pointer-offset register set, accessed through the AC97ADDRESS and AC97DATA registers */ +/********************************************************************************************************/ + +#define AC97_RESET 0x00 +#define AC97_MASTERVOLUME 0x02 /* Master volume */ +#define AC97_HEADPHONEVOLUME 0x04 /* Headphone volume */ +#define AC97_MASTERVOLUMEMONO 0x06 /* Mast volume mono */ +#define AC97_MASTERTONE 0x08 +#define AC97_PCBEEPVOLUME 0x0a /* PC speaker system beep volume */ +#define AC97_PHONEVOLUME 0x0c +#define AC97_MICVOLUME 0x0e +#define AC97_LINEINVOLUME 0x10 +#define AC97_CDVOLUME 0x12 +#define AC97_VIDEOVOLUME 0x14 +#define AC97_AUXVOLUME 0x16 +#define AC97_PCMOUTVOLUME 0x18 +#define AC97_RECORDSELECT 0x1a +#define AC97_RECORDGAIN 0x1c +#define AC97_RECORDGAINMIC 0x1e +#define AC97_GENERALPUPOSE 0x20 +#define AC97_3DCONTROL 0x22 +#define AC97_MODEMRATE 0x24 +#define AC97_POWERDOWN 0x26 +#define AC97_VENDORID1 0x7c +#define AC97_VENDORID2 0x7e +#define AC97_ZVIDEOVOLUME 0xec +#define AC97_AC3VOLUME 0xed + +/********************************************************************************************************/ +/* Emu10k1 pointer-offset register set, accessed through the PTR and DATA registers */ +/********************************************************************************************************/ + +#define CPF 0x00 /* Current pitch and fraction register */ +#define CPF_CURRENTPITCH_MASK 0xffff0000 /* Current pitch (linear, 0x4000 == unity pitch shift) */ +#define CPF_CURRENTPITCH 0x10100000 +#define CPF_STEREO_MASK 0x00008000 /* 1 = Even channel interleave, odd channel locked */ +#define CPF_STOP_MASK 0x00004000 /* 1 = Current pitch forced to 0 */ +#define CPF_FRACADDRESS_MASK 0x00003fff /* Linear fractional address of the current channel */ + +#define PTRX 0x01 /* Pitch target and send A/B amounts register */ +#define PTRX_PITCHTARGET_MASK 0xffff0000 /* Pitch target of specified channel */ +#define PTRX_PITCHTARGET 0x10100001 +#define PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00 /* Linear level of channel output sent to FX send bus A */ +#define PTRX_FXSENDAMOUNT_A 0x08080001 +#define PTRX_FXSENDAMOUNT_B_MASK 0x000000ff /* Linear level of channel output sent to FX send bus B */ +#define PTRX_FXSENDAMOUNT_B 0x08000001 + +#define CVCF 0x02 /* Current volume and filter cutoff register */ +#define CVCF_CURRENTVOL_MASK 0xffff0000 /* Current linear volume of specified channel */ +#define CVCF_CURRENTVOL 0x10100002 +#define CVCF_CURRENTFILTER_MASK 0x0000ffff /* Current filter cutoff frequency of specified channel */ +#define CVCF_CURRENTFILTER 0x10000002 + +#define VTFT 0x03 /* Volume target and filter cutoff target register */ +#define VTFT_VOLUMETARGET_MASK 0xffff0000 /* Volume target of specified channel */ +#define VTFT_FILTERTARGET_MASK 0x0000ffff /* Filter cutoff target of specified channel */ + +#define Z1 0x05 /* Filter delay memory 1 register */ + +#define Z2 0x04 /* Filter delay memory 2 register */ + +#define PSST 0x06 /* Send C amount and loop start address register */ +#define PSST_FXSENDAMOUNT_C_MASK 0xff000000 /* Linear level of channel output sent to FX send bus C */ + +#define PSST_FXSENDAMOUNT_C 0x08180006 + +#define PSST_LOOPSTARTADDR_MASK 0x00ffffff /* Loop start address of the specified channel */ +#define PSST_LOOPSTARTADDR 0x18000006 + +#define DSL 0x07 /* Send D amount and loop start address register */ +#define DSL_FXSENDAMOUNT_D_MASK 0xff000000 /* Linear level of channel output sent to FX send bus D */ + +#define DSL_FXSENDAMOUNT_D 0x08180007 + +#define DSL_LOOPENDADDR_MASK 0x00ffffff /* Loop end address of the specified channel */ +#define DSL_LOOPENDADDR 0x18000007 + +#define CCCA 0x08 /* Filter Q, interp. ROM, byte size, cur. addr register */ +#define CCCA_RESONANCE 0xf0000000 /* Lowpass filter resonance (Q) height */ +#define CCCA_INTERPROMMASK 0x0e000000 /* Selects passband of interpolation ROM */ + /* 1 == full band, 7 == lowpass */ + /* ROM 0 is used when pitch shifting downward or less */ + /* then 3 semitones upward. Increasingly higher ROM */ + /* numbers are used, typically in steps of 3 semitones, */ + /* as upward pitch shifting is performed. */ +#define CCCA_INTERPROM_0 0x00000000 /* Select interpolation ROM 0 */ +#define CCCA_INTERPROM_1 0x02000000 /* Select interpolation ROM 1 */ +#define CCCA_INTERPROM_2 0x04000000 /* Select interpolation ROM 2 */ +#define CCCA_INTERPROM_3 0x06000000 /* Select interpolation ROM 3 */ +#define CCCA_INTERPROM_4 0x08000000 /* Select interpolation ROM 4 */ +#define CCCA_INTERPROM_5 0x0a000000 /* Select interpolation ROM 5 */ +#define CCCA_INTERPROM_6 0x0c000000 /* Select interpolation ROM 6 */ +#define CCCA_INTERPROM_7 0x0e000000 /* Select interpolation ROM 7 */ +#define CCCA_8BITSELECT 0x01000000 /* 1 = Sound memory for this channel uses 8-bit samples */ +#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */ +#define CCCA_CURRADDR 0x18000008 + +#define CCR 0x09 /* Cache control register */ +#define CCR_CACHEINVALIDSIZE 0xfe000000 /* Number of invalid samples cache for this channel */ +#define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */ +#define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */ +#define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */ +#define CCR_READADDRESS_MASK 0x003f0000 /* Location of cache just beyond current cache service */ +#define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */ + /* NOTE: This is valid only if CACHELOOPFLAG is set */ +#define CCR_LOOPFLAG 0x00000100 /* Set for a single sample period when a loop occurs */ +#define CCR_CACHELOOPADDRHI 0x000000ff /* DSL_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */ + +#define CLP 0x0a /* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */ + /* NOTE: This register is normally not used */ +#define CLP_CACHELOOPADDR 0x0000ffff /* Cache loop address (DSL_LOOPSTARTADDR [0..15]) */ + +#define FXRT 0x0b /* Effects send routing register */ + /* NOTE: It is illegal to assign the same routing to */ + /* two effects sends. */ +#define FXRT_CHANNELA 0x000f0000 /* Effects send bus number for channel's effects send A */ +#define FXRT_CHANNELB 0x00f00000 /* Effects send bus number for channel's effects send B */ +#define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */ +#define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */ + +#define MAPA 0x0c /* Cache map A */ + +#define MAPB 0x0d /* Cache map B */ + +#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ +#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ + +#define ENVVOL 0x10 /* Volume envelope register */ +#define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */ + /* 0x8000-n == 666*n usec delay */ + +#define ATKHLDV 0x11 /* Volume envelope hold and attack register */ +#define ATKHLDV_PHASE0 0x00008000 /* 0 = Begin attack phase */ +#define ATKHLDV_HOLDTIME_MASK 0x00007f00 /* Envelope hold time (127-n == n*88.2msec) */ +#define ATKHLDV_ATTACKTIME_MASK 0x0000007f /* Envelope attack time, log encoded */ + /* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec */ + +#define DCYSUSV 0x12 /* Volume envelope sustain and decay register */ +#define DCYSUSV_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */ +#define DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */ +#define DCYSUSV_CHANNELENABLE_MASK 0x00000080 /* 1 = Inhibit envelope engine from writing values in */ + /* this channel and from writing to pitch, filter and */ + /* volume targets. */ +#define DCYSUSV_DECAYTIME_MASK 0x0000007f /* Volume envelope decay time, log encoded */ + /* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */ + +#define LFOVAL1 0x13 /* Modulation LFO value */ +#define LFOVAL_MASK 0x0000ffff /* Current value of modulation LFO state variable */ + /* 0x8000-n == 666*n usec delay */ + +#define ENVVAL 0x14 /* Modulation envelope register */ +#define ENVVAL_MASK 0x0000ffff /* Current value of modulation envelope state variable */ + /* 0x8000-n == 666*n usec delay */ + +#define ATKHLDM 0x15 /* Modulation envelope hold and attack register */ +#define ATKHLDM_PHASE0 0x00008000 /* 0 = Begin attack phase */ +#define ATKHLDM_HOLDTIME 0x00007f00 /* Envelope hold time (127-n == n*42msec) */ +#define ATKHLDM_ATTACKTIME 0x0000007f /* Envelope attack time, log encoded */ + /* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec */ + +#define DCYSUSM 0x16 /* Modulation envelope decay and sustain register */ +#define DCYSUSM_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */ +#define DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */ +#define DCYSUSM_DECAYTIME_MASK 0x0000007f /* Envelope decay time, log encoded */ + /* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */ + +#define LFOVAL2 0x17 /* Vibrato LFO register */ +#define LFOVAL2_MASK 0x0000ffff /* Current value of vibrato LFO state variable */ + /* 0x8000-n == 666*n usec delay */ + +#define IP 0x18 /* Initial pitch register */ +#define IP_MASK 0x0000ffff /* Exponential initial pitch shift */ + /* 4 bits of octave, 12 bits of fractional octave */ +#define IP_UNITY 0x0000e000 /* Unity pitch shift */ + +#define IFATN 0x19 /* Initial filter cutoff and attenuation register */ +#define IFATN_FILTERCUTOFF_MASK 0x0000ff00 /* Initial filter cutoff frequency in exponential units */ + /* 6 most significant bits are semitones */ + /* 2 least significant bits are fractions */ +#define IFATN_FILTERCUTOFF 0x08080019 +#define IFATN_ATTENUATION_MASK 0x000000ff /* Initial attenuation in 0.375dB steps */ +#define IFATN_ATTENUATION 0x08000019 + + +#define PEFE 0x1a /* Pitch envelope and filter envelope amount register */ +#define PEFE_PITCHAMOUNT_MASK 0x0000ff00 /* Pitch envlope amount */ + /* Signed 2's complement, +/- one octave peak extremes */ +#define PEFE_PITCHAMOUNT 0x0808001a +#define PEFE_FILTERAMOUNT_MASK 0x000000ff /* Filter envlope amount */ + /* Signed 2's complement, +/- six octaves peak extremes */ +#define PEFE_FILTERAMOUNT 0x0800001a +#define FMMOD 0x1b /* Vibrato/filter modulation from LFO register */ +#define FMMOD_MODVIBRATO 0x0000ff00 /* Vibrato LFO modulation depth */ + /* Signed 2's complement, +/- one octave extremes */ +#define FMMOD_MOFILTER 0x000000ff /* Filter LFO modulation depth */ + /* Signed 2's complement, +/- three octave extremes */ + + +#define TREMFRQ 0x1c /* Tremolo amount and modulation LFO frequency register */ +#define TREMFRQ_DEPTH 0x0000ff00 /* Tremolo depth */ + /* Signed 2's complement, with +/- 12dB extremes */ + +#define FM2FRQ2 0x1d /* Vibrato amount and vibrato LFO frequency register */ +#define FM2FRQ2_DEPTH 0x0000ff00 /* Vibrato LFO vibrato depth */ + /* Signed 2's complement, +/- one octave extremes */ +#define FM2FRQ2_FREQUENCY 0x000000ff /* Vibrato LFO frequency */ + /* 0.039Hz steps, maximum of 9.85 Hz. */ + +#define TEMPENV 0x1e /* Tempory envelope register */ +#define TEMPENV_MASK 0x0000ffff /* 16-bit value */ + /* NOTE: All channels contain internal variables; do */ + /* not write to these locations. */ + +#define CD0 0x20 /* Cache data 0 register */ +#define CD1 0x21 /* Cache data 1 register */ +#define CD2 0x22 /* Cache data 2 register */ +#define CD3 0x23 /* Cache data 3 register */ +#define CD4 0x24 /* Cache data 4 register */ +#define CD5 0x25 /* Cache data 5 register */ +#define CD6 0x26 /* Cache data 6 register */ +#define CD7 0x27 /* Cache data 7 register */ +#define CD8 0x28 /* Cache data 8 register */ +#define CD9 0x29 /* Cache data 9 register */ +#define CDA 0x2a /* Cache data A register */ +#define CDB 0x2b /* Cache data B register */ +#define CDC 0x2c /* Cache data C register */ +#define CDD 0x2d /* Cache data D register */ +#define CDE 0x2e /* Cache data E register */ +#define CDF 0x2f /* Cache data F register */ + +#define PTB 0x40 /* Page table base register */ +#define PTB_MASK 0xfffff000 /* Physical address of the page table in host memory */ + +#define TCB 0x41 /* Tank cache base register */ +#define TCB_MASK 0xfffff000 /* Physical address of the bottom of host based TRAM */ + +#define ADCCR 0x42 /* ADC sample rate/stereo control register */ +#define ADCCR_RCHANENABLE 0x00000010 /* Enables right channel for writing to the host */ +#define ADCCR_LCHANENABLE 0x00000008 /* Enables left channel for writing to the host */ + /* NOTE: To guarantee phase coherency, both channels */ + /* must be disabled prior to enabling both channels. */ +#define ADCCR_SAMPLERATE_MASK 0x00000007 /* Sample rate convertor output rate */ +#define ADCCR_SAMPLERATE_48 0x00000000 /* 48kHz sample rate */ +#define ADCCR_SAMPLERATE_44 0x00000001 /* 44.1kHz sample rate */ +#define ADCCR_SAMPLERATE_32 0x00000002 /* 32kHz sample rate */ +#define ADCCR_SAMPLERATE_24 0x00000003 /* 24kHz sample rate */ +#define ADCCR_SAMPLERATE_22 0x00000004 /* 22.05kHz sample rate */ +#define ADCCR_SAMPLERATE_16 0x00000005 /* 16kHz sample rate */ +#define ADCCR_SAMPLERATE_11 0x00000006 /* 11.025kHz sample rate */ +#define ADCCR_SAMPLERATE_8 0x00000007 /* 8kHz sample rate */ + +#define FXWC 0x43 /* FX output write channels register */ + /* When set, each bit enables the writing of the */ + /* corresponding FX output channel into host memory */ + +#define TCBS 0x44 /* Tank cache buffer size register */ +#define TCBS_MASK 0x00000007 /* Tank cache buffer size field */ +#define TCBS_BUFFSIZE_16K 0x00000000 +#define TCBS_BUFFSIZE_32K 0x00000001 +#define TCBS_BUFFSIZE_64K 0x00000002 +#define TCBS_BUFFSIZE_128K 0x00000003 +#define TCBS_BUFFSIZE_256K 0x00000004 +#define TCBS_BUFFSIZE_512K 0x00000005 +#define TCBS_BUFFSIZE_1024K 0x00000006 +#define TCBS_BUFFSIZE_2048K 0x00000007 + +#define MICBA 0x45 /* AC97 microphone buffer address register */ +#define MICBA_MASK 0xfffff000 /* 20 bit base address */ + +#define ADCBA 0x46 /* ADC buffer address register */ +#define ADCBA_MASK 0xfffff000 /* 20 bit base address */ + +#define FXBA 0x47 /* FX Buffer Address */ +#define FXBA_MASK 0xfffff000 /* 20 bit base address */ + +#define MICBS 0x49 /* Microphone buffer size register */ + +#define ADCBS 0x4a /* ADC buffer size register */ + +#define FXBS 0x4b /* FX buffer size register */ + +/* The following mask values define the size of the ADC, MIX and FX buffers in bytes */ +#define ADCBS_BUFSIZE_NONE 0x00000000 +#define ADCBS_BUFSIZE_384 0x00000001 +#define ADCBS_BUFSIZE_448 0x00000002 +#define ADCBS_BUFSIZE_512 0x00000003 +#define ADCBS_BUFSIZE_640 0x00000004 +#define ADCBS_BUFSIZE_768 0x00000005 +#define ADCBS_BUFSIZE_896 0x00000006 +#define ADCBS_BUFSIZE_1024 0x00000007 +#define ADCBS_BUFSIZE_1280 0x00000008 +#define ADCBS_BUFSIZE_1536 0x00000009 +#define ADCBS_BUFSIZE_1792 0x0000000a +#define ADCBS_BUFSIZE_2048 0x0000000b +#define ADCBS_BUFSIZE_2560 0x0000000c +#define ADCBS_BUFSIZE_3072 0x0000000d +#define ADCBS_BUFSIZE_3584 0x0000000e +#define ADCBS_BUFSIZE_4096 0x0000000f +#define ADCBS_BUFSIZE_5120 0x00000010 +#define ADCBS_BUFSIZE_6144 0x00000011 +#define ADCBS_BUFSIZE_7168 0x00000012 +#define ADCBS_BUFSIZE_8192 0x00000013 +#define ADCBS_BUFSIZE_10240 0x00000014 +#define ADCBS_BUFSIZE_12288 0x00000015 +#define ADCBS_BUFSIZE_14366 0x00000016 +#define ADCBS_BUFSIZE_16384 0x00000017 +#define ADCBS_BUFSIZE_20480 0x00000018 +#define ADCBS_BUFSIZE_24576 0x00000019 +#define ADCBS_BUFSIZE_28672 0x0000001a +#define ADCBS_BUFSIZE_32768 0x0000001b +#define ADCBS_BUFSIZE_40960 0x0000001c +#define ADCBS_BUFSIZE_49152 0x0000001d +#define ADCBS_BUFSIZE_57344 0x0000001e +#define ADCBS_BUFSIZE_65536 0x0000001f + + +#define CDCS 0x50 /* CD-ROM digital channel status register */ + +#define GPSCS 0x51 /* General Purpose SPDIF channel status register*/ + +#define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ + +#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ + +#define SPCS0 0x54 /* SPDIF output Channel Status 0 register */ + +#define SPCS1 0x55 /* SPDIF output Channel Status 1 register */ + +#define SPCS2 0x56 /* SPDIF output Channel Status 2 register */ + +#define SPCS_CLKACCYMASK 0x30000000 /* Clock accuracy */ +#define SPCS_CLKACCY_1000PPM 0x00000000 /* 1000 parts per million */ +#define SPCS_CLKACCY_50PPM 0x10000000 /* 50 parts per million */ +#define SPCS_CLKACCY_VARIABLE 0x20000000 /* Variable accuracy */ +#define SPCS_SAMPLERATEMASK 0x0f000000 /* Sample rate */ +#define SPCS_SAMPLERATE_44 0x00000000 /* 44.1kHz sample rate */ +#define SPCS_SAMPLERATE_48 0x02000000 /* 48kHz sample rate */ +#define SPCS_SAMPLERATE_32 0x03000000 /* 32kHz sample rate */ +#define SPCS_CHANNELNUMMASK 0x00f00000 /* Channel number */ +#define SPCS_CHANNELNUM_UNSPEC 0x00000000 /* Unspecified channel number */ +#define SPCS_CHANNELNUM_LEFT 0x00100000 /* Left channel */ +#define SPCS_CHANNELNUM_RIGHT 0x00200000 /* Right channel */ +#define SPCS_SOURCENUMMASK 0x000f0000 /* Source number */ +#define SPCS_SOURCENUM_UNSPEC 0x00000000 /* Unspecified source number */ +#define SPCS_GENERATIONSTATUS 0x00008000 /* Originality flag (see IEC-958 spec) */ +#define SPCS_CATEGORYCODEMASK 0x00007f00 /* Category code (see IEC-958 spec) */ +#define SPCS_MODEMASK 0x000000c0 /* Mode (see IEC-958 spec) */ +#define SPCS_EMPHASISMASK 0x00000038 /* Emphasis */ +#define SPCS_EMPHASIS_NONE 0x00000000 /* No emphasis */ +#define SPCS_EMPHASIS_50_15 0x00000008 /* 50/15 usec 2 channel */ +#define SPCS_COPYRIGHT 0x00000004 /* Copyright asserted flag -- do not modify */ +#define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */ +#define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */ + +/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */ +#define CLIEL 0x58 /* Channel loop interrupt enable low register */ + +#define CLIEH 0x59 /* Channel loop interrupt enable high register */ + +#define CLIPL 0x5a /* Channel loop interrupt pending low register */ + +#define CLIPH 0x5b /* Channel loop interrupt pending high register */ + +#define SOLEL 0x5c /* Stop on loop enable low register */ + +#define SOLEH 0x5d /* Stop on loop enable high register */ + +#define SPBYPASS 0x5e /* SPDIF BYPASS mode register */ +#define SPBYPASS_ENABLE 0x00000001 /* Enable SPDIF bypass mode */ + +#define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */ + +#define GPSRCS 0x61 /* General Purpose SPDIF sample rate cvt status */ + +#define ZVSRCS 0x62 /* ZVideo sample rate converter status */ + /* NOTE: This one has no SPDIFLOCKED field */ + /* Assumes sample lock */ + +/* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS. */ +#define SRCS_SPDIFLOCKED 0x02000000 /* SPDIF stream locked */ +#define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */ +#define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */ + +#define MICIDX 0x63 /* Microphone recording buffer index register */ +#define MICIDX_MASK 0x0000ffff /* 16-bit value */ +#define MICIDX_IDX 0x10000063 + +#define ADCIDX 0x64 /* ADC recording buffer index register */ +#define ADCIDX_MASK 0x0000ffff /* 16 bit index field */ +#define ADCIDX_IDX 0x10000064 + +#define FXIDX 0x65 /* FX recording buffer index register */ +#define FXIDX_MASK 0x0000ffff /* 16-bit value */ +#define FXIDX_IDX 0x10000065 + +/* Each FX general purpose register is 32 bits in length, all bits are used */ +#define FXGPREGBASE 0x100 /* FX general purpose registers base */ + +/* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is */ +/* decompressed back to 20 bits on a read. There are a total of 160 locations, the last 32 */ +/* locations are for external TRAM. */ +#define TANKMEMDATAREGBASE 0x200 /* Tank memory data registers base */ +#define TANKMEMDATAREG_MASK 0x000fffff /* 20 bit tank audio data field */ + +/* Combined address field and memory opcode or flag field. 160 locations, last 32 are external */ +#define TANKMEMADDRREGBASE 0x300 /* Tank memory address registers base */ +#define TANKMEMADDRREG_ADDR_MASK 0x000fffff /* 20 bit tank address field */ +#define TANKMEMADDRREG_CLEAR 0x00800000 /* Clear tank memory */ +#define TANKMEMADDRREG_ALIGN 0x00400000 /* Align read or write relative to tank access */ +#define TANKMEMADDRREG_WRITE 0x00200000 /* Write to tank memory */ +#define TANKMEMADDRREG_READ 0x00100000 /* Read from tank memory */ + +#define MICROCODEBASE 0x400 /* Microcode data base address */ + +/* Each DSP microcode instruction is mapped into 2 doublewords */ +/* NOTE: When writing, always write the LO doubleword first. Reads can be in either order. */ +#define LOWORD_OPX_MASK 0x000ffc00 /* Instruction operand X */ +#define LOWORD_OPY_MASK 0x000003ff /* Instruction operand Y */ +#define HIWORD_OPCODE_MASK 0x00f00000 /* Instruction opcode */ +#define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */ +#define HIWORD_OPA_MASK 0x000003ff /* Instruction operand A */ + +#endif /* _8010_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/Makefile linux/drivers/sound/emu10k1/Makefile --- v2.3.99-pre5/linux/drivers/sound/emu10k1/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/Makefile Fri Apr 21 16:08:45 2000 @@ -0,0 +1,29 @@ +# Makefile for Creative Labs EMU10K1 +# +# 12 Apr 2000 Rui Sousa + +ifeq ($(CONFIG_SOUND_EMU10K1),y) + O_TARGET := emu10k1.o + O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \ + emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \ + osutils.o recmgr.o timer.o voicemgr.o +else + ifeq ($(CONFIG_SOUND_EMU10K1),m) + M_OBJS := emu10k1.o + O_TARGET := emu10k1.o + O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \ + emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \ + osutils.o recmgr.o timer.o voicemgr.o + endif +endif + +EXTRA_CFLAGS += -I. + +ifdef DEBUG + EXTRA_CFLAGS += -DEMU10K1_DEBUG +endif + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/audio.c linux/drivers/sound/emu10k1/audio.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/audio.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/audio.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,1441 @@ + +/* + ********************************************************************** + * audio.c -- /dev/dsp interface for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up types/leaks + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "cardwo.h" +#include "cardwi.h" +#include "recmgr.h" +#include "audio.h" + +static void calculate_ofrag(struct woinst *); +static void calculate_ifrag(struct wiinst *); + +/* Audio file operations */ +static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int nOrigin) +{ + return -ESPIPE; +} + +static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, loff_t * ppos) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + struct wiinst *wiinst = wave_dev->wiinst; + struct wave_in *wave_in; + ssize_t ret = 0; + unsigned long flags; + + DPD(4, "emu10k1_audio_read(), buffer=%p, count=%x\n", buffer, (u32) count); + + if (ppos != &file->f_pos) + return -ESPIPE; + + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + + spin_lock_irqsave(&wiinst->lock, flags); + + if (wiinst->mapped) { + spin_unlock_irqrestore(&wiinst->lock, flags); + return -ENXIO; + } + + if (!wiinst->wave_in) { + calculate_ifrag(wiinst); + + while (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) { + spin_unlock_irqrestore(&wiinst->lock, flags); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + UP_INODE_SEM(&inode->i_sem); + interruptible_sleep_on(&wave_dev->card->open_wait); + DOWN_INODE_SEM(&inode->i_sem); + + if (signal_pending(current)) + return -ERESTARTSYS; + + spin_lock_irqsave(&wiinst->lock, flags); + } + } + + wave_in = wiinst->wave_in; + + spin_unlock_irqrestore(&wiinst->lock, flags); + + while (count > 0) { + u32 bytestocopy, dummy; + + spin_lock_irqsave(&wiinst->lock, flags); + + if ((wave_in->state != CARDWAVE_STATE_STARTED) + && (wave_dev->enablebits & PCM_ENABLE_INPUT)) + emu10k1_wavein_start(wave_dev); + + emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); + + spin_unlock_irqrestore(&wiinst->lock, flags); + + DPD(4, "bytestocopy --> %x\n", bytestocopy); + + if ((bytestocopy >= wiinst->fragment_size) + || (bytestocopy >= count)) { + bytestocopy = min(bytestocopy, count); + + emu10k1_wavein_xferdata(wiinst, (u8 *) buffer, &bytestocopy); + + count -= bytestocopy; + buffer += bytestocopy; + ret += bytestocopy; + } + + if (count > 0) { + if ((file->f_flags & O_NONBLOCK) + || (!(wave_dev->enablebits & PCM_ENABLE_INPUT))) + return (ret ? ret : -EAGAIN); + + UP_INODE_SEM(&inode->i_sem); + interruptible_sleep_on(&wiinst->wait_queue); + DOWN_INODE_SEM(&inode->i_sem); + + if (signal_pending(current)) + return (ret ? ret : -ERESTARTSYS); + + } + } + + DPD(4, "bytes copied -> %x\n", (u32) ret); + + return ret; +} + +static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out; + ssize_t ret; + unsigned long flags; + + GET_INODE_STRUCT(); + + DPD(4, "emu10k1_audio_write(), buffer=%p, count=%x\n", buffer, (u32) count); + + if (ppos != &file->f_pos) + return -ESPIPE; + + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + + spin_lock_irqsave(&woinst->lock, flags); + + if (woinst->mapped) { + spin_unlock_irqrestore(&woinst->lock, flags); + return -ENXIO; + } + + if (!woinst->wave_out) { + calculate_ofrag(woinst); + + while (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) { + spin_unlock_irqrestore(&woinst->lock, flags); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + UP_INODE_SEM(&inode->i_sem); + interruptible_sleep_on(&wave_dev->card->open_wait); + DOWN_INODE_SEM(&inode->i_sem); + + if (signal_pending(current)) + return -ERESTARTSYS; + + spin_lock_irqsave(&woinst->lock, flags); + } + } + + wave_out = woinst->wave_out; + + spin_unlock_irqrestore(&woinst->lock, flags); + + ret = 0; + while (count > 0) { + u32 bytestocopy, pending, dummy; + + spin_lock_irqsave(&woinst->lock, flags); + + emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); + + spin_unlock_irqrestore(&woinst->lock, flags); + + DPD(4, "bytestocopy --> %x\n", bytestocopy); + + if ((bytestocopy >= woinst->fragment_size) + || (bytestocopy >= count)) { + + bytestocopy = min(bytestocopy, count); + + emu10k1_waveout_xferdata(woinst, (u8 *) buffer, &bytestocopy); + + count -= bytestocopy; + buffer += bytestocopy; + ret += bytestocopy; + + spin_lock_irqsave(&woinst->lock, flags); + woinst->total_copied += bytestocopy; + + if ((wave_out->state != CARDWAVE_STATE_STARTED) + && (wave_dev->enablebits & PCM_ENABLE_OUTPUT) + && (woinst->total_copied >= woinst->fragment_size)) { + + if (emu10k1_waveout_start(wave_dev) != CTSTATUS_SUCCESS) { + spin_unlock_irqrestore(&woinst->lock, flags); + ERROR(); + return -EFAULT; + } + } + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (count > 0) { + if ((file->f_flags & O_NONBLOCK) + || (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT))) + return (ret ? ret : -EAGAIN); + + UP_INODE_SEM(&inode->i_sem); + interruptible_sleep_on(&woinst->wait_queue); + DOWN_INODE_SEM(&inode->i_sem); + + if (signal_pending(current)) + return (ret ? ret : -ERESTARTSYS); + } + } + + DPD(4, "bytes copied -> %x\n", (u32) ret); + + return ret; +} + +static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + int val = 0; + struct woinst *woinst = NULL; + struct wave_out *wave_out = NULL; + struct wiinst *wiinst = NULL; + struct wave_in *wave_in = NULL; + u32 pending, bytestocopy, dummy; + unsigned long flags; + + DPF(4, "emu10k1_audio_ioctl()\n"); + + if (file->f_mode & FMODE_WRITE) { + woinst = wave_dev->woinst; + spin_lock_irqsave(&woinst->lock, flags); + wave_out = woinst->wave_out; + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (file->f_mode & FMODE_READ) { + wiinst = wave_dev->wiinst; + spin_lock_irqsave(&wiinst->lock, flags); + wave_in = wiinst->wave_in; + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + switch (cmd) { + case OSS_GETVERSION: + DPF(2, "OSS_GETVERSION:\n"); + return put_user(SOUND_VERSION, (int *) arg); + + case SNDCTL_DSP_RESET: + DPF(2, "SNDCTL_DSP_RESET:\n"); + wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; + + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + if (wave_out) + emu10k1_waveout_close(wave_dev); + + woinst->total_copied = 0; + woinst->total_played = 0; + woinst->blocks = 0; + woinst->curpos = 0; + + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + if (wave_in) + emu10k1_wavein_close(wave_dev); + + wiinst->total_recorded = 0; + wiinst->blocks = 0; + wiinst->curpos = 0; + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + break; + + case SNDCTL_DSP_SYNC: + DPF(2, "SNDCTL_DSP_SYNC:\n"); + + if (file->f_mode & FMODE_WRITE) { + + if (wave_out) { + spin_lock_irqsave(&woinst->lock, flags); + + if (wave_out->state == CARDWAVE_STATE_STARTED) + while ((woinst->total_played < woinst->total_copied) + && !signal_pending(current)) { + spin_unlock_irqrestore(&woinst->lock, flags); + interruptible_sleep_on(&woinst->wait_queue); + spin_lock_irqsave(&woinst->lock, flags); + } + + emu10k1_waveout_close(wave_dev); + woinst->total_copied = 0; + woinst->total_played = 0; + woinst->blocks = 0; + woinst->curpos = 0; + + spin_unlock_irqrestore(&woinst->lock, flags); + } + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + if (wave_in) + emu10k1_wavein_close(wave_dev); + + wiinst->total_recorded = 0; + wiinst->blocks = 0; + wiinst->curpos = 0; + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + break; + + case SNDCTL_DSP_SETDUPLEX: + DPF(2, "SNDCTL_DSP_SETDUPLEX:\n"); + break; + + case SNDCTL_DSP_GETCAPS: + DPF(2, "SNDCTL_DSP_GETCAPS:\n"); + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_COPROC, (int *) arg); + + case SNDCTL_DSP_SPEED: + DPF(2, "SNDCTL_DSP_SPEED:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + DPD(2, "val is %d\n", val); + + if (val >= 0) { + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + woinst->wave_fmt.samplingrate = val; + + if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = woinst->wave_fmt.samplingrate; + + spin_unlock_irqrestore(&woinst->lock, flags); + + DPD(2, "set playback sampling rate -> %d\n", val); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + wiinst->wave_fmt.samplingrate = val; + + if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = wiinst->wave_fmt.samplingrate; + + spin_unlock_irqrestore(&wiinst->lock, flags); + + DPD(2, "set recording sampling rate -> %d\n", val); + } + + return put_user(val, (int *) arg); + } else { + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.samplingrate; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.samplingrate; + + return put_user(val, (int *) arg); + } + break; + + case SNDCTL_DSP_STEREO: + DPF(2, "SNDCTL_DSP_STEREO:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + DPD(2, " val is %d\n", val); + + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + woinst->wave_fmt.channels = val ? 2 : 1; + + if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = woinst->wave_fmt.channels - 1; + + spin_unlock_irqrestore(&woinst->lock, flags); + + DPD(2, "set playback stereo -> %d\n", val); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + wiinst->wave_fmt.channels = val ? 2 : 1; + + if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = wiinst->wave_fmt.channels - 1; + + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording stereo -> %d\n", val); + } + + return put_user(val, (int *) arg); + + break; + + case SNDCTL_DSP_CHANNELS: + DPF(2, "SNDCTL_DSP_CHANNELS:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + DPD(2, " val is %d\n", val); + + if (val != 0) { + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + woinst->wave_fmt.channels = val; + + if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = woinst->wave_fmt.channels; + + spin_unlock_irqrestore(&woinst->lock, flags); + DPD(2, "set playback number of channels -> %d\n", val); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + wiinst->wave_fmt.channels = val; + + if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = wiinst->wave_fmt.channels; + + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording number of channels -> %d\n", val); + } + + return put_user(val, (int *) arg); + } else { + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.channels; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.channels; + + return put_user(val, (int *) arg); + } + break; + + case SNDCTL_DSP_GETFMTS: + DPF(2, "SNDCTL_DSP_GETFMTS:\n"); + + if (file->f_mode & FMODE_READ) + val = AFMT_S16_LE; + else if (file->f_mode & FMODE_WRITE) + val = AFMT_S16_LE | AFMT_U8; + + return put_user(val, (int *) arg); + + case SNDCTL_DSP_SETFMT: /* Same as SNDCTL_DSP_SAMPLESIZE */ + DPF(2, "SNDCTL_DSP_SETFMT:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + DPD(2, " val is %d\n", val); + + if (val != AFMT_QUERY) { + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + woinst->wave_fmt.bitsperchannel = val; + + if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = woinst->wave_fmt.bitsperchannel; + + spin_unlock_irqrestore(&woinst->lock, flags); + DPD(2, "set playback sample size -> %d\n", val); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + wiinst->wave_fmt.bitsperchannel = val; + + if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + return -EINVAL; + + val = wiinst->wave_fmt.bitsperchannel; + + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording sample size -> %d\n", val); + } + + return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); + } else { + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.bitsperchannel; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.bitsperchannel; + + return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); + } + break; + + case SOUND_PCM_READ_BITS: + + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.bitsperchannel; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.bitsperchannel; + + return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); + + case SOUND_PCM_READ_RATE: + + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.samplingrate; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.samplingrate; + + return put_user(val, (int *) arg); + + case SOUND_PCM_READ_CHANNELS: + + if (file->f_mode & FMODE_READ) + val = wiinst->wave_fmt.channels; + else if (file->f_mode & FMODE_WRITE) + val = woinst->wave_fmt.channels; + + return put_user(val, (int *) arg); + + case SOUND_PCM_WRITE_FILTER: + DPF(2, "SOUND_PCM_WRITE_FILTER: not implemented\n"); + break; + + case SOUND_PCM_READ_FILTER: + DPF(2, "SOUND_PCM_READ_FILTER: not implemented\n"); + break; + + case SNDCTL_DSP_SETSYNCRO: + DPF(2, "SNDCTL_DSP_SETSYNCRO: not implemented\n"); + break; + + case SNDCTL_DSP_GETTRIGGER: + DPF(2, "SNDCTL_DSP_GETTRIGGER:\n"); + + if (file->f_mode & FMODE_WRITE && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)) + val |= PCM_ENABLE_OUTPUT; + if (file->f_mode & FMODE_READ && (wave_dev->enablebits & PCM_ENABLE_INPUT)) + val |= PCM_ENABLE_INPUT; + + return put_user(val, (int *) arg); + + case SNDCTL_DSP_SETTRIGGER: + DPF(2, "SNDCTL_DSP_SETTRIGGER:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + if (val & PCM_ENABLE_OUTPUT) { + wave_dev->enablebits |= PCM_ENABLE_OUTPUT; + if (wave_out) + emu10k1_waveout_start(wave_dev); + } else { + wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT; + if (wave_out) + emu10k1_waveout_stop(wave_dev); + } + + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + if (val & PCM_ENABLE_INPUT) { + wave_dev->enablebits |= PCM_ENABLE_INPUT; + if (wave_in) + emu10k1_wavein_start(wave_dev); + } else { + wave_dev->enablebits &= ~PCM_ENABLE_INPUT; + if (wave_in) + emu10k1_wavein_stop(wave_dev); + } + + spin_unlock_irqrestore(&wiinst->lock, flags); + } + break; + + case SNDCTL_DSP_GETOSPACE: + { + audio_buf_info info; + + DPF(4, "SNDCTL_DSP_GETOSPACE:\n"); + + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + + if (wave_out) { + spin_lock_irqsave(&woinst->lock, flags); + emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); + spin_unlock_irqrestore(&woinst->lock, flags); + + info.bytes = bytestocopy; + } else { + spin_lock_irqsave(&woinst->lock, flags); + calculate_ofrag(woinst); + spin_unlock_irqrestore(&woinst->lock, flags); + + info.bytes = woinst->numfrags * woinst->fragment_size; + } + + info.fragstotal = woinst->numfrags; + info.fragments = info.bytes / woinst->fragment_size; + info.fragsize = woinst->fragment_size; + + if (copy_to_user((int *) arg, &info, sizeof(info))) + return -EFAULT; + } + break; + + case SNDCTL_DSP_GETISPACE: + { + audio_buf_info info; + + DPF(4, "SNDCTL_DSP_GETISPACE:\n"); + + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + + if (wave_in) { + spin_lock_irqsave(&wiinst->lock, flags); + emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); + spin_unlock_irqrestore(&wiinst->lock, flags); + + info.bytes = bytestocopy; + } else { + spin_lock_irqsave(&wiinst->lock, flags); + calculate_ifrag(wiinst); + spin_unlock_irqrestore(&wiinst->lock, flags); + + info.bytes = 0; + } + + info.fragstotal = wiinst->numfrags; + info.fragments = info.bytes / wiinst->fragment_size; + info.fragsize = wiinst->fragment_size; + + if (copy_to_user((int *) arg, &info, sizeof(info))) + return -EFAULT; + } + break; + + case SNDCTL_DSP_NONBLOCK: + DPF(2, "SNDCTL_DSP_NONBLOCK:\n"); + + file->f_flags |= O_NONBLOCK; + break; + + case SNDCTL_DSP_GETODELAY: + DPF(4, "SNDCTL_DSP_GETODELAY:\n"); + + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + + if (wave_out) { + spin_lock_irqsave(&woinst->lock, flags); + emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); + spin_unlock_irqrestore(&woinst->lock, flags); + + val = pending; + } else + val = 0; + + return put_user(val, (int *) arg); + + case SNDCTL_DSP_GETIPTR: + { + count_info cinfo; + + DPF(4, "SNDCTL_DSP_GETIPTR: \n"); + + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + + spin_lock_irqsave(&wiinst->lock, flags); + + if (wave_in) { + emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, (u32 *) & cinfo.ptr); + cinfo.bytes = + cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % (wiinst->fragment_size * wiinst->numfrags); + cinfo.blocks = cinfo.bytes / wiinst->fragment_size - wiinst->blocks; + wiinst->blocks = cinfo.bytes / wiinst->fragment_size; + } else { + cinfo.ptr = 0; + cinfo.bytes = 0; + cinfo.blocks = 0; + wiinst->blocks = 0; + } + + spin_unlock_irqrestore(&wiinst->lock, flags); + + if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo))) + return -EFAULT; + } + break; + + case SNDCTL_DSP_GETOPTR: + { + count_info cinfo; + + DPF(4, "SNDCTL_DSP_GETOPTR:\n"); + + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + + spin_lock_irqsave(&woinst->lock, flags); + + if (wave_out) { + emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, (u32 *) & cinfo.ptr); + cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % (woinst->fragment_size * woinst->numfrags); + cinfo.blocks = cinfo.bytes / woinst->fragment_size - woinst->blocks; + woinst->blocks = cinfo.bytes / woinst->fragment_size; + } else { + cinfo.ptr = 0; + cinfo.bytes = 0; + cinfo.blocks = 0; + woinst->blocks = 0; + } + + spin_unlock_irqrestore(&woinst->lock, flags); + + if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo))) + return -EFAULT; + } + break; + + case SNDCTL_DSP_GETBLKSIZE: + DPF(2, "SNDCTL_DSP_GETBLKSIZE:\n"); + + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + calculate_ofrag(woinst); + val = woinst->fragment_size; + + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (file->f_mode & FMODE_READ) { + spin_lock_irqsave(&wiinst->lock, flags); + + calculate_ifrag(wiinst); + val = wiinst->fragment_size; + + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + return put_user(val, (int *) arg); + + break; + + case SNDCTL_DSP_POST: + DPF(2, "SNDCTL_DSP_POST: not implemented\n"); + break; + + case SNDCTL_DSP_SUBDIVIDE: + DPF(2, "SNDCTL_DSP_SUBDIVIDE: not implemented\n"); + break; + + case SNDCTL_DSP_SETFRAGMENT: + DPF(2, "SNDCTL_DSP_SETFRAGMENT:\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + + DPD(2, "val is %x\n", val); + + if (val == 0) + return -EIO; + + if (file->f_mode & FMODE_WRITE) { + if (wave_out) + return -EINVAL; /* too late to change */ + + woinst->ossfragshift = val & 0xffff; + woinst->numfrags = (val >> 16) & 0xffff; + } + + if (file->f_mode & FMODE_READ) { + if (wave_in) + return -EINVAL; /* too late to change */ + + wiinst->ossfragshift = val & 0xffff; + wiinst->numfrags = (val >> 16) & 0xffff; + } + + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer buf; + u32 i; + + DPF(2, "SNDCTL_COPR_LOAD:\n"); + + if (copy_from_user(&buf, (copr_buffer *) arg, sizeof(buf))) + return -EFAULT; + + if ((buf.command != 1) && (buf.command != 2)) + return -EINVAL; + + if (((buf.offs < 0x100) && (buf.command == 2)) + || (buf.offs < 0x000) + || (buf.offs + buf.len > 0x800) || (buf.len > 1000)) + return -EINVAL; + + if (buf.command == 1) { + for (i = 0; i < buf.len; i++) + + ((u32 *) buf.data)[i] = sblive_readptr(wave_dev->card, buf.offs + i, 0); + if (copy_to_user((copr_buffer *) arg, &buf, sizeof(buf))) + return -EFAULT; + } else { + for (i = 0; i < buf.len; i++) + sblive_writeptr(wave_dev->card, buf.offs + i, 0, ((u32 *) buf.data)[i]); + } + break; + } + + default: /* Default is unrecognized command */ + DPD(2, "default: %x\n", cmd); + return -EINVAL; + } + return 0; +} + +static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + + DPF(2, "emu10k1_audio_mmap()\n"); + + if (vma_get_pgoff(vma) != 0) + return -ENXIO; + + if (vma->vm_flags & VM_WRITE) { + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out; + u32 size; + unsigned long flags; + int i; + + spin_lock_irqsave(&woinst->lock, flags); + + wave_out = woinst->wave_out; + + if (!wave_out) { + calculate_ofrag(woinst); + + if (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) { + spin_unlock_irqrestore(&woinst->lock, flags); + ERROR(); + return -EINVAL; + } + + wave_out = woinst->wave_out; + + /* Now mark the pages as reserved, otherwise remap_page_range doesn't do what we want */ + for (i = 0; i < wave_out->wavexferbuf->numpages; i++) + set_bit(PG_reserved, &mem_map[MAP_NR(wave_out->pagetable[i])].flags); + } + + size = vma->vm_end - vma->vm_start; + + if (size > (PAGE_SIZE * wave_out->wavexferbuf->numpages)) { + spin_unlock_irqrestore(&woinst->lock, flags); + return -EINVAL; + } + + for (i = 0; i < wave_out->wavexferbuf->numpages; i++) { + if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(wave_out->pagetable[i]), PAGE_SIZE, vma->vm_page_prot)) { + spin_unlock_irqrestore(&woinst->lock, flags); + return -EAGAIN; + } + } + + woinst->mapped = 1; + + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (vma->vm_flags & VM_READ) { + struct wiinst *wiinst = wave_dev->wiinst; + unsigned long flags; + + spin_lock_irqsave(&wiinst->lock, flags); + wiinst->mapped = 1; + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + return 0; +} + +static int emu10k1_audio_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct emu10k1_card *card; + struct list_head *entry; + struct emu10k1_wavedevice *wave_dev; + + DPF(2, "emu10k1_audio_open()\n"); + + /* Check for correct device to open */ + + list_for_each(entry, &emu10k1_devs) { + card = list_entry(entry, struct emu10k1_card, list); + + if (card->audio1_num == minor || card->audio2_num == minor) + break; + } + + if (entry == &emu10k1_devs) + return -ENODEV; + + MOD_INC_USE_COUNT; + + if ((wave_dev = (struct emu10k1_wavedevice *) + kmalloc(sizeof(struct emu10k1_wavedevice), GFP_KERNEL)) == NULL) { + ERROR(); + MOD_DEC_USE_COUNT; + return -EINVAL; + } + + wave_dev->card = card; + wave_dev->wiinst = NULL; + wave_dev->woinst = NULL; + wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; /* Default */ + + if (file->f_mode & FMODE_WRITE) { + struct woinst *woinst; + + if ((woinst = (struct woinst *) kmalloc(sizeof(struct woinst), GFP_KERNEL)) == NULL) { + ERROR(); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + woinst->wave_fmt.samplingrate = 8000; + woinst->wave_fmt.bitsperchannel = 8; + woinst->wave_fmt.channels = 1; + woinst->ossfragshift = 0; + woinst->fragment_size = 0; + woinst->numfrags = 0; + woinst->device = (card->audio2_num == minor); + woinst->wave_out = NULL; + + init_waitqueue_head(&woinst->wait_queue); + + woinst->mapped = 0; + woinst->total_copied = 0; + woinst->total_played = 0; + woinst->blocks = 0; + woinst->curpos = 0; + woinst->lock = SPIN_LOCK_UNLOCKED; + wave_dev->woinst = woinst; + +#ifdef PRIVATE_PCM_VOLUME + { + int i; + int j = -1; + + /* + * find out if we've already been in this table + * xmms reopens dsp on every move of slider + * this way we keep the same local pcm for such + * process + */ + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) + break; + // here we should select last used memeber + // improve me in case its not sufficient + if (j < 0 && !sblive_pcm_volume[i].opened) + j = i; + } + // current task not found + if (i == MAX_PCM_CHANNELS) { + // add new entry + if (j < 0) + printk("TOO MANY WRITTERS!!!\n"); + i = (j >= 0) ? j : 0; + DPD(2, "new pcm private %p\n", current->files); + sblive_pcm_volume[i].files = current->files; + sblive_pcm_volume[i].mixer = 0x6464; // max + sblive_pcm_volume[i].attn_l = 0; + sblive_pcm_volume[i].attn_r = 0; + sblive_pcm_volume[i].channel_l = NUM_G; + sblive_pcm_volume[i].channel_r = NUM_G; + } + sblive_pcm_volume[i].opened++; + } +#endif + } + + if (file->f_mode & FMODE_READ) { + /* Recording */ + struct wiinst *wiinst; + + if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) { + ERROR(); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + switch (card->wavein->recsrc) { + case WAVERECORD_AC97: + wiinst->wave_fmt.samplingrate = 8000; + wiinst->wave_fmt.bitsperchannel = 8; + wiinst->wave_fmt.channels = 1; + break; + case WAVERECORD_MIC: + wiinst->wave_fmt.samplingrate = 8000; + wiinst->wave_fmt.bitsperchannel = 8; + wiinst->wave_fmt.channels = 1; + break; + case WAVERECORD_FX: + wiinst->wave_fmt.samplingrate = 48000; + wiinst->wave_fmt.bitsperchannel = 16; + wiinst->wave_fmt.channels = 2; + break; + default: + break; + } + + wiinst->recsrc = card->wavein->recsrc; + wiinst->ossfragshift = 0; + wiinst->fragment_size = 0; + wiinst->numfrags = 0; + wiinst->wave_in = NULL; + + init_waitqueue_head(&wiinst->wait_queue); + + wiinst->mapped = 0; + wiinst->total_recorded = 0; + wiinst->blocks = 0; + wiinst->curpos = 0; + wiinst->lock = SPIN_LOCK_UNLOCKED; + wave_dev->wiinst = wiinst; + } + + file->private_data = (void *) wave_dev; + + return 0; /* Success? */ +} + +static int emu10k1_audio_release(struct inode *inode, struct file *file) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + struct emu10k1_card *card = wave_dev->card; + unsigned long flags; + + DPF(2, "emu10k1_audio_release()\n"); + + if (file->f_mode & FMODE_WRITE) { + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out; + + spin_lock_irqsave(&woinst->lock, flags); + + wave_out = woinst->wave_out; + + if (wave_out) { + if ((wave_out->state == CARDWAVE_STATE_STARTED) + && !(file->f_flags & O_NONBLOCK)) { + while (!signal_pending(current) + && (woinst->total_played < woinst->total_copied)) { + DPF(4, "Buffer hasn't been totally played, sleep....\n"); + spin_unlock_irqrestore(&woinst->lock, flags); + interruptible_sleep_on(&woinst->wait_queue); + spin_lock_irqsave(&woinst->lock, flags); + } + } + + if (woinst->mapped && wave_out->pagetable) { + int i; + + /* Undo marking the pages as reserved */ + for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++) + set_bit(PG_reserved, &mem_map[MAP_NR(woinst->wave_out->pagetable[i])].flags); + } + + woinst->mapped = 0; + emu10k1_waveout_close(wave_dev); + } +#ifdef PRIVATE_PCM_VOLUME + { + int i; + + /* mark as closed + * NOTE: structure remains unchanged for next reopen */ + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + sblive_pcm_volume[i].opened--; + break; + } + } + } +#endif + spin_unlock_irqrestore(&woinst->lock, flags); + kfree(wave_dev->woinst); + } + + if (file->f_mode & FMODE_READ) { + struct wiinst *wiinst = wave_dev->wiinst; + struct wave_in *wave_in; + + spin_lock_irqsave(&wiinst->lock, flags); + + wave_in = wiinst->wave_in; + + if (wave_in) { + wiinst->mapped = 0; + emu10k1_wavein_close(wave_dev); + } + spin_unlock_irqrestore(&wiinst->lock, flags); + kfree(wave_dev->wiinst); + } + + kfree(wave_dev); + + wake_up_interruptible(&card->open_wait); + MOD_DEC_USE_COUNT; + + return 0; +} + +static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_struct *wait) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; + struct woinst *woinst = wave_dev->woinst; + struct wiinst *wiinst = wave_dev->wiinst; + unsigned int mask = 0; + u32 bytestocopy, pending, dummy; + unsigned long flags; + + DPF(4, "emu10k1_audio_poll()\n"); + + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &woinst->wait_queue, wait); + + if (file->f_mode & FMODE_READ) + poll_wait(file, &wiinst->wait_queue, wait); + + if (file->f_mode & FMODE_WRITE) { + struct wave_out *wave_out; + + spin_lock_irqsave(&woinst->lock, flags); + + wave_out = woinst->wave_out; + + if (wave_out) { + + emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); + + if (bytestocopy >= woinst->fragment_size) + mask |= POLLOUT | POLLWRNORM; + } else + mask |= POLLOUT | POLLWRNORM; + + spin_unlock_irqrestore(&woinst->lock, flags); + } + + if (file->f_mode & FMODE_READ) { + struct wave_in *wave_in; + + spin_lock_irqsave(&wiinst->lock, flags); + + wave_in = wiinst->wave_in; + + if (!wave_in) { + calculate_ifrag(wiinst); + if (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) { + spin_unlock_irqrestore(&wiinst->lock, flags); + return (mask |= POLLERR); + } + + wave_in = wiinst->wave_in; + } + + if (wave_in->state != CARDWAVE_STATE_STARTED) { + wave_dev->enablebits |= PCM_ENABLE_INPUT; + emu10k1_wavein_start(wave_dev); + } + + emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); + + if (bytestocopy >= wiinst->fragment_size) + mask |= POLLIN | POLLRDNORM; + + spin_unlock_irqrestore(&wiinst->lock, flags); + } + + return mask; +} + +static void calculate_ofrag(struct woinst *woinst) +{ + u32 fragsize, bytespersec; + + if (woinst->fragment_size) + return; + + bytespersec = woinst->wave_fmt.channels * (woinst->wave_fmt.bitsperchannel >> 3) * woinst->wave_fmt.samplingrate; + + if (!woinst->ossfragshift) { + fragsize = (bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1; + + while (fragsize) { + fragsize >>= 1; + woinst->ossfragshift++; + } + } + + if (woinst->ossfragshift < WAVEOUT_MINFRAGSHIFT) + woinst->ossfragshift = WAVEOUT_MINFRAGSHIFT; + + woinst->fragment_size = 1 << woinst->ossfragshift; + + if (!woinst->numfrags) { + u32 numfrags; + + numfrags = (bytespersec * WAVEOUT_DEFAULTBUFLEN) / (woinst->fragment_size * 1000) - 1; + + woinst->numfrags = 1; + + while (numfrags) { + numfrags >>= 1; + woinst->numfrags <<= 1; + } + } + + if (woinst->numfrags < MINFRAGS) + woinst->numfrags = MINFRAGS; + + if (woinst->numfrags * woinst->fragment_size > WAVEOUT_MAXBUFSIZE) { + woinst->numfrags = WAVEOUT_MAXBUFSIZE / woinst->fragment_size; + + if (woinst->numfrags < MINFRAGS) { + woinst->numfrags = MINFRAGS; + woinst->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS; + } + + } else if (woinst->numfrags * woinst->fragment_size < WAVEOUT_MINBUFSIZE) + woinst->numfrags = WAVEOUT_MINBUFSIZE / woinst->fragment_size; + + DPD(2, " calculated playback fragment_size -> %d\n", woinst->fragment_size); + DPD(2, " calculated playback numfrags -> %d\n", woinst->numfrags); +} + +static void calculate_ifrag(struct wiinst *wiinst) +{ + u32 fragsize, bytespersec; + + if (wiinst->fragment_size) + return; + + bytespersec = wiinst->wave_fmt.channels * (wiinst->wave_fmt.bitsperchannel >> 3) * wiinst->wave_fmt.samplingrate; + + if (!wiinst->ossfragshift) { + fragsize = (bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1; + + while (fragsize) { + fragsize >>= 1; + wiinst->ossfragshift++; + } + } + + if (wiinst->ossfragshift < WAVEIN_MINFRAGSHIFT) + wiinst->ossfragshift = WAVEIN_MINFRAGSHIFT; + + wiinst->fragment_size = 1 << wiinst->ossfragshift; + + if (!wiinst->numfrags) + wiinst->numfrags = (bytespersec * WAVEIN_DEFAULTBUFLEN) / (wiinst->fragment_size * 1000) - 1; + + if (wiinst->numfrags < MINFRAGS) + wiinst->numfrags = MINFRAGS; + + if (wiinst->numfrags * wiinst->fragment_size > WAVEIN_MAXBUFSIZE) { + wiinst->numfrags = WAVEIN_MAXBUFSIZE / wiinst->fragment_size; + + if (wiinst->numfrags < MINFRAGS) { + wiinst->numfrags = MINFRAGS; + wiinst->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS; + } + } else if (wiinst->numfrags * wiinst->fragment_size < WAVEIN_MINBUFSIZE) + wiinst->numfrags = WAVEIN_MINBUFSIZE / wiinst->fragment_size; + + DPD(2, " calculated recording fragment_size -> %d\n", wiinst->fragment_size); + DPD(2, " calculated recording numfrags -> %d\n", wiinst->numfrags); +} + +void emu10k1_wavein_bh(unsigned long refdata) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata; + struct wiinst *wiinst = wave_dev->wiinst; + struct wave_in *wave_in = wiinst->wave_in; + u32 bytestocopy, curpos; + unsigned long flags; + + spin_lock_irqsave(&wiinst->lock, flags); + + if (wave_in->state == CARDWAVE_STATE_STOPPED) { + spin_unlock_irqrestore(&wiinst->lock, flags); + return; + } + + emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &curpos); + + wiinst->total_recorded += curpos - wiinst->curpos; + + if (curpos < wiinst->curpos) + wiinst->total_recorded += wiinst->fragment_size * wiinst->numfrags; + + wiinst->curpos = curpos; + + if (wiinst->mapped) { + spin_unlock_irqrestore(&wiinst->lock, flags); + return; + } + + spin_unlock_irqrestore(&wiinst->lock, flags); + + if (bytestocopy >= wiinst->fragment_size) + wake_up_interruptible(&wiinst->wait_queue); + else + DPD(4, "Not enough transfer size, %d\n", bytestocopy); + + return; +} + +void emu10k1_waveout_bh(unsigned long refdata) +{ + struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata; + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out = woinst->wave_out; + u32 bytestocopy, pending, curpos; + unsigned long flags; + + spin_lock_irqsave(&woinst->lock, flags); + + if (wave_out->state == CARDWAVE_STATE_STOPPED) { + spin_unlock_irqrestore(&woinst->lock, flags); + return; + } + + emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &curpos); + + woinst->total_played += curpos - woinst->curpos; + + if (curpos < woinst->curpos) + woinst->total_played += woinst->fragment_size * woinst->numfrags; + + woinst->curpos = curpos; + + if (woinst->mapped) { + spin_unlock_irqrestore(&woinst->lock, flags); + return; + } + + if (wave_out->fill_silence) { + spin_unlock_irqrestore(&woinst->lock, flags); + emu10k1_waveout_fillsilence(woinst); + } else + spin_unlock_irqrestore(&woinst->lock, flags); + + if (bytestocopy >= woinst->fragment_size) + wake_up_interruptible(&woinst->wait_queue); + else + DPD(4, "Not enough transfer size -> %x\n", bytestocopy); + + return; +} + +struct file_operations emu10k1_audio_fops = { + llseek:emu10k1_audio_llseek, + read:emu10k1_audio_read, + write:emu10k1_audio_write, + poll:emu10k1_audio_poll, + ioctl:emu10k1_audio_ioctl, + mmap:emu10k1_audio_mmap, + open:emu10k1_audio_open, + release:emu10k1_audio_release, +}; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/audio.h linux/drivers/sound/emu10k1/audio.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/audio.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/audio.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,46 @@ +/* + ********************************************************************** + * audio.c -- /dev/dsp interface for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up types/leaks + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _AUDIO_H +#define _AUDIO_H + +#define __NO_VERSION__ +#include +#include +#include + +#define MINFRAGS 2 /* _don't_ got bellow 2 */ + +void emu10k1_waveout_bh(unsigned long); +void emu10k1_wavein_bh(unsigned long); + +#endif /* _AUDIO_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmi.c linux/drivers/sound/emu10k1/cardmi.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/cardmi.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,813 @@ + +/* + ********************************************************************** + * sblive_mi.c - MIDI UART input HAL for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox clean up + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "cardmi.h" + +static struct { + int (*Fn) (struct emu10k1_mpuin *, u8); +} midistatefn[] = { + + { + sblive_miStateParse}, { + sblive_miState3Byte}, /* 0x8n, 0x9n, 0xAn, 0xBn, 0xEn */ + { + sblive_miState3ByteKey}, /* Byte 1 */ + { + sblive_miState3ByteVel}, /* Byte 2 */ + { + sblive_miState2Byte}, /* 0xCn, 0xDn */ + { + sblive_miState2ByteKey}, /* Byte 1 */ + { + sblive_miStateSysCommon2}, /* 0xF1 , 0xF3 */ + { + sblive_miStateSysCommon2Key}, /* 0xF1 , 0xF3, Byte 1 */ + { + sblive_miStateSysCommon3}, /* 0xF2 */ + { + sblive_miStateSysCommon3Key}, /* 0xF2 , Byte 1 */ + { + sblive_miStateSysCommon3Vel}, /* 0xF2 , Byte 2 */ + { + sblive_miStateSysExNorm}, /* 0xF0, 0xF7, Normal mode */ + { + sblive_miStateSysReal} /* 0xF4 - 0xF6 ,0xF8 - 0xFF */ +}; + +/* Installs the IRQ handler for the MPU in port */ + +/* and initialize parameters */ + +int emu10k1_mpuin_open(struct emu10k1_card *card, struct midi_openinfo *openinfo) +{ + struct emu10k1_mpuin *card_mpuin = card->mpuin; + + DPF(2, "emu10k1_mpuin_open\n"); + + if (!(card_mpuin->status & FLAGS_AVAILABLE)) + return CTSTATUS_INUSE; + + /* Copy open info and mark channel as in use */ + card_mpuin->openinfo = *openinfo; + card_mpuin->status &= ~FLAGS_AVAILABLE; /* clear */ + card_mpuin->status |= FLAGS_READY; /* set */ + card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ + card_mpuin->firstmidiq = NULL; + card_mpuin->lastmidiq = NULL; + card_mpuin->qhead = 0; + card_mpuin->qtail = 0; + + sblive_miStateInit(card_mpuin); + + emu10k1_mpu_reset(card); + emu10k1_mpu_acquire(card); + + return CTSTATUS_SUCCESS; +} + +int emu10k1_mpuin_close(struct emu10k1_card *card) +{ + struct emu10k1_mpuin *card_mpuin = card->mpuin; + + DPF(2, "emu10k1_mpuin_close()\n"); + + /* Check if there are pending input SysEx buffers */ + if (card_mpuin->firstmidiq != NULL) { + ERROR(); + return CTSTATUS_ERROR; + } + + /* Disable RX interrupt */ + emu10k1_irq_disable(card, INTE_MIDIRXENABLE); + + emu10k1_mpu_release(card); + + card_mpuin->status |= FLAGS_AVAILABLE; /* set */ + card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ + + return CTSTATUS_SUCCESS; +} + +/* Adds MIDI buffer to local queue list */ + +int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *card_mpuin, struct midi_hdr *midihdr) +{ + struct midi_queue *midiq; + unsigned long flags; + + DPF(2, "emu10k1_mpuin_add_buffer()\n"); + + /* Update MIDI buffer flags */ + midihdr->flags |= MIDIBUF_INQUEUE; /* set */ + midihdr->flags &= ~MIDIBUF_DONE; /* clear */ + + if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) { + /* Message lost */ + return CTSTATUS_ERROR; + } + + midiq->next = NULL; + midiq->qtype = 1; + midiq->length = midihdr->bufferlength; + midiq->sizeLeft = midihdr->bufferlength; + midiq->midibyte = midihdr->data; + midiq->refdata = (unsigned long) midihdr; + + spin_lock_irqsave(&card_mpuin->lock, flags); + + if (card_mpuin->firstmidiq == NULL) { + card_mpuin->firstmidiq = midiq; + card_mpuin->lastmidiq = midiq; + } else { + (card_mpuin->lastmidiq)->next = midiq; + card_mpuin->lastmidiq = midiq; + } + + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + return CTSTATUS_SUCCESS; +} + +/* First set the Time Stamp if MIDI IN has not started. */ + +/* Then enable RX Irq. */ + +int emu10k1_mpuin_start(struct emu10k1_card *card) +{ + struct emu10k1_mpuin *card_mpuin = card->mpuin; + u8 dummy; + + DPF(2, "emu10k1_mpuin_start()\n"); + + /* Set timestamp if not set */ + if (card_mpuin->status & FLAGS_MIDM_STARTED) { + DPF(2, "Time Stamp not changed\n"); + } else { + while (emu10k1_mpu_read_data(card, &dummy) == CTSTATUS_SUCCESS); + + card_mpuin->status |= FLAGS_MIDM_STARTED; /* set */ + + /* Set new time stamp */ + card_mpuin->timestart = (jiffies * 1000) / HZ; + DPD(2, "New Time Stamp = %d\n", card_mpuin->timestart); + + card_mpuin->qhead = 0; + card_mpuin->qtail = 0; + + emu10k1_irq_enable(card, INTE_MIDIRXENABLE); + } + + return CTSTATUS_SUCCESS; +} + +/* Disable the RX Irq. If a partial recorded buffer */ + +/* exist, send it up to IMIDI level. */ + +int emu10k1_mpuin_stop(struct emu10k1_card *card) +{ + struct emu10k1_mpuin *card_mpuin = card->mpuin; + struct midi_queue *midiq; + unsigned long flags; + + DPF(2, "emu10k1_mpuin_stop()\n"); + + emu10k1_irq_disable(card, INTE_MIDIRXENABLE); + + card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ + + if (card_mpuin->firstmidiq) { + spin_lock_irqsave(&card_mpuin->lock, flags); + + midiq = card_mpuin->firstmidiq; + if (midiq != NULL) { + if (midiq->sizeLeft == midiq->length) + midiq = NULL; + else { + card_mpuin->firstmidiq = midiq->next; + if (card_mpuin->firstmidiq == NULL) + card_mpuin->lastmidiq = NULL; + } + } + + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + if (midiq) { + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0); + kfree(midiq); + } + } + + return CTSTATUS_SUCCESS; +} + +/* Disable the RX Irq. If any buffer */ + +/* exist, send it up to IMIDI level. */ +int emu10k1_mpuin_reset(struct emu10k1_card *card) +{ + struct emu10k1_mpuin *card_mpuin = card->mpuin; + struct midi_queue *midiq; + + DPF(2, "emu10k1_mpuin_reset()\n"); + + emu10k1_irq_disable(card, INTE_MIDIRXENABLE); + + while (card_mpuin->firstmidiq) { + midiq = card_mpuin->firstmidiq; + card_mpuin->firstmidiq = midiq->next; + + if (midiq->sizeLeft == midiq->length) + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0); + else + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0); + + kfree(midiq); + } + + card_mpuin->lastmidiq = NULL; + card_mpuin->status &= ~FLAGS_MIDM_STARTED; + + return CTSTATUS_SUCCESS; +} + +/* Passes the message with the data back to the client */ + +/* via IRQ & DPC callbacks to Ring 3 */ +int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid) +{ + unsigned long timein; + struct midi_queue *midiq; + unsigned long callback_msg[3]; + struct midi_hdr *midihdr; + + /* Called during ISR. The data & code touched are: + * 1. card_mpuin + * 2. The function to be called + */ + + timein = card_mpuin->timein; + if (card_mpuin->timestart <= timein) + callback_msg[0] = timein - card_mpuin->timestart; + else + callback_msg[0] = (~0x0L - card_mpuin->timestart) + timein; + + if (msg == ICARDMIDI_INDATA || msg == ICARDMIDI_INDATAERROR) { + callback_msg[1] = data; + callback_msg[2] = bytesvalid; + DPD(2, "emu10k1_mpuin_callback: midimsg = %lx\n", data); + } else { + midiq = (struct midi_queue *) data; + midihdr = (struct midi_hdr *) midiq->refdata; + + callback_msg[1] = midiq->length - midiq->sizeLeft; + callback_msg[2] = midiq->refdata; + midihdr->flags &= ~MIDIBUF_INQUEUE; + midihdr->flags |= MIDIBUF_DONE; + + midihdr->bytesrecorded = midiq->length - midiq->sizeLeft; + } + + /* Notify client that Sysex buffer has been sent */ + emu10k1_midi_callback(msg, card_mpuin->openinfo.refdata, callback_msg); + + return CTSTATUS_SUCCESS; +} + +void emu10k1_mpuin_bh(unsigned long refdata) +{ + u8 data; + unsigned idx; + struct emu10k1_mpuin *card_mpuin = (struct emu10k1_mpuin *) refdata; + unsigned long flags; + + while (card_mpuin->qhead != card_mpuin->qtail) { + spin_lock_irqsave(&card_mpuin->lock, flags); + idx = card_mpuin->qhead; + data = card_mpuin->midiq[idx].data; + card_mpuin->timein = card_mpuin->midiq[idx].timein; + idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE; + card_mpuin->qhead = idx; + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + sblive_miStateEntry(card_mpuin, data); + } + + return; +} + +/* IRQ callback handler routine for the MPU in port */ + +int emu10k1_mpuin_irqhandler(struct emu10k1_card *card) +{ + unsigned idx; + unsigned count; + u8 MPUIvalue; + struct emu10k1_mpuin *card_mpuin = card->mpuin; + + /* IRQ service routine. The data and code touched are: + * 1. card_mpuin + */ + + count = 0; + idx = card_mpuin->qtail; + + while (1) { + if (emu10k1_mpu_read_data(card, &MPUIvalue) == CTSTATUS_SUCCESS) { + ++count; + card_mpuin->midiq[idx].data = MPUIvalue; + card_mpuin->midiq[idx].timein = (jiffies * 1000) / HZ; + idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE; + } else { + break; + } + } + + if (count) { + card_mpuin->qtail = idx; + + tasklet_hi_schedule(&card_mpuin->tasklet); + } + + return CTSTATUS_SUCCESS; +} + +/*****************************************************************************/ + +/* Supporting functions for Midi-In Interpretation State Machine */ + +/*****************************************************************************/ + +/* FIXME: This should be a macro */ +int sblive_miStateInit(struct emu10k1_mpuin *card_mpuin) +{ + card_mpuin->status = 0; /* For MIDI running status */ + card_mpuin->fstatus = 0; /* For 0xFn status only */ + card_mpuin->curstate = STIN_PARSE; + card_mpuin->laststate = STIN_PARSE; + card_mpuin->data = 0; + card_mpuin->timestart = 0; + card_mpuin->timein = 0; + + return CTSTATUS_SUCCESS; +} + +/* FIXME: This should be a macro */ +int sblive_miStateEntry(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data); +} + +int sblive_miStateParse(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + switch (data & 0xf0) { + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + case 0xE0: + card_mpuin->curstate = STIN_3BYTE; + break; + + case 0xC0: + case 0xD0: + card_mpuin->curstate = STIN_2BYTE; + break; + + case 0xF0: + /* System messages do not affect the previous running status! */ + switch (data & 0x0f) { + case 0x0: + card_mpuin->laststate = card_mpuin->curstate; + card_mpuin->curstate = STIN_SYS_EX_NORM; + + if (card_mpuin->firstmidiq) { + struct midi_queue *midiq; + + midiq = card_mpuin->firstmidiq; + *midiq->midibyte = data; + --midiq->sizeLeft; + ++midiq->midibyte; + } + + return CTSTATUS_NEXT_BYTE; + + case 0x7: + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, 0xf7, 0); + return CTSTATUS_ERROR; + + case 0x2: + card_mpuin->laststate = card_mpuin->curstate; + card_mpuin->curstate = STIN_SYS_COMMON_3; + break; + + case 0x1: + case 0x3: + card_mpuin->laststate = card_mpuin->curstate; + card_mpuin->curstate = STIN_SYS_COMMON_2; + break; + + default: + /* includes 0xF4 - 0xF6, 0xF8 - 0xFF */ + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + } + + break; + + default: + DPF(2, "BUG: default case hit\n"); + return CTSTATUS_ERROR; + } + + return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data); +} + +int sblive_miState3Byte(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + u8 temp = data & 0xf0; + + if (temp < 0x80) { + return midistatefn[STIN_3BYTE_KEY].Fn(card_mpuin, data); + } else if (temp <= 0xe0 && temp != 0xc0 && temp != 0xd0) { + card_mpuin->status = data; + card_mpuin->curstate = STIN_3BYTE_KEY; + + return CTSTATUS_NEXT_BYTE; + } + + return midistatefn[STIN_PARSE].Fn(card_mpuin, data); +} + +int sblive_miState3ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 1 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = STIN_PARSE; + tmp = ((unsigned long) data) << 8; + tmp |= (unsigned long) card_mpuin->status; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->data = data; + card_mpuin->curstate = STIN_3BYTE_VEL; + + return CTSTATUS_NEXT_BYTE; +} + +int sblive_miState3ByteVel(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 2 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = STIN_PARSE; + tmp = ((unsigned long) data) << 8; + tmp |= card_mpuin->data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->status; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->curstate = STIN_3BYTE; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->status; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3); + + return CTSTATUS_SUCCESS; +} + +int sblive_miState2Byte(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + u8 temp = data & 0xf0; + + if ((temp == 0xc0) || (temp == 0xd0)) { + card_mpuin->status = data; + card_mpuin->curstate = STIN_2BYTE_KEY; + + return CTSTATUS_NEXT_BYTE; + } + + if (temp < 0x80) + return midistatefn[STIN_2BYTE_KEY].Fn(card_mpuin, data); + + return midistatefn[STIN_PARSE].Fn(card_mpuin, data); +} + +int sblive_miState2ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 1 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = STIN_PARSE; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->status; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->curstate = STIN_2BYTE; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->status; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2); + + return CTSTATUS_SUCCESS; +} + +int sblive_miStateSysCommon2(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + card_mpuin->fstatus = data; + card_mpuin->curstate = STIN_SYS_COMMON_2_KEY; + + return CTSTATUS_NEXT_BYTE; +} + +int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 1 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = card_mpuin->laststate; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->fstatus; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->curstate = card_mpuin->laststate; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->fstatus; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2); + + return CTSTATUS_SUCCESS; +} + +int sblive_miStateSysCommon3(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + card_mpuin->fstatus = data; + card_mpuin->curstate = STIN_SYS_COMMON_3_KEY; + + return CTSTATUS_NEXT_BYTE; +} + +int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 1 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = card_mpuin->laststate; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->fstatus; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->data = data; + card_mpuin->curstate = STIN_SYS_COMMON_3_VEL; + + return CTSTATUS_NEXT_BYTE; +} + +int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *card_mpuin, u8 data) + +/* byte 2 */ +{ + unsigned long tmp; + + if (data > 0x7f) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = card_mpuin->laststate; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->fstatus; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); + + return CTSTATUS_ERROR; + } + + card_mpuin->curstate = card_mpuin->laststate; + tmp = (unsigned long) data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->data; + tmp = tmp << 8; + tmp |= (unsigned long) card_mpuin->fstatus; + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3); + + return CTSTATUS_SUCCESS; +} + +int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + unsigned long flags; + + if ((data > 0x7f) && (data != 0xf7)) { + /* Real-time messages check */ + if (data > 0xf7) + return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data); + + /* Invalid Data! */ + DPF(2, "Invalid data!\n"); + + card_mpuin->curstate = card_mpuin->laststate; + + if (card_mpuin->firstmidiq) { + struct midi_queue *midiq; + + midiq = card_mpuin->firstmidiq; + *midiq->midibyte = data; + --midiq->sizeLeft; + ++midiq->midibyte; + + spin_lock_irqsave(&card_mpuin->lock, flags); + + card_mpuin->firstmidiq = midiq->next; + if (card_mpuin->firstmidiq == NULL) + card_mpuin->lastmidiq = NULL; + + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0); + + kfree(midiq); + } + + return CTSTATUS_ERROR; + } + + if (card_mpuin->firstmidiq) { + struct midi_queue *midiq; + + midiq = card_mpuin->firstmidiq; + *midiq->midibyte = data; + --midiq->sizeLeft; + ++midiq->midibyte; + } + + if (data == 0xf7) { + /* End of Sysex buffer */ + /* Send down the buffer */ + + card_mpuin->curstate = card_mpuin->laststate; + + if (card_mpuin->firstmidiq) { + struct midi_queue *midiq; + + midiq = card_mpuin->firstmidiq; + + spin_lock_irqsave(&card_mpuin->lock, flags); + + card_mpuin->firstmidiq = midiq->next; + if (card_mpuin->firstmidiq == NULL) + card_mpuin->lastmidiq = NULL; + + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0); + + kfree(midiq); + } + + return CTSTATUS_SUCCESS; + } + + if (card_mpuin->firstmidiq) { + struct midi_queue *midiq; + + midiq = card_mpuin->firstmidiq; + + if (midiq->sizeLeft == 0) { + /* Special case */ + + spin_lock_irqsave(&card_mpuin->lock, flags); + + card_mpuin->firstmidiq = midiq->next; + if (card_mpuin->firstmidiq == NULL) + card_mpuin->lastmidiq = NULL; + + spin_unlock_irqrestore(&card_mpuin->lock, flags); + + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0); + + kfree(midiq); + + return CTSTATUS_NEXT_BYTE; + } + } + + return CTSTATUS_NEXT_BYTE; +} + +int sblive_miStateSysReal(struct emu10k1_mpuin *card_mpuin, u8 data) +{ + emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, data, 1); + + return CTSTATUS_NEXT_BYTE; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmi.h linux/drivers/sound/emu10k1/cardmi.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/cardmi.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,113 @@ +/* + ********************************************************************** + * sblive_mi.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _CARDMI_H +#define _CARDMI_H + +#include "icardmid.h" + +typedef enum +{ + STIN_PARSE = 0, + STIN_3BYTE, /* 0x80, 0x90, 0xA0, 0xB0, 0xE0 */ + STIN_3BYTE_KEY, /* Byte 1 */ + STIN_3BYTE_VEL, /* Byte 1 */ + STIN_2BYTE, /* 0xC0, 0xD0 */ + STIN_2BYTE_KEY, /* Byte 1 */ + STIN_SYS_COMMON_2, /* 0xF1, 0xF3 */ + STIN_SYS_COMMON_2_KEY, + STIN_SYS_COMMON_3, /* 0xF2 */ + STIN_SYS_COMMON_3_KEY, + STIN_SYS_COMMON_3_VEL, + STIN_SYS_EX_NORM, /* 0xF0, Normal mode */ + STIN_SYS_REAL +} midi_in_state; + + +/* flags for card MIDI in object */ +#define FLAGS_MIDM_STARTED 0x00001000 // Data has started to come in after Midm Start +#define MIDIIN_MAX_BUFFER_SIZE 200 // Definition for struct emu10k1_mpuin + +struct midi_data +{ + u8 data; + u32 timein; +}; + +struct emu10k1_mpuin +{ + spinlock_t lock; + struct midi_queue *firstmidiq; + struct midi_queue *lastmidiq; + unsigned qhead, qtail; + struct midi_data midiq[MIDIIN_MAX_BUFFER_SIZE]; + struct tasklet_struct tasklet; + struct midi_openinfo openinfo; + + /* For MIDI state machine */ + u8 status; /* For MIDI running status */ + u8 fstatus; /* For 0xFn status only */ + midi_in_state curstate; + midi_in_state laststate; + u32 timestart; + u32 timein; + u8 data; +}; + +int emu10k1_mpuin_open(struct emu10k1_card *, struct midi_openinfo *); +int emu10k1_mpuin_close(struct emu10k1_card *); +int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *, struct midi_hdr *); +int emu10k1_mpuin_start(struct emu10k1_card *); +int emu10k1_mpuin_stop(struct emu10k1_card *); +int emu10k1_mpuin_reset(struct emu10k1_card *); + +int sblive_miStateInit(struct emu10k1_mpuin *); +int sblive_miStateEntry(struct emu10k1_mpuin *, u8); +int sblive_miStateParse(struct emu10k1_mpuin *, u8); +int sblive_miState3Byte(struct emu10k1_mpuin *, u8); +int sblive_miState3ByteKey(struct emu10k1_mpuin *, u8); +int sblive_miState3ByteVel(struct emu10k1_mpuin *, u8); +int sblive_miState2Byte(struct emu10k1_mpuin *, u8); +int sblive_miState2ByteKey(struct emu10k1_mpuin *, u8); +int sblive_miStateSysCommon2(struct emu10k1_mpuin *, u8); +int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *, u8); +int sblive_miStateSysCommon3(struct emu10k1_mpuin *, u8); +int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *, u8); +int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *, u8); +int sblive_miStateSysExNorm(struct emu10k1_mpuin *, u8); +int sblive_miStateSysReal(struct emu10k1_mpuin *, u8); + +int emu10k1_mpuin_irqhandler(struct emu10k1_card *); +void emu10k1_mpuin_bh(unsigned long); +int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid); + +#endif /* _CARDMI_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmo.c linux/drivers/sound/emu10k1/cardmo.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmo.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/cardmo.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,229 @@ + +/* + ********************************************************************** + * cardmo.c - MIDI UART output HAL for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "cardmo.h" + +/* Installs the IRQ handler for the MPU out port * + * and initialize parameters */ + +int emu10k1_mpuout_open(struct emu10k1_card *card, struct midi_openinfo *openinfo) +{ + struct emu10k1_mpuout *card_mpuout = card->mpuout; + + DPF(2, "emu10k1_mpuout_open()\n"); + + if (!(card_mpuout->status & FLAGS_AVAILABLE)) + return CTSTATUS_INUSE; + + /* Copy open info and mark channel as in use */ + card_mpuout->intr = 0; + card_mpuout->openinfo = *openinfo; + card_mpuout->status &= ~FLAGS_AVAILABLE; + card_mpuout->laststatus = 0x80; + card_mpuout->firstmidiq = NULL; + card_mpuout->lastmidiq = NULL; + + emu10k1_mpu_reset(card); + emu10k1_mpu_acquire(card); + + return CTSTATUS_SUCCESS; +} + +int emu10k1_mpuout_close(struct emu10k1_card *card) +{ + struct emu10k1_mpuout *card_mpuout = card->mpuout; + struct midi_queue *midiq; + struct midi_hdr *midihdr; + unsigned long flags; + + DPF(2, "emu10k1_mpuout_close()\n"); + + emu10k1_irq_disable(card, INTE_MIDITXENABLE); + + spin_lock_irqsave(&card_mpuout->lock, flags); + + while (card_mpuout->firstmidiq != NULL) { + midiq = card_mpuout->firstmidiq; + midihdr = (struct midi_hdr *) midiq->refdata; + + card_mpuout->firstmidiq = midiq->next; + + kfree(midihdr->data); + kfree(midihdr); + kfree(midiq); + } + + card_mpuout->lastmidiq = NULL; + + emu10k1_mpu_release(card); + + card_mpuout->status |= FLAGS_AVAILABLE; + + spin_unlock_irqrestore(&card_mpuout->lock, flags); + + return CTSTATUS_SUCCESS; +} + +/* If there isn't enough buffer space, reject Midi Buffer. * +* Otherwise, disable TX, create object to hold Midi * +* uffer, update buffer flags and other parameters * +* before enabling TX again. */ + +int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihdr) +{ + struct emu10k1_mpuout *card_mpuout = card->mpuout; + struct midi_queue *midiq; + unsigned long flags; + + DPF(2, "emu10k1_mpuout_add_buffer()\n"); + + if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND) + return CTSTATUS_SUCCESS; + + midihdr->flags |= MIDIBUF_INQUEUE; + midihdr->flags &= ~MIDIBUF_DONE; + + if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) { + /* Message lost */ + return CTSTATUS_NOMEMORY; + } + + midiq->next = NULL; + midiq->qtype = 1; + midiq->length = midihdr->bufferlength; + midiq->sizeLeft = midihdr->bufferlength; + midiq->midibyte = midihdr->data; + + midiq->refdata = (unsigned long) midihdr; + + spin_lock_irqsave(&card_mpuout->lock, flags); + + if (card_mpuout->firstmidiq == NULL) { + card_mpuout->firstmidiq = midiq; + card_mpuout->lastmidiq = midiq; + } else { + (card_mpuout->lastmidiq)->next = midiq; + card_mpuout->lastmidiq = midiq; + } + + card_mpuout->intr = 0; + + emu10k1_irq_enable(card, INTE_MIDITXENABLE); + + spin_unlock_irqrestore(&card_mpuout->lock, flags); + + return CTSTATUS_SUCCESS; +} + +void emu10k1_mpuout_bh(unsigned long refdata) +{ + struct emu10k1_card *card = (struct emu10k1_card *) refdata; + struct emu10k1_mpuout *card_mpuout = card->mpuout; + int cByteSent = 0; + int status; + struct midi_queue *midiq; + struct midi_queue *doneq = NULL; + unsigned long flags; + + spin_lock_irqsave(&card_mpuout->lock, flags); + + while (card_mpuout->firstmidiq != NULL) { + midiq = card_mpuout->firstmidiq; + + while (cByteSent < 4 && midiq->sizeLeft) { + status = emu10k1_mpu_write_data(card, *midiq->midibyte); + + if (status == CTSTATUS_SUCCESS) { + ++cByteSent; + --midiq->sizeLeft; + ++midiq->midibyte; + } else { + DPF(2, "emu10k1_mpuoutDpcCallback error!!\n"); + } + } + + if (midiq->sizeLeft == 0) { + if (doneq == NULL) + doneq = midiq; + card_mpuout->firstmidiq = midiq->next; + } else + break; + } + + if (card_mpuout->firstmidiq == NULL) + card_mpuout->lastmidiq = NULL; + + if (doneq != NULL) { + while (doneq != card_mpuout->firstmidiq) { + unsigned long callback_msg[3]; + + midiq = doneq; + doneq = midiq->next; + + if (midiq->qtype) { + callback_msg[0] = 0; + callback_msg[1] = midiq->length; + callback_msg[2] = midiq->refdata; + + emu10k1_midi_callback(ICARDMIDI_OUTLONGDATA, card_mpuout->openinfo.refdata, callback_msg); + } else if (((u8) midiq->refdata) < 0xF0 && ((u8) midiq->refdata) > 0x7F) + card_mpuout->laststatus = (u8) midiq->refdata; + + kfree(midiq); + } + } + + if ((card_mpuout->firstmidiq != NULL) || cByteSent) { + card_mpuout->intr = 0; + emu10k1_irq_enable(card, INTE_MIDITXENABLE); + } + + spin_unlock_irqrestore(&card_mpuout->lock, flags); + + return; +} + +int emu10k1_mpuout_irqhandler(struct emu10k1_card *card) +{ + struct emu10k1_mpuout *card_mpuout = card->mpuout; + + DPF(4, "emu10k1_mpuout_irqhandler\n"); + + card_mpuout->intr = 1; + emu10k1_irq_disable(card, INTE_MIDITXENABLE); + + tasklet_hi_schedule(&card_mpuout->tasklet); + + return CTSTATUS_SUCCESS; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmo.h linux/drivers/sound/emu10k1/cardmo.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardmo.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/cardmo.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,61 @@ +/* + ********************************************************************** + * cardmo.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _CARDMO_H +#define _CARDMO_H + +#include "icardmid.h" + +#define CARDMIDIOUT_STATE_DEFAULT 0x00000000 +#define CARDMIDIOUT_STATE_SUSPEND 0x00000001 + +struct emu10k1_mpuout +{ + u32 status; + u32 state; + volatile int intr; + struct midi_queue *firstmidiq; + struct midi_queue *lastmidiq; + u8 laststatus; + struct tasklet_struct tasklet; + spinlock_t lock; + struct midi_openinfo openinfo; +}; + +int emu10k1_mpuout_open(struct emu10k1_card *, struct midi_openinfo *); +int emu10k1_mpuout_close(struct emu10k1_card *); +int emu10k1_mpuout_add_buffer(struct emu10k1_card *, struct midi_hdr *); + +int emu10k1_mpuout_irqhandler(struct emu10k1_card *); +void emu10k1_mpuout_bh(unsigned long); + +#endif /* _CARDMO_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwi.c linux/drivers/sound/emu10k1/cardwi.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/cardwi.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,472 @@ + +/* + ********************************************************************** + * cardwi.c - PCM input HAL for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "recmgr.h" +#include "audio.h" +#include "cardwi.h" + +void query_format(int recsrc, struct wave_format *wave_fmt) +{ + + switch (recsrc) { + case WAVERECORD_AC97: + + if ((wave_fmt->channels != 2) && (wave_fmt->channels != 1)) + wave_fmt->channels = 2; + + if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2) + wave_fmt->samplingrate = 0xBB80; + else if (wave_fmt->samplingrate >= (0xAC44 + 0x7D00) / 2) + wave_fmt->samplingrate = 0xAC44; + else if (wave_fmt->samplingrate >= (0x7D00 + 0x5DC0) / 2) + wave_fmt->samplingrate = 0x7D00; + else if (wave_fmt->samplingrate >= (0x5DC0 + 0x5622) / 2) + wave_fmt->samplingrate = 0x5DC0; + else if (wave_fmt->samplingrate >= (0x5622 + 0x3E80) / 2) + wave_fmt->samplingrate = 0x5622; + else if (wave_fmt->samplingrate >= (0x3E80 + 0x2B11) / 2) + wave_fmt->samplingrate = 0x3E80; + else if (wave_fmt->samplingrate >= (0x2B11 + 0x1F40) / 2) + wave_fmt->samplingrate = 0x2B11; + else + wave_fmt->samplingrate = 0x1F40; + + if ((wave_fmt->bitsperchannel != 16) && (wave_fmt->bitsperchannel != 8)) + wave_fmt->bitsperchannel = 16; + + break; + + case WAVERECORD_MIC: + wave_fmt->channels = 1; + wave_fmt->samplingrate = 0x1F40; + wave_fmt->bitsperchannel = 8; + break; + + case WAVERECORD_FX: + wave_fmt->channels = 2; + wave_fmt->samplingrate = 0xBB80; + wave_fmt->bitsperchannel = 16; + break; + + default: + break; + } + + return; +} + +static int alloc_recbuffer(struct wave_in *wave_in, u32 * bufsize, u8 ** buffer) +{ + u32 reqsize; + int i, j; + u32 size[4]; + + /* NOTE: record buffer size only can be certain sizes. If the requested + * size is not a nice size, use the smaller nearest size. The minimum size is 1k. */ + if (!wave_in->rec_ptr->is_16bit) + *bufsize <<= 1; + + if (*bufsize >= 0x10000) { + *bufsize = reqsize = 0x10000; + wave_in->rec_ptr->bufsize = 31; + } else { + reqsize = 0; + size[0] = 384; + size[1] = 448; + size[2] = 512; + size[3] = 640; + + for (i = 0; i < 8; i++) + for (j = 0; j < 4; j++) + if (*bufsize >= size[j]) { + reqsize = size[j]; + size[j] = size[j] * 2; + wave_in->rec_ptr->bufsize = i * 4 + j + 1; + } else + goto exitloop; + exitloop: + if (reqsize == 0) { + reqsize = 384; + wave_in->rec_ptr->bufsize = 1; + } + + *bufsize = reqsize; + } + + DPD(2, "bufsizereg: %x\n", wave_in->rec_ptr->bufsize); + + /* Recording buffer must be continuous and page-aligned */ + if ((wave_in->memhandle = emu10k1_alloc_memphysical(reqsize)) == NULL) + return CTSTATUS_ERROR; + + DPD(2, "recbufsize: %x\n", *bufsize); + + *buffer = (u8 *) wave_in->memhandle->virtaddx; + + return CTSTATUS_SUCCESS; +} + +static int get_recbuffer(struct emu10k1_card *card, struct wave_in *wave_in, u32 * size) +{ + u8 *buffer; + + wave_in->rec_ptr->card = card; + wave_in->rec_ptr->recpos = 0; + wave_in->rec_ptr->samplingrate = wave_in->wave_fmt.samplingrate; + wave_in->rec_ptr->is_stereo = (wave_in->wave_fmt.channels == 2) ? 1 : 0; + wave_in->rec_ptr->is_16bit = (wave_in->wave_fmt.bitsperchannel == 16) ? 1 : 0; + + /* Allocate buffer here */ + if (alloc_recbuffer(wave_in, size, &buffer) != CTSTATUS_SUCCESS) { + ERROR(); + return CTSTATUS_ERROR; + } + + /* recbufsize contains actual record buffer size */ + /* for 8 bit samples the size is twice the requested */ + /* value since we only make use of one in every two bytes */ + wave_in->rec_ptr->recbufsize = *size; + wave_in->rec_ptr->recbuffer = buffer; + wave_in->rec_ptr->busaddx = wave_in->memhandle->busaddx; + + return CTSTATUS_SUCCESS; +} + +static void dealloc_recbuffer(struct wave_in *wave_in) +{ + emu10k1_free_memphysical(wave_in->memhandle); + return; +} + +int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wiinst *wiinst = wave_dev->wiinst; + struct wave_in *wave_in; + struct wave_in **wave_in_tmp = NULL; + u32 buffsize, bytespersec, delay; + unsigned long flags; + + DPF(2, "emu10k1_wavein_open()\n"); + + if ((wave_in = (struct wave_in *) kmalloc(sizeof(struct wave_in), GFP_KERNEL)) == NULL) { + ERROR(); + return CTSTATUS_ERROR; + } + + wave_in->state = CARDWAVE_STATE_STOPPED; + wave_in->wave_fmt = wiinst->wave_fmt; + wave_in->memhandle = NULL; + wave_in->timer = NULL; + + switch (wiinst->recsrc) { + case WAVERECORD_AC97: + wave_in_tmp = &card->wavein->ac97; + break; + case WAVERECORD_MIC: + wave_in_tmp = &card->wavein->mic; + break; + case WAVERECORD_FX: + wave_in_tmp = &card->wavein->fx; + break; + default: + break; + } + + spin_lock_irqsave(&card->lock, flags); + if (*wave_in_tmp != NULL) { + spin_unlock_irqrestore(&card->lock, flags); + kfree(wave_in); + return CTSTATUS_ERROR; + } + + *wave_in_tmp = wave_in; + spin_unlock_irqrestore(&card->lock, flags); + + wiinst->wave_in = wave_in; + + if ((wave_in->rec_ptr = (struct record *) kmalloc(sizeof(struct record), GFP_KERNEL)) == NULL) { + ERROR(); + emu10k1_wavein_close(wave_dev); + return CTSTATUS_ERROR; + } + + buffsize = wiinst->fragment_size * wiinst->numfrags; + + if (get_recbuffer(card, wave_in, &buffsize) != CTSTATUS_SUCCESS) { + ERROR(); + emu10k1_wavein_close(wave_dev); + return CTSTATUS_ERROR; + } + + wiinst->fragment_size = buffsize / wiinst->numfrags; + + /* This callback size returned is the size in the play buffer. + * For 8-bit samples, callbacksize of user buffer should be + * half of the callbacksize in play buffer. */ + if (wave_in->wave_fmt.bitsperchannel == 8) + wiinst->fragment_size >>= 1; + + wave_in->callbacksize = wiinst->fragment_size; + + emu10k1_set_record_src(wave_in->rec_ptr, wiinst->recsrc); + + bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate); + delay = (48000 * wave_in->callbacksize) / bytespersec; + + if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { + ERROR(); + emu10k1_wavein_close(wave_dev); + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} + +void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wave_in *wave_in = wave_dev->wiinst->wave_in; + unsigned long flags; + + if (wave_in->state != CARDWAVE_STATE_STOPPED) + emu10k1_wavein_stop(wave_dev); + + if (wave_in->timer != NULL) + emu10k1_timer_uninstall(card, wave_in->timer); + + if (wave_in->memhandle != NULL) + dealloc_recbuffer(wave_in); + + if (wave_in->rec_ptr != NULL) + kfree(wave_in->rec_ptr); + + spin_lock_irqsave(&card->lock, flags); + switch (wave_dev->wiinst->recsrc) { + case WAVERECORD_AC97: + card->wavein->ac97 = NULL; + break; + case WAVERECORD_MIC: + card->wavein->mic = NULL; + break; + case WAVERECORD_FX: + card->wavein->fx = NULL; + break; + default: + break; + } + spin_unlock_irqrestore(&card->lock, flags); + + kfree(wave_in); + wave_dev->wiinst->wave_in = NULL; + + return; +} + +void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev) +{ + struct wave_in *wave_in = wave_dev->wiinst->wave_in; + + DPF(2, "emu10k1_wavein_start()\n"); + + if (wave_in->state == CARDWAVE_STATE_STARTED) + return; + + emu10k1_start_record(wave_in->rec_ptr); + wave_in->state = CARDWAVE_STATE_STARTED; + + emu10k1_timer_enable(wave_dev->card, wave_in->timer); + + return; +} + +void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev) +{ + struct wave_in *wave_in = wave_dev->wiinst->wave_in; + + DPF(2, "emu10k1_wavein_stop()\n"); + + emu10k1_stop_record(wave_in->rec_ptr); + emu10k1_timer_disable(wave_dev->card, wave_in->timer); + + wave_in->rec_ptr->recpos = 0; + wave_in->state = CARDWAVE_STATE_STOPPED; + + return; +} + +int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wiinst *wiinst = wave_dev->wiinst; + struct wave_in *wave_in = wiinst->wave_in; + u32 bytespersec, delay; + + DPF(2, "emu10k1_wavein_setformat()\n"); + + query_format(wiinst->recsrc, &wiinst->wave_fmt); + + if (!wave_in) + return CTSTATUS_SUCCESS; + + if (wave_in->state == CARDWAVE_STATE_STARTED) { + wiinst->wave_fmt = wave_in->wave_fmt; + return CTSTATUS_SUCCESS; + } + + if ((wave_in->wave_fmt.samplingrate != wiinst->wave_fmt.samplingrate) + || (wave_in->wave_fmt.bitsperchannel != wiinst->wave_fmt.bitsperchannel) + || (wave_in->wave_fmt.channels != wiinst->wave_fmt.channels)) { + + emu10k1_timer_uninstall(card, wave_in->timer); + + wave_in->wave_fmt = wiinst->wave_fmt; + + bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate); + delay = (48000 * wave_in->callbacksize) / bytespersec; + + if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { + ERROR(); + emu10k1_wavein_close(wave_dev); + return CTSTATUS_ERROR; + } + } + + return CTSTATUS_SUCCESS; +} + +void emu10k1_wavein_getxfersize(struct wave_in *wave_in, u32 * size, u32 * curpos) +{ + struct record *rec_ptr = wave_in->rec_ptr; + + /* Get position of current address, this is in no. of bytes in play buffer */ + emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, curpos); + + *size = *curpos - rec_ptr->recpos; + + /* Recpos is the actual position in user buffer and play buffer */ + if (*curpos < rec_ptr->recpos) + *size += rec_ptr->recbufsize; + + if (!rec_ptr->is_16bit) + *size >>= 1; + + return; +} + +static void copy_s16_to_u8(u8 * dstbuf, s16 * srcbuf, u32 size) +{ + u16 sample; + u8 byte; + + while (size--) { + sample = (*srcbuf) + 32767; + byte = (u8) (sample >> 8); + copy_to_user(dstbuf, &byte, 1); + dstbuf++; + srcbuf++; + } +} + +/* transfer the data from the wave device. */ +void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 * data, u32 * size) +{ + struct wave_in *wave_in = wiinst->wave_in; + struct record *rec_ptr = wave_in->rec_ptr; + u32 sizetocopy, sizetocopy_now, start; + unsigned long flags; + + sizetocopy = min(rec_ptr->recbufsize * (rec_ptr->is_16bit + 1) / 2, *size); + *size = sizetocopy; + + if (!sizetocopy) + return; + + spin_lock_irqsave(&wiinst->lock, flags); + + sizetocopy_now = (rec_ptr->recbufsize - rec_ptr->recpos) * (rec_ptr->is_16bit + 1) / 2; + + start = rec_ptr->recpos; + + if (sizetocopy > sizetocopy_now) { + sizetocopy -= sizetocopy_now; + rec_ptr->recpos = sizetocopy * 2 / (rec_ptr->is_16bit + 1); + + spin_unlock_irqrestore(&wiinst->lock, flags); + + if (rec_ptr->is_16bit) { + copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy_now); + copy_to_user(data + sizetocopy_now, rec_ptr->recbuffer, sizetocopy); + } else { + copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy_now); + copy_s16_to_u8(data + sizetocopy_now, (s16 *) rec_ptr->recbuffer, sizetocopy); + } + } else { + if (sizetocopy == sizetocopy_now) + rec_ptr->recpos = 0; + else + rec_ptr->recpos += sizetocopy * 2 / (rec_ptr->is_16bit + 1); + + spin_unlock_irqrestore(&wiinst->lock, flags); + + if (rec_ptr->is_16bit) + copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy); + else + copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy); + } + + return; +} + +/* get the specified control value of the wave device. */ + +int emu10k1_wavein_getcontrol(struct wave_in *wave_in, u32 ctrlid, u32 * value) +{ + switch (ctrlid) { + case WAVECURPOS: + /* There is no actual start yet */ + if (wave_in->state == CARDWAVE_STATE_STOPPED) { + *value = 0; + } else { + /* value is in byte units */ + *value = sblive_readptr(wave_in->rec_ptr->card, wave_in->rec_ptr->bufidxreg, 0); + } + + break; + + default: + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwi.h linux/drivers/sound/emu10k1/cardwi.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/cardwi.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,92 @@ +/* + ********************************************************************** + * cardwi.h -- header file for card wave input functions + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ +#ifndef _CARDWI_H +#define _CARDWI_H + +#include "icardwav.h" + +struct wave_in +{ + struct list_head list; + + u32 state; + struct record *rec_ptr; + struct memhandle *memhandle; + struct emu_timer *timer; + u32 callbacksize; + struct wave_format wave_fmt; +}; + +struct wiinst +{ + struct wave_in *wave_in; + struct wave_format wave_fmt; + u16 ossfragshift; + u32 fragment_size; + u32 numfrags; + wait_queue_head_t wait_queue; + int mapped; + u32 total_recorded; + u32 blocks; + u32 curpos; + spinlock_t lock; + u8 recsrc; +}; + +struct emu10k1_wavein +{ + struct wave_in *ac97; + struct wave_in *mic; + struct wave_in *fx; + + u8 recsrc; +}; + + +#define WAVEIN_MAXBUFSIZE 65536 +#define WAVEIN_MINBUFSIZE 368 + +#define WAVEIN_DEFAULTFRAGLEN 100 +#define WAVEIN_DEFAULTBUFLEN 1000 + +#define WAVEIN_MINFRAGSHIFT 8 + +int emu10k1_wavein_open(struct emu10k1_wavedevice *); +void emu10k1_wavein_close(struct emu10k1_wavedevice *); +void emu10k1_wavein_start(struct emu10k1_wavedevice *); +void emu10k1_wavein_stop(struct emu10k1_wavedevice *); +void emu10k1_wavein_getxfersize(struct wave_in *, u32 *, u32 *); +void emu10k1_wavein_xferdata(struct wiinst *, u8 *, u32 *); +int emu10k1_wavein_setformat(struct emu10k1_wavedevice *); +int emu10k1_wavein_getcontrol(struct wave_in *, u32, u32 *); + + +#endif /* _CARDWI_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwo.c linux/drivers/sound/emu10k1/cardwo.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwo.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/cardwo.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,755 @@ + +/* + ********************************************************************** + * cardwo.c - PCM output HAL for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "cardwo.h" +#include "audio.h" + +/* Volume calcs */ + +static int set_volume_instance(struct emu10k1_waveout *card_waveout, struct wave_out *wave_out, struct voice_param *left) +{ + /* only applicable for playback */ + u32 volL, volR, vol = 0; + + volL = (wave_out->localvol & 0xffff); + volR = ((wave_out->localvol >> 16) & 0xffff); + + if (wave_out->globalvolFactor) { + volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * (u16) volL)) / 0xffff; + volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) volR))) / 0xffff; + } + + /* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */ + /* New volume and pan */ + + if (volL == volR) { + vol = volL; + left->send_c = 0xff; + left->send_b = 0xff; + } else { + if (volL > volR) { + vol = volL; + left->send_c = 0xff; + left->send_b = (char) ((volR * 255) / vol); + } else { + vol = volR; + left->send_b = 0xff; + left->send_c = (char) ((volL * 255) / vol); + } + } + + left->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2); + + return vol; +} + +static void query_format(struct wave_format *wave_fmt) +{ + if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2)) + wave_fmt->channels = 2; + + if (wave_fmt->samplingrate >= 0x2EE00) + wave_fmt->samplingrate = 0x2EE00; + + if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16)) + wave_fmt->bitsperchannel = 16; + + return; +} + +static int alloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size, void ***buffer) +{ + u32 numpages, reqsize, pageindex, pagecount; + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + unsigned long busaddx; + int i; + + reqsize = *size; + numpages = reqsize / PAGE_SIZE; + + /* If size is not a multiple of PAGE_SIZE then we need to round up */ + if (reqsize % PAGE_SIZE) + numpages += 1; + + DPD(2, "requested pages is: %d\n", numpages); + + wavexferbuf->numpages = numpages; + + /* Only for playback, request for emu address space */ + /* Support non page-aligned buffer, don't need interpolation page */ + + if ((wave_out->emupageindex = emu10k1_addxmgr_alloc(numpages * PAGE_SIZE, card)) < 0) + return CTSTATUS_ERROR; + + if ((wave_out->pagetable = (void **) kmalloc(sizeof(void *) * numpages, GFP_KERNEL)) == NULL) + return CTSTATUS_ERROR; + + /* Fill in virtual memory table */ + for (pagecount = 0; pagecount < numpages; pagecount++) { + if ((wave_out->pagetable[pagecount] = (void *) __get_free_page(GFP_KERNEL)) == NULL) { + wavexferbuf->numpages = pagecount; + return CTSTATUS_ERROR; + } + + DPD(2, "Virtual Addx: %p\n", wave_out->pagetable[pagecount]); + + for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) { + busaddx = virt_to_bus((u8 *) wave_out->pagetable[pagecount] + i * EMUPAGESIZE); + + DPD(3, "Bus Addx: %lx\n", busaddx); + + pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; + + ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = ((u32) busaddx * 2) | pageindex; + } + } + + *buffer = wave_out->pagetable; + + return CTSTATUS_SUCCESS; +} + +static int get_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size) +{ + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + void **buffer; + + wavexferbuf->xferpos = 0; + wavexferbuf->silence_xferpos = 0; + wavexferbuf->stopposition = 0; + wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0; + wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0; + wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1); + + if (alloc_xferbuffer(card, wave_out, size, &buffer) != CTSTATUS_SUCCESS) + return CTSTATUS_ERROR; + + /* xferbufsize contains actual transfer buffer size */ + wavexferbuf->xferbufsize = *size; + wavexferbuf->xferbuffer = buffer; + + return CTSTATUS_SUCCESS; +} + +static void dealloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out) +{ + u32 pagecount, pageindex; + int i; + + if (wave_out->pagetable != NULL) { + for (pagecount = 0; pagecount < wave_out->wavexferbuf->numpages; pagecount++) { + free_page((unsigned long) wave_out->pagetable[pagecount]); + + for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) { + pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; + ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = (card->silentpage->busaddx * 2) | pageindex; + } + } + kfree(wave_out->pagetable); + } + + emu10k1_addxmgr_free(card, wave_out->emupageindex); + + return; +} + +static int get_voice(struct emu10k1_card *card, struct wave_out *wave_out, int device) +{ + struct emu10k1_waveout *card_waveout = card->waveout; + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + struct voice_allocdesc voice_allocdesc; + struct voice_param *left, *right; + u32 size; + + /* Allocate voices here, if no voices available, return error. + * Init voice_allocdesc first.*/ + + voice_allocdesc.usage = VOICEMGR_USAGE_PLAYBACK; + + voice_allocdesc.flags = 0; + + if (device == 1) + voice_allocdesc.flags |= VOICEMGR_FLAGS_FXRT2; + + if (wave_out->wave_fmt.channels == 1) + voice_allocdesc.flags |= VOICEMGR_FLAGS_MONO; + + if (wave_out->wave_fmt.bitsperchannel == 16) + voice_allocdesc.flags |= VOICEMGR_FLAGS_16BIT; + + if ((wave_out->voice = emu10k1_voice_alloc(&card->voicemgr, &voice_allocdesc)) == NULL) + return CTSTATUS_ERROR; + + /* voice initialization */ + + left = &wave_out->voice->params; + + /* Calculate pitch */ + left->initial_pitch = (u16) (srToPitch(wave_out->wave_fmt.samplingrate) >> 8); + + DPD(2, "Initial pitch --> %x\n", left->initial_pitch); + + /* Easy way out.. gotta calculate value */ + left->pitch_target = 0; + left->volume_target = 0; + left->FC_target = 0; + + left->byampl_env_sustain = 0x7f; + left->byampl_env_decay = 0x7f; + + if (wave_out->globalreverbFactor) { + u8 t = (card_waveout->globalreverb & 0xff) + (wave_out->localreverb & 0xff); + + left->send_a = (t > 255) ? 255 : t; + } else { + left->send_a = 0; + } + + if (wave_out->globalchorusFactor) { + u8 t = (card_waveout->globalchorus & 0xff) + (wave_out->localchorus & 0xff); + + left->send_d = (t > 255) ? 255 : t; + } else { + left->send_d = 0; + } + + set_volume_instance(card_waveout, wave_out, left); + + left->pan_target = left->send_c; + left->aux_target = left->send_b; + + size = wavexferbuf->xferbufsize / wavexferbuf->bytespersample; + left->start = 2 * (wave_out->emupageindex << 11) / wavexferbuf->bytespersample; + left->end = left->start + size; + left->startloop = left->start; + left->endloop = left->end; + + if (wave_out->voice->linked_voice) { + DPF(2, "is stereo\n"); + right = &wave_out->voice->linked_voice->params; + + right->initial_pitch = left->initial_pitch; + + /* Easy way out.. gotta calculate value */ + right->pitch_target = 0; + right->volume_target = 0; + right->FC_target = 0; + + right->byampl_env_sustain = 0x7f; + right->byampl_env_decay = 0x7f; + + right->send_d = left->send_d; + right->send_a = left->send_a; + + /* Left output of right channel is always zero */ + right->send_c = 0; + + /* Update right channel aux */ + right->pan_target = 0; + right->send_b = left->send_b; + right->aux_target = right->send_b; + + /* Zero out right output of left channel */ + left->send_b = 0; + left->aux_target = 0; + + /* Update right channel attenuation */ + right->initial_attn = left->initial_attn; + + right->start = left->start; + right->end = left->end; + right->startloop = left->startloop; + right->endloop = left->endloop; + + } + + DPD(2, "voice: start=%x, end=%x, startloop=%x, endloop=%x\n", left->start, left->end, left->startloop, left->endloop); + + return CTSTATUS_SUCCESS; +} + +int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out; + u32 bytespersec, delay; + u32 buffsize; + + DPF(2, "emu10k1_waveout_open()\n"); + + if ((wave_out = (struct wave_out *) kmalloc(sizeof(struct wave_out), GFP_KERNEL)) == NULL) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + woinst->wave_out = wave_out; + + /* Init channel object */ + wave_out->state = CARDWAVE_STATE_STOPPED; + wave_out->wave_fmt = woinst->wave_fmt; + wave_out->voice = NULL; + wave_out->emupageindex = -1; + wave_out->wavexferbuf = NULL; + wave_out->pagetable = NULL; + wave_out->timer = NULL; + + /* Assign default local volume */ + /* FIXME: Should we be maxing the initial values like this? */ + wave_out->localvol = 0xffffffff; + wave_out->localreverb = 0xffffffff; + wave_out->localchorus = 0xffffffff; + wave_out->globalvolFactor = 0xffff; + wave_out->globalreverbFactor = 0xffff; + wave_out->globalchorusFactor = 0xffff; + + wave_out->setpos = 0; + wave_out->position = 0; + + wave_out->fill_silence = 0; + + if ((wave_out->wavexferbuf = (struct wave_xferbuf *) kmalloc(sizeof(struct wave_xferbuf), GFP_KERNEL)) == NULL) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + buffsize = woinst->fragment_size * woinst->numfrags; + + if (get_xferbuffer(card, wave_out, &buffsize) != CTSTATUS_SUCCESS) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + woinst->fragment_size = buffsize / woinst->numfrags; + wave_out->callbacksize = woinst->fragment_size; + + if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate); + delay = (48000 * wave_out->callbacksize) / bytespersec; + + if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} + +void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wave_out *wave_out = wave_dev->woinst->wave_out; + + DPF(2, "emu10k1_waveout_close()\n"); + + if (wave_out->state != CARDWAVE_STATE_STOPPED) + emu10k1_waveout_stop(wave_dev); + + if (wave_out->timer != NULL) + emu10k1_timer_uninstall(card, wave_out->timer); + + if (wave_out->voice != NULL) + emu10k1_voice_free(&card->voicemgr, wave_out->voice); + + if (wave_out->emupageindex >= 0) + dealloc_xferbuffer(card, wave_out); + + if (wave_out->wavexferbuf != NULL) + kfree(wave_out->wavexferbuf); + + kfree(wave_out); + wave_dev->woinst->wave_out = NULL; + + return; +} + +int emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wave_out *wave_out = wave_dev->woinst->wave_out; + u32 start, startPosition; + + DPF(2, "emu10k1_waveout_start()\n"); + + /* If already started, return success */ + if (wave_out->state == CARDWAVE_STATE_STARTED) + return CTSTATUS_SUCCESS; + + if (wave_out->state == CARDWAVE_STATE_STOPPED && wave_out->setpos) + startPosition = wave_out->position / (wave_out->wavexferbuf->bytespersample); + else + startPosition = wave_out->wavexferbuf->stopposition; + + start = wave_out->voice->params.start; + wave_out->voice->params.start += startPosition; + + DPD(2, "CA is %x\n", wave_out->voice->params.start); + + emu10k1_voice_playback_setup(wave_out->voice); + + wave_out->voice->params.start = start; + + /* Actual start */ + emu10k1_voice_start(wave_out->voice); + + wave_out->state = CARDWAVE_STATE_STARTED; + wave_out->setpos = 0; + + emu10k1_timer_enable(card, wave_out->timer); + + return CTSTATUS_SUCCESS; +} + +int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct woinst *woinst = wave_dev->woinst; + struct wave_out *wave_out = woinst->wave_out; + u32 bytespersec, delay; + + DPF(2, "emu10k1_waveout_setformat()\n"); + + query_format(&woinst->wave_fmt); + + if (wave_out == NULL) + return CTSTATUS_SUCCESS; + + if (wave_out->state == CARDWAVE_STATE_STARTED) { + woinst->wave_fmt = wave_out->wave_fmt; + return CTSTATUS_SUCCESS; + } + + if ((wave_out->wave_fmt.samplingrate != woinst->wave_fmt.samplingrate) + || (wave_out->wave_fmt.bitsperchannel != woinst->wave_fmt.bitsperchannel) + || (wave_out->wave_fmt.channels != woinst->wave_fmt.channels)) { + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + + emu10k1_timer_uninstall(card, wave_out->timer); + + emu10k1_voice_free(&card->voicemgr, wave_out->voice); + + wave_out->wave_fmt = woinst->wave_fmt; + wave_out->timer = NULL; + + wavexferbuf->xferpos = 0; + wavexferbuf->silence_xferpos = 0; + wavexferbuf->stopposition = 0; + wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0; + wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0; + wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1); + + if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + + bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate); + delay = (48000 * wave_out->callbacksize) / bytespersec; + + if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { + ERROR(); + emu10k1_waveout_close(wave_dev); + return CTSTATUS_ERROR; + } + } + + return CTSTATUS_SUCCESS; +} + +void emu10k1_waveout_stop(struct emu10k1_wavedevice *wave_dev) +{ + struct emu10k1_card *card = wave_dev->card; + struct wave_out *wave_out = wave_dev->woinst->wave_out; + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + u32 samples = 32; + u32 position; + + DPF(2, "emu10k1_waveout_stop()\n"); + + if (wave_out->state == CARDWAVE_STATE_STOPPED) + return; + + emu10k1_timer_disable(card, wave_out->timer); + + /* Stop actual voice */ + emu10k1_voice_stop(wave_out->voice); + + /* Save the stop position */ + emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, &wavexferbuf->stopposition); + + wavexferbuf->stopposition -= wave_out->voice->params.start; + + /* Refer to voicemgr.c, CA is not started at zero. We need to take this into account. */ + position = wavexferbuf->stopposition * wavexferbuf->bytespersample; + + if (!wavexferbuf->is_16bit) + samples <<= 1; + + if (wavexferbuf->is_stereo) + samples <<= 1; + + samples -= 4; + + if (position >= samples * (wavexferbuf->is_16bit + 1)) + position -= samples * (wavexferbuf->is_16bit + 1); + else + position += wavexferbuf->xferbufsize - samples * (wavexferbuf->is_16bit + 1); + + wavexferbuf->stopposition = position / wavexferbuf->bytespersample; + + DPD(2, "position is %x\n", wavexferbuf->stopposition); + + wave_out->state = CARDWAVE_STATE_STOPPED; + wave_out->setpos = 0; + wave_out->position = 0; + + return; +} + +void emu10k1_waveout_getxfersize(struct wave_out *wave_out, u32 * size, u32 * pending, u32 * curpos) +{ + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + + /* Get position of current address, this is in no. of bytes in play buffer */ + emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, curpos); + + if ((*curpos > wavexferbuf->silence_xferpos) + || ((*curpos == wavexferbuf->silence_xferpos) + && (wave_out->state == CARDWAVE_STATE_STARTED)) + || ((*curpos == wavexferbuf->silence_xferpos) && (wavexferbuf->silence_xferpos != 0) + && (wave_out->state == CARDWAVE_STATE_STOPPED))) { + *size = *curpos - wavexferbuf->silence_xferpos; + *pending = wavexferbuf->xferbufsize - *size; + } else { + *pending = wavexferbuf->silence_xferpos - *curpos; + *size = wavexferbuf->xferbufsize - *pending; + } + + if (wavexferbuf->silence_xferpos != wavexferbuf->xferpos) { + if (*pending < wave_out->callbacksize) { + wave_out->fill_silence = 2; + *pending = 0; + *size = wavexferbuf->xferbufsize; + wavexferbuf->xferpos = *curpos; + } else { + if (wave_out->fill_silence == 2) { + *pending = 0; + *size = wavexferbuf->xferbufsize; + wavexferbuf->xferpos = *curpos; + } else { + *pending -= wave_out->callbacksize; + *size += wave_out->callbacksize; + } + } + } else { + if (*pending < wave_out->callbacksize) + wave_out->fill_silence = 1; + else + wave_out->fill_silence = 0; + } + + return; +} + +static void copy_block(u32 dst, u8 * src, u32 len, void **pt) +{ + int i, j, k; + + i = dst / PAGE_SIZE; + j = dst % PAGE_SIZE; + k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len; + copy_from_user(pt[i] + j, src, k); + len -= k; + while (len >= PAGE_SIZE) { + copy_from_user(pt[++i], src + k, PAGE_SIZE); + k += PAGE_SIZE; + len -= PAGE_SIZE; + } + copy_from_user(pt[++i], src + k, len); + + return; +} + +static void fill_block(u32 dst, u8 val, u32 len, void **pt) +{ + int i, j, k; + + i = dst / PAGE_SIZE; + j = dst % PAGE_SIZE; + k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len; + memset(pt[i] + j, val, k); + len -= k; + while (len >= PAGE_SIZE) { + memset(pt[++i], val, PAGE_SIZE); + len -= PAGE_SIZE; + } + memset(pt[++i], val, len); + + return; +} + +void emu10k1_waveout_xferdata(struct woinst *woinst, u8 * data, u32 * size) +{ + struct wave_out *wave_out = woinst->wave_out; + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + u32 sizetocopy, sizetocopy_now, start; + unsigned long flags; + + sizetocopy = min(wavexferbuf->xferbufsize, *size); + *size = sizetocopy; + + if (!sizetocopy) + return; + + spin_lock_irqsave(&woinst->lock, flags); + + sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->xferpos; + + start = wavexferbuf->xferpos; + + if (sizetocopy > sizetocopy_now) { + sizetocopy -= sizetocopy_now; + wavexferbuf->xferpos = sizetocopy; + wavexferbuf->silence_xferpos = wavexferbuf->xferpos; + spin_unlock_irqrestore(&woinst->lock, flags); + + copy_block(start, data, sizetocopy_now, wavexferbuf->xferbuffer); + copy_block(0, data + sizetocopy_now, sizetocopy, wavexferbuf->xferbuffer); + } else { + if (sizetocopy == sizetocopy_now) + wavexferbuf->xferpos = 0; + else + wavexferbuf->xferpos += sizetocopy; + + wavexferbuf->silence_xferpos = wavexferbuf->xferpos; + spin_unlock_irqrestore(&woinst->lock, flags); + + copy_block(start, data, sizetocopy, wavexferbuf->xferbuffer); + } + + return; +} + +void emu10k1_waveout_fillsilence(struct woinst *woinst) +{ + struct wave_out *wave_out = woinst->wave_out; + struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + u16 filldata; + u32 sizetocopy, sizetocopy_now, start; + unsigned long flags; + + sizetocopy = wave_out->callbacksize; + + if (wave_out->wave_fmt.bitsperchannel == 8) + filldata = 0x8080; + else + filldata = 0x0000; + + spin_lock_irqsave(&woinst->lock, flags); + + sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->silence_xferpos; + start = wavexferbuf->silence_xferpos; + + if (sizetocopy > sizetocopy_now) { + sizetocopy -= sizetocopy_now; + wavexferbuf->silence_xferpos = sizetocopy; + spin_unlock_irqrestore(&woinst->lock, flags); + fill_block(start, filldata, sizetocopy_now, wavexferbuf->xferbuffer); + fill_block(0, filldata, sizetocopy, wavexferbuf->xferbuffer); + } else { + if (sizetocopy == sizetocopy_now) + wavexferbuf->silence_xferpos = 0; + else + wavexferbuf->silence_xferpos += sizetocopy; + + spin_unlock_irqrestore(&woinst->lock, flags); + + fill_block(start, filldata, sizetocopy, wavexferbuf->xferbuffer); + } + + return; +} + +/* get the specified control value of the wave device. */ + +int emu10k1_waveout_getcontrol(struct wave_out *wave_out, u32 ctrl_id, u32 * value) +{ + switch (ctrl_id) { + case WAVECURPOS: + /* There is no actual start yet */ + if (wave_out->state == CARDWAVE_STATE_STOPPED) { + if (wave_out->setpos) + *value = wave_out->position; + else + *value = wave_out->wavexferbuf->stopposition * wave_out->wavexferbuf->bytespersample; + } else { + emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, value); + + *value -= wave_out->voice->params.start; + + /* Get number of bytes in play buffer per channel. + * If 8 bit mode is enabled, this needs to be changed. */ + { + u32 samples = 64 * (wave_out->wavexferbuf->is_stereo + 1); + + *value *= wave_out->wavexferbuf->bytespersample; + + /* Refer to voicemgr.c, CA is not started at zero. + * We need to take this into account. */ + + samples -= 4 * (wave_out->wavexferbuf->is_16bit + 1); + + if (*value >= samples) + *value -= samples; + else + *value += wave_out->wavexferbuf->xferbufsize - samples; + } + } + + break; + default: + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwo.h linux/drivers/sound/emu10k1/cardwo.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/cardwo.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/cardwo.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,118 @@ +/* + ********************************************************************** + * cardwo.h -- header file for card wave out functions + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _CARDWO_H +#define _CARDWO_H + +#include "icardwav.h" + +struct wave_xferbuf +{ + u32 xferpos; + u32 silence_xferpos; + u32 xferbufsize; /* transfer buffer size */ + u32 numpages; /* number of pages in transfer buffer */ + void **xferbuffer; /* pointer to the transfer buffer */ + int is_stereo; + int is_16bit; + int bytespersample; + u32 stopposition; +}; + +struct wave_out +{ + u32 state; + struct emu_voice *voice; + int emupageindex; + struct emu_timer *timer; + struct wave_xferbuf *wavexferbuf; + void **pagetable; + u32 callbacksize; + u32 localvol; + u32 localreverb; + u32 localchorus; + u32 globalvolFactor; + u32 globalreverbFactor; + u32 globalchorusFactor; + int setpos; + u32 position; + struct wave_format wave_fmt; + int fill_silence; +}; + +/* setting this to other than a power of two + may break some applications */ +#define WAVEOUT_MAXBUFSIZE 32768 +#define WAVEOUT_MINBUFSIZE 64 + +#define WAVEOUT_DEFAULTFRAGLEN 100 /* Time to play a fragment in ms (latency) */ +#define WAVEOUT_DEFAULTBUFLEN 1000 /* Time to play the entire buffer in ms */ + +#define WAVEOUT_MINFRAGSHIFT 4 + +struct woinst +{ + struct wave_out *wave_out; + struct wave_format wave_fmt; + u16 ossfragshift; + u32 fragment_size; + u32 numfrags; + wait_queue_head_t wait_queue; + int mapped; + u32 total_copied; + u32 total_played; + u32 blocks; + u32 curpos; + u32 device; + spinlock_t lock; +}; + +struct emu10k1_waveout +{ + u32 globalvol; + u32 mute; + u32 left; + u32 right; + u32 globalreverb; + u32 globalchorus; +}; + +int emu10k1_waveout_open(struct emu10k1_wavedevice *); +void emu10k1_waveout_close(struct emu10k1_wavedevice *); +int emu10k1_waveout_start(struct emu10k1_wavedevice *); +void emu10k1_waveout_stop(struct emu10k1_wavedevice *); +void emu10k1_waveout_getxfersize(struct wave_out *, u32 *, u32 *, u32 *); +void emu10k1_waveout_xferdata(struct woinst*, u8*, u32 *); +void emu10k1_waveout_fillsilence(struct woinst*); +int emu10k1_waveout_setformat(struct emu10k1_wavedevice*); +int emu10k1_waveout_getcontrol(struct wave_out*, u32, u32 *); + +#endif /* _CARDWO_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/efxmgr.c linux/drivers/sound/emu10k1/efxmgr.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/efxmgr.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/efxmgr.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,34 @@ + +/* + ********************************************************************** + * sblive_fx.c + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "efxmgr.h" diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/efxmgr.h linux/drivers/sound/emu10k1/efxmgr.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/efxmgr.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/efxmgr.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,43 @@ +/* + ********************************************************************** + * sblive_fx.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _EFXMGR_H +#define _EFXMGR_H + +#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c)) + +#define OP(op, z, w, x, y) \ + do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \ + WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \ + ++pc; } while (0) + + +#endif /* _EFXMGR_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/emu_wrapper.h linux/drivers/sound/emu10k1/emu_wrapper.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/emu_wrapper.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/emu_wrapper.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,11 @@ +#ifndef __EMU_WRAPPER_H +#define __EMU_WRAPPER_H + +#include + +#define UP_INODE_SEM(a) +#define DOWN_INODE_SEM(a) + +#define GET_INODE_STRUCT() + +#endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/emuadxmg.c linux/drivers/sound/emu10k1/emuadxmg.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/emuadxmg.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/emuadxmg.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,101 @@ + +/* + ********************************************************************** + * emuadxmg.c - Address space manager for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" + +/* Allocates emu address space */ + +int emu10k1_addxmgr_alloc(u32 size, struct emu10k1_card *card) +{ + u16 *pagetable = card->emupagetable; + u16 index = 0; + u16 numpages; + unsigned long flags; + + /* Convert bytes to pages */ + numpages = (size / EMUPAGESIZE) + ((size % EMUPAGESIZE) ? 1 : 0); + + while (index < (MAXPAGES - RESERVED - 1)) { + if (pagetable[index] & 0x8000) { + /* This block of pages is in use, jump to the start of the next block. */ + index += (pagetable[index] & 0x7fff); + } else { + /* Found free block */ + if (pagetable[index] >= numpages) { + spin_lock_irqsave(&card->lock, flags); + + /* Block is large enough */ + + /* If free block is larger than the block requested + * then adjust the size of the block remaining */ + if (pagetable[index] > numpages) + pagetable[index + numpages] = pagetable[index] - numpages; + + pagetable[index] = (numpages | 0x8000); /* Mark block as used */ + + spin_unlock_irqrestore(&card->lock, flags); + + return index; + } else { + /* Block too small, jump to the start of the next block */ + index += pagetable[index]; + } + } + } + + return -1; +} + +/* Frees a previously allocated emu address space. */ + +void emu10k1_addxmgr_free(struct emu10k1_card *card, int index) +{ + u16 *pagetable = card->emupagetable; + u16 origsize = 0; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + if (pagetable[index] & 0x8000) { + /* Block is allocated - mark block as free */ + origsize = pagetable[index] & 0x7fff; + pagetable[index] = origsize; + + /* If next block is free, we concat both blocks */ + if (!(pagetable[index + origsize] & 0x8000)) + pagetable[index] += pagetable[index + origsize] & 0x7fff; + } + + spin_unlock_irqrestore(&card->lock, flags); + + return; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/hwaccess.c linux/drivers/sound/emu10k1/hwaccess.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/hwaccess.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/hwaccess.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,430 @@ + +/* + ********************************************************************** + * hwaccess.c -- Hardware access layer + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * December 9, 1999 Jon Taylor rewrote the I/O subsystem + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "icardmid.h" + +/************************************************************************* +* Function : srToPitch * +* Input : sampleRate - sampling rate * +* Return : pitch value * +* About : convert sampling rate to pitch * +* Note : for 8010, sampling rate is at 48kHz, this function should * +* be changed. * +*************************************************************************/ +u32 srToPitch(u32 sampleRate) +{ + int i; + + /* FIXME: These tables should be defined in a headerfile */ + static u32 logMagTable[128] = { + 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2, + 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5, + 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081, + 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191, + 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, + 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, + 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e, + 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26, + 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d, + 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885, + 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, + 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, + 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, + 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3, + 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83, + 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df + }; + + static char logSlopeTable[128] = { + 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58, + 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53, + 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, + 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, + 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47, + 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, + 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, + 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, + 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, + 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, + 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35, + 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f + }; + + if (sampleRate == 0) + return (0); /* Bail out if no leading "1" */ + + sampleRate *= 11185; /* Scale 48000 to 0x20002380 */ + + for (i = 31; i > 0; i--) { + if (sampleRate & 0x80000000) { /* Detect leading "1" */ + return (u32) (((s32) (i - 15) << 20) + + logMagTable[0x7f & (sampleRate >> 24)] + + (0x7f & (sampleRate >> 17)) * logSlopeTable[0x7f & (sampleRate >> 24)]); + } + sampleRate = sampleRate << 1; + } + + DPF(2, "srToPitch: BUG!\n"); + return 0; /* Should never reach this point */ +} + +/* Returns an attenuation based upon a cumulative volume value */ + +/* Algorithm calculates 0x200 - 0x10 log2 (input) */ +u8 sumVolumeToAttenuation(u32 value) +{ + u16 count = 16; + s16 ans; + + if (value == 0) + return 0xFF; + + /* Find first SET bit. This is the integer part of the value */ + while ((value & 0x10000) == 0) { + value <<= 1; + count--; + } + + /* The REST of the data is the fractional part. */ + ans = (s16) (0x110 - ((count << 4) + ((value & 0x0FFFFL) >> 12))); + if (ans > 0xFF) + ans = 0xFF; + + return (u8) ans; +} + +/******************************************* +* write/read PCI function 0 registers * +********************************************/ +void sblive_writefn0(struct emu10k1_card *card, u8 reg, u32 data) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + outl(data, card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + + return; +} + +void sblive_wrtmskfn0(struct emu10k1_card *card, u8 reg, u32 mask, u32 data) +{ + unsigned long flags; + + data &= mask; + + spin_lock_irqsave(&card->lock, flags); + data |= inl(card->iobase + reg) & ~mask; + outl(data, card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + + return; +} + +u32 sblive_readfn0(struct emu10k1_card * card, u8 reg) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + return val; +} + +u32 sblive_rdmskfn0(struct emu10k1_card * card, u8 reg, u32 mask) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + return val & mask; +} + +/************************************************************************ +* write/read Emu10k1 pointer-offset register set, accessed through * +* the PTR and DATA registers * +*************************************************************************/ +void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data) +{ + u32 regptr; + unsigned long flags; + + regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); + + if (reg & 0xff000000) { + u32 mask; + u8 size, offset; + + size = (reg >> 24) & 0x3f; + offset = (reg >> 16) & 0x1f; + mask = ((1 << size) - 1) << offset; + data = (data << offset) & mask; + + spin_lock_irqsave(&card->lock, flags); + outl(regptr, card->iobase + PTR); + data |= inl(card->iobase + DATA) & ~mask; + outl(data, card->iobase + DATA); + spin_unlock_irqrestore(&card->lock, flags); + } else { + spin_lock_irqsave(&card->lock, flags); + outl(regptr, card->iobase + PTR); + outl(data, card->iobase + DATA); + spin_unlock_irqrestore(&card->lock, flags); + } + + return; +} + +u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel) +{ + u32 regptr, val; + unsigned long flags; + + regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); + + if (reg & 0xff000000) { + u32 mask; + u8 size, offset; + + size = (reg >> 24) & 0x3f; + offset = (reg >> 16) & 0x1f; + mask = ((1 << size) - 1) << offset; + + spin_lock_irqsave(&card->lock, flags); + outl(regptr, card->iobase + PTR); + val = inl(card->iobase + DATA); + spin_unlock_irqrestore(&card->lock, flags); + + return (val & mask) >> offset; + } else { + spin_lock_irqsave(&card->lock, flags); + outl(regptr, card->iobase + PTR); + val = inl(card->iobase + DATA); + spin_unlock_irqrestore(&card->lock, flags); + + return val; + } +} + +void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum) +{ + /* Voice interrupt */ + if (voicenum >= 32) + sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 1); + else + sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 1); + + return; +} + +void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum) +{ + /* Voice interrupt */ + if (voicenum >= 32) + sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0); + else + sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0); + + return; +} + +static void sblive_wcwait(struct emu10k1_card *card, u32 wait) +{ + volatile unsigned uCount; + u32 newtime = 0, curtime; + + curtime = READ_FN0(card, WC_SAMPLECOUNTER); + while (wait--) { + uCount = 0; + while (uCount++ < TIMEOUT) { + newtime = READ_FN0(card, WC_SAMPLECOUNTER); + if (newtime != curtime) + break; + } + + if (uCount >= TIMEOUT) + break; + + curtime = newtime; + } +} + +int sblive_readac97(struct emu10k1_card *card, u8 index, u16 * data) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + outb(index, card->mixeraddx + 2); + *data = inw(card->mixeraddx); + + spin_unlock_irqrestore(&card->lock, flags); + + return CTSTATUS_SUCCESS; +} + +int sblive_writeac97(struct emu10k1_card *card, u8 index, u16 data) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + outb(index, card->mixeraddx + 2); + outw(data, card->mixeraddx); + + spin_unlock_irqrestore(&card->lock, flags); + + return CTSTATUS_SUCCESS; +} + +int sblive_rmwac97(struct emu10k1_card *card, u8 index, u16 data, u16 mask) +{ + u16 temp; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + outb(index, card->mixeraddx + 2); + temp = inw(card->mixeraddx); + temp &= ~mask; + data &= mask; + temp |= data; + outw(temp, card->mixeraddx); + + spin_unlock_irqrestore(&card->lock, flags); + + return CTSTATUS_SUCCESS; +} + +/********************************************************* +* MPU access functions * +**********************************************************/ + +int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&card->lock, flags); + + if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) { + outb(data, card->iobase + MUDATA); + ret = CTSTATUS_SUCCESS; + } else + ret = CTSTATUS_BUSY; + + spin_unlock_irqrestore(&card->lock, flags); + + return ret; +} + +int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&card->lock, flags); + + if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) { + *data = inb(card->iobase + MUDATA); + ret = CTSTATUS_SUCCESS; + } else + ret = CTSTATUS_NODATA; + + spin_unlock_irqrestore(&card->lock, flags); + + return ret; +} + +int emu10k1_mpu_reset(struct emu10k1_card *card) +{ + u8 status; + unsigned long flags; + + DPF(2, "emu10k1_mpu_reset()\n"); + + if (card->mpuacqcount == 0) { + spin_lock_irqsave(&card->lock, flags); + outb(MUCMD_RESET, card->iobase + MUCMD); + spin_unlock_irqrestore(&card->lock, flags); + + sblive_wcwait(card, 8); + + spin_lock_irqsave(&card->lock, flags); + outb(MUCMD_RESET, card->iobase + MUCMD); + spin_unlock_irqrestore(&card->lock, flags); + + sblive_wcwait(card, 8); + + spin_lock_irqsave(&card->lock, flags); + outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD); + spin_unlock_irqrestore(&card->lock, flags); + + sblive_wcwait(card, 8); + + spin_lock_irqsave(&card->lock, flags); + status = inb(card->iobase + MUDATA); + spin_unlock_irqrestore(&card->lock, flags); + + if (status == 0xfe) + return CTSTATUS_SUCCESS; + else + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} + +int emu10k1_mpu_acquire(struct emu10k1_card *card) +{ + /* FIXME: This should be a macro */ + ++card->mpuacqcount; + + return CTSTATUS_SUCCESS; +} + +int emu10k1_mpu_release(struct emu10k1_card *card) +{ + /* FIXME: this should be a macro */ + --card->mpuacqcount; + + return CTSTATUS_SUCCESS; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/hwaccess.h linux/drivers/sound/emu10k1/hwaccess.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/hwaccess.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/hwaccess.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,204 @@ +/* + ********************************************************************** + * hwaccess.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _HWACCESS_H +#define _HWACCESS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +enum GlobalErrorCode +{ + CTSTATUS_SUCCESS = 0x0000, + CTSTATUS_ERROR, + CTSTATUS_NOMEMORY, + CTSTATUS_INUSE, +}; + +#define FLAGS_AVAILABLE 0x0001 +#define FLAGS_READY 0x0002 + +#define min(x,y) ((x) < (y)) ? (x) : (y) + +struct memhandle +{ + unsigned long busaddx; + void *virtaddx; + u32 order; +}; + +struct memhandle *emu10k1_alloc_memphysical(u32); +void emu10k1_free_memphysical(struct memhandle *); + +#define DEBUG_LEVEL 2 + +#ifdef EMU10K1_DEBUG +# define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0) +# define DPF(level,x) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0) +#define ERROR() DPF(1,"error\n"); +#else +# define DPD(level,x,y...) /* not debugging: nothing */ +# define DPF(level,x) +#define ERROR() +#endif /* EMU10K1_DEBUG */ + +#include "8010.h" +#include "voicemgr.h" + +int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *); +void emu10k1_addxmgr_free(struct emu10k1_card *, int); + +#include "timer.h" +#include "irqmgr.h" + +/* DATA STRUCTURES */ + +struct emu10k1_card +{ + struct list_head list; + + struct memhandle *virtualpagetable; + + struct memhandle *tankmem; + u32 tmemsize; + struct memhandle *silentpage; + + spinlock_t lock; + + struct voice_manager voicemgr; + u16 emupagetable[MAXPAGES]; + + struct list_head timers; + unsigned timer_delay; + spinlock_t timer_lock; + + struct pci_dev *pci_dev; + unsigned long iobase; + unsigned long mixeraddx; + u32 irq; + + unsigned long audio1_num; + unsigned long audio2_num; + unsigned long mixer_num; + unsigned long midi_num; + + struct emu10k1_waveout *waveout; + struct emu10k1_wavein *wavein; + struct emu10k1_mpuout *mpuout; + struct emu10k1_mpuin *mpuin; + + u16 arrwVol[SOUND_MIXER_NRDEVICES + 1]; + /* array is used from the member 1 to save (-1) operation */ + u32 digmix[96]; + unsigned int modcnt; + struct semaphore open_sem; + mode_t open_mode; + wait_queue_head_t open_wait; + + u32 mpuacqcount; // Mpu acquire count + u32 has_toslink; // TOSLink detection + + u8 chiprev; /* Chip revision */ +}; + +#ifdef PRIVATE_PCM_VOLUME + +#define MAX_PCM_CHANNELS NUM_G +struct sblive_pcm_volume_rec { + struct files_struct *files; // identification of the same thread + u8 attn_l; // attenuation for left channel + u8 attn_r; // attenuation for right channel + u16 mixer; // saved mixer value for return + u8 channel_l; // idx of left channel + u8 channel_r; // idx of right channel + int opened; // counter - locks element +}; +extern struct sblive_pcm_volume_rec sblive_pcm_volume[]; + +#endif + + +#define ENABLE 0xffffffff +#define DISABLE 0x00000000 + +#define ENV_ON 0x80 +#define ENV_OFF 0x00 + +#define TIMEOUT 16384 + +u32 srToPitch(u32); +u8 sumVolumeToAttenuation(u32); + +extern struct list_head emu10k1_devs; + +/* Hardware Abstraction Layer access functions */ + +#define WRITE_FN0(a,b,c) sblive_wrtmskfn0((a),(u8)(b), ((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f), (c) << (((b) >> 16) & 0x1f)) + +#define READ_FN0(a,b) sblive_rdmskfn0((a),(u8)(b),((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f)) >> (((b) >> 16) & 0x1f) + +void sblive_writefn0(struct emu10k1_card *, u8 , u32 ); +void sblive_wrtmskfn0(struct emu10k1_card *, u8 , u32 , u32 ); + +u32 sblive_readfn0(struct emu10k1_card *, u8 ); +u32 sblive_rdmskfn0(struct emu10k1_card *, u8, u32 ); + +void sblive_writeptr(struct emu10k1_card *, u32 , u32 , u32 ); +u32 sblive_readptr(struct emu10k1_card *, u32 , u32 ); + +void emu10k1_set_stop_on_loop(struct emu10k1_card *, u32); +void emu10k1_clear_stop_on_loop(struct emu10k1_card *, u32); + +/* AC97 Mixer access function */ +int sblive_readac97(struct emu10k1_card *, u8, u16 *); +int sblive_writeac97(struct emu10k1_card *, u8, u16); +int sblive_rmwac97(struct emu10k1_card *, u8, u16, u16); + +/* MPU access function*/ +int emu10k1_mpu_write_data(struct emu10k1_card *, u8); +int emu10k1_mpu_read_data(struct emu10k1_card *, u8 *); +int emu10k1_mpu_reset(struct emu10k1_card *); +int emu10k1_mpu_acquire(struct emu10k1_card *); +int emu10k1_mpu_release(struct emu10k1_card *); + +#endif /* _HWACCESS_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/icardmid.h linux/drivers/sound/emu10k1/icardmid.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/icardmid.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/icardmid.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,163 @@ +/* + ********************************************************************** + * isblive_mid.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _ICARDMIDI_H +#define _ICARDMIDI_H + +/* MIDI defines */ +#define MIDI_DATA_FIRST 0x00 +#define MIDI_DATA_LAST 0x7F +#define MIDI_STATUS_FIRST 0x80 +#define MIDI_STATUS_LAST 0xFF + +/* Channel status bytes */ +#define MIDI_STATUS_CHANNEL_FIRST 0x80 +#define MIDI_STATUS_CHANNEL_LAST 0xE0 +#define MIDI_STATUS_CHANNEL_MASK 0xF0 + +/* Channel voice messages */ +#define MIDI_VOICE_NOTE_OFF 0x80 +#define MIDI_VOICE_NOTE_ON 0x90 +#define MIDI_VOICE_POLY_PRESSURE 0xA0 +#define MIDI_VOICE_CONTROL_CHANGE 0xB0 +#define MIDI_VOICE_PROGRAM_CHANGE 0xC0 +#define MIDI_VOICE_CHANNEL_PRESSURE 0xD0 +#define MIDI_VOICE_PITCH_BEND 0xE0 + +/* Channel mode messages */ +#define MIDI_MODE_CHANNEL MIDI_VOICE_CONTROL_CHANGE + +/* System status bytes */ +#define MIDI_STATUS_SYSTEM_FIRST 0xF0 +#define MIDI_STATUS_SYSTEM_LAST 0xFF + +/* System exclusive messages */ +#define MIDI_SYSEX_BEGIN 0xF0 +#define MIDI_SYSEX_EOX 0xF7 + +/* System common messages */ +#define MIDI_COMMON_TCQF 0xF1 /* Time code quarter frame */ +#define MIDI_COMMON_SONG_POSITION 0xF2 +#define MIDI_COMMON_SONG_SELECT 0xF3 +#define MIDI_COMMON_UNDEFINED_F4 0xF4 +#define MIDI_COMMON_UNDEFINED_F5 0xF5 +#define MIDI_COMMON_TUNE_REQUEST 0xF6 + +/* System real-time messages */ +#define MIDI_RTIME_TIMING_CLOCK 0xF8 +#define MIDI_RTIME_UNDEFINED_F9 0xF9 +#define MIDI_RTIME_START 0xFA +#define MIDI_RTIME_CONTINUE 0xFB +#define MIDI_RTIME_STOP 0xFC +#define MIDI_RTIME_UNDEFINED_FD 0xFD +#define MIDI_RTIME_ACTIVE_SENSING 0xFE +#define MIDI_RTIME_SYSTEM_RESET 0xFF + +/* Flags for flags parm of midiOutCachePatches(), midiOutCacheDrumPatches() */ +#define MIDI_CACHE_ALL 1 +#define MIDI_CACHE_BESTFIT 2 +#define MIDI_CACHE_QUERY 3 +#define MIDI_UNCACHE 4 + +/* Event declarations for MPU IRQ Callbacks */ +#define ICARDMIDI_INLONGDATA 0x00000001 /* MIM_LONGDATA */ +#define ICARDMIDI_INLONGERROR 0x00000002 /* MIM_LONGERROR */ +#define ICARDMIDI_OUTLONGDATA 0x00000004 /* MOM_DONE for MPU OUT buffer */ +#define ICARDMIDI_INDATA 0x00000010 /* MIM_DATA */ +#define ICARDMIDI_INDATAERROR 0x00000020 /* MIM_ERROR */ + +/* Declaration for flags in CARDMIDIBUFFERHDR */ +/* Make it the same as MHDR_DONE, MHDR_INQUEUE in mmsystem.h */ +#define MIDIBUF_DONE 0x00000001 +#define MIDIBUF_INQUEUE 0x00000004 + +/* Declaration for msg parameter in midiCallbackFn */ +#define ICARDMIDI_OUTBUFFEROK 0x00000001 +#define ICARDMIDI_INMIDIOK 0x00000002 + +/* Declaration for technology in struct midi_caps */ +#define MT_MIDIPORT 0x00000001 /* In original MIDIOUTCAPS structure */ +#define MT_FMSYNTH 0x00000004 /* In original MIDIOUTCAPS structure */ +#define MT_AWESYNTH 0x00001000 +#define MT_PCISYNTH 0x00002000 +#define MT_PCISYNTH64 0x00004000 +#define CARDMIDI_AWEMASK 0x0000F000 + +enum LocalErrorCode +{ + CTSTATUS_NOTENABLED = 0x7000, + CTSTATUS_READY, + CTSTATUS_BUSY, + CTSTATUS_DATAAVAIL, + CTSTATUS_NODATA, + CTSTATUS_NEXT_BYTE +}; + +/* MIDI data block header */ +struct midi_hdr +{ + u8 *reserved; /* Pointer to original locked data block */ + u32 bufferlength; /* Length of data in data block */ + u32 bytesrecorded; /* Used for input only */ + u32 user; /* For client's use */ + u32 flags; /* Assorted flags (see defines) */ + struct list_head list; /* Reserved for driver */ + u8 *data; /* Second copy of first pointer */ +}; + +/* Enumeration for SetControl */ +enum +{ + MIDIOBJVOLUME = 0x1, + MIDIQUERYACTIVEINST +}; + +struct midi_queue +{ + struct midi_queue *next; + u32 qtype; /* 0 = short message, 1 = long data */ + u32 length; + u32 sizeLeft; + u8 *midibyte; + unsigned long refdata; +}; + +struct midi_openinfo +{ + u32 cbsize; + u32 flags; + unsigned long refdata; + u32 streamid; +}; + +int emu10k1_midi_callback(unsigned long , unsigned long, unsigned long *); + +#endif /* _ICARDMIDI_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/icardwav.h linux/drivers/sound/emu10k1/icardwav.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/icardwav.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/icardwav.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,52 @@ +/* + ********************************************************************** + * icardwav.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _ICARDWAV_H +#define _ICARDWAV_H + +/* Enumeration for SetControl */ +enum +{ + WAVECURPOS = 0x10, +}; + +struct wave_format +{ + u32 samplingrate; + u32 bitsperchannel; + u32 channels; /* 1 = Mono, 2 = Stereo */ +}; + +/* emu10k1_wave states */ +#define CARDWAVE_STATE_STOPPED 0x0001 +#define CARDWAVE_STATE_STARTED 0x0002 + +#endif /* _ICARDWAV_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/irqmgr.c linux/drivers/sound/emu10k1/irqmgr.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/irqmgr.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/irqmgr.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,127 @@ + +/* + ********************************************************************** + * irqmgr.c - IRQ manager for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "cardmi.h" +#include "cardmo.h" +#include "irqmgr.h" + +/* Interrupt handler */ + +void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct emu10k1_card *card = (struct emu10k1_card *) dev_id; + u32 irqstatus, ptr, tmp; + + if (!(irqstatus = sblive_readfn0(card, IPR))) + return; + + DPD(4, "emu10k1_interrupt called, irq = %u\n", irq); + + /* Preserve PTR register */ + ptr = sblive_readfn0(card, PTR); + + /* + ** NOTE : + ** We do a 'while loop' here cos on certain machines, with both + ** playback and recording going on at the same time, IRQs will + ** stop coming in after a while. Checking IPND indeed shows that + ** there are interrupts pending but the PIC says no IRQs pending. + ** I suspect that some boards need edge-triggered IRQs but are not + ** getting that condition if we don't completely clear the IPND + ** (make sure no more interrupts are pending). + ** - Eric + */ + + do { + DPD(4, "irq status %x\n", irqstatus); + + tmp = irqstatus; + + if (irqstatus & IRQTYPE_TIMER) { + emu10k1_timer_irqhandler(card); + irqstatus &= ~IRQTYPE_TIMER; + } + + if (irqstatus & IRQTYPE_MPUIN) { + emu10k1_mpuin_irqhandler(card); + irqstatus &= ~IRQTYPE_MPUIN; + } + + if (irqstatus & IRQTYPE_MPUOUT) { + emu10k1_mpuout_irqhandler(card); + irqstatus &= ~IRQTYPE_MPUOUT; + } + + if (irqstatus) + emu10k1_irq_disable(card, irqstatus); + + sblive_writefn0(card, IPR, tmp); + + } while ((irqstatus = sblive_readfn0(card, IPR))); + + sblive_writefn0(card, PTR, ptr); + + return; +} + +/* Enables the specified irq service */ + +int emu10k1_irq_enable(struct emu10k1_card *card, u32 irqtype) +{ + /* + * TODO : + * put protection here so that we don't accidentally + * screw-up another cardxxx objects irqs + */ + + DPD(4, "emu10k1_irq_enable %x\n", irqtype); + sblive_wrtmskfn0(card, INTE, irqtype, ENABLE); + + return CTSTATUS_SUCCESS; +} + +/* Disables the specified irq service */ + +int emu10k1_irq_disable(struct emu10k1_card *card, u32 irqtype) +{ + /* + * TODO : + * put protection here so that we don't accidentally + * screw-up another cardxxx objects irqs + */ + + DPD(4, "emu10k1_irq_disable %x\n", irqtype); + sblive_wrtmskfn0(card, INTE, irqtype, DISABLE); + + return CTSTATUS_SUCCESS; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/irqmgr.h linux/drivers/sound/emu10k1/irqmgr.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/irqmgr.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/irqmgr.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,59 @@ +/* + ********************************************************************** + * irq.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _IRQ_H +#define _IRQ_H + +/* EMU Irq Types */ +#define IRQTYPE_PCIBUSERROR IPR_PCIERROR +#define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE) +#define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK) +#define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL) +#define IRQTYPE_MPUOUT IPR_MIDITRANSBUFEMPTY +#define IRQTYPE_MPUIN IPR_MIDIRECVBUFEMPTY +#define IRQTYPE_TIMER IPR_INTERVALTIMER +#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE) +#define IRQTYPE_DSP IPR_FXDSP + +struct emu10k1_wavedevice +{ + struct emu10k1_card *card; + struct wiinst *wiinst; + struct woinst *woinst; + u16 enablebits; +}; + +void emu10k1_timer_irqhandler(struct emu10k1_card *); + +int emu10k1_irq_enable(struct emu10k1_card *, u32); +int emu10k1_irq_disable(struct emu10k1_card *, u32); + +#endif /* _IRQ_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/main.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/main.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,825 @@ + +/* + ********************************************************************** + * main.c - Creative EMU10K1 audio driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up stuff + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + * + * Supported devices: + * /dev/dsp: Standard /dev/dsp device, OSS-compatible + * /dev/mixer: Standard /dev/mixer device, OSS-compatible + * /dev/midi: Raw MIDI UART device, mostly OSS-compatible + * + * Revision history: + * 0.1 beta Initial release + * 0.2 Lowered initial mixer vol. Improved on stuttering wave playback. Added MIDI UART support. + * 0.3 Fixed mixer routing bug, added APS, joystick support. + * 0.4 Added rear-channel, SPDIF support. + * 0.5 Source cleanup, SMP fixes, multiopen support, 64 bit arch fixes, + * moved bh's to tasklets, moved to the new PCI driver initialization style. + ********************************************************************** + */ + +/* These are only included once per module */ +#include +#include + +#include "hwaccess.h" +#include "efxmgr.h" +#include "cardwo.h" +#include "cardwi.h" +#include "cardmo.h" +#include "cardmi.h" +#include "recmgr.h" + +#define DRIVER_VERSION "0.5" + +/* FIXME: is this right? */ +#define EMU10K1_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */ + +#ifndef PCI_VENDOR_ID_CREATIVE +#define PCI_VENDOR_ID_CREATIVE 0x1102 +#endif + +#ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1 +#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 +#endif + +#define EMU10K1_EXTENT 0x20 /* 32 byte I/O space */ + +enum { + EMU10K1 = 0, +}; + +static char *card_names[] __devinitdata = { + "EMU10K1", +}; + +static struct pci_device_id emu10k1_pci_tbl[] __initdata = { + {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, emu10k1_pci_tbl); + +/* Global var instantiation */ + +LIST_HEAD(emu10k1_devs); + +extern struct file_operations emu10k1_audio_fops; +extern struct file_operations emu10k1_mixer_fops; +extern struct file_operations emu10k1_midi_fops; + +extern void emu10k1_interrupt(int, void *, struct pt_regs *s); +extern int emu10k1_mixer_wrch(struct emu10k1_card *, unsigned int, int); + +static int __devinit audio_init(struct emu10k1_card *card) +{ + if ((card->waveout = kmalloc(sizeof(struct emu10k1_waveout), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_waveout: out of memory\n"); + return CTSTATUS_ERROR; + } + memset(card->waveout, 0, sizeof(struct emu10k1_waveout)); + + /* Assign default global volume, reverb, chorus */ + card->waveout->globalvol = 0xffffffff; + card->waveout->left = 0xffff; + card->waveout->right = 0xffff; + card->waveout->mute = 0; + card->waveout->globalreverb = 0xffffffff; + card->waveout->globalchorus = 0xffffffff; + + if ((card->wavein = kmalloc(sizeof(struct emu10k1_wavein), GFP_KERNEL)) + == NULL) { + printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_wavein: out of memory\n"); + return CTSTATUS_ERROR; + } + memset(card->wavein, 0, sizeof(struct emu10k1_wavein)); + + card->wavein->recsrc = WAVERECORD_AC97; + + return CTSTATUS_SUCCESS; +} + +static void __devinit mixer_init(struct emu10k1_card *card) +{ + int count; + struct initvol { + int mixch; + int vol; + } initvol[] = { + { + SOUND_MIXER_VOLUME, 0x5050}, { + SOUND_MIXER_OGAIN, 0x3232}, { + SOUND_MIXER_SPEAKER, 0x3232}, { + SOUND_MIXER_PHONEIN, 0x3232}, { + SOUND_MIXER_MIC, 0x0000}, { + SOUND_MIXER_LINE, 0x0000}, { + SOUND_MIXER_CD, 0x3232}, { + SOUND_MIXER_LINE1, 0x3232}, { + SOUND_MIXER_LINE3, 0x3232}, { + SOUND_MIXER_DIGITAL1, 0x6464}, { + SOUND_MIXER_DIGITAL2, 0x6464}, { + SOUND_MIXER_PCM, 0x6464}, { + SOUND_MIXER_RECLEV, 0x3232}, { + SOUND_MIXER_TREBLE, 0x3232}, { + SOUND_MIXER_BASS, 0x3232}, { + SOUND_MIXER_LINE2, 0x4b4b}}; + + int initdig[] = { 0, 1, 2, 3, 6, 7, 16, 17, 18, 19, 22, 23, 64, 65, 66, 67, 70, 71, + 84, 85 + }; + + /* Reset */ + sblive_writeac97(card, AC97_RESET, 0); + +#if 0 + /* Check status word */ + { + u16 reg; + + sblive_readac97(card, AC97_RESET, ®); + DPD(2, "RESET 0x%x\n", reg); + sblive_readac97(card, AC97_MASTERTONE, ®); + DPD(2, "MASTER_TONE 0x%x\n", reg); + } +#endif + + /* Set default recording source to mic in */ + sblive_writeac97(card, AC97_RECORDSELECT, 0); + + /* Set default AC97 "PCM" volume to acceptable max */ + //sblive_writeac97(card, AC97_PCMOUTVOLUME, 0); + //sblive_writeac97(card, AC97_LINE2, 0); + + /* Set default volumes for all mixer channels */ + + for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) { + card->digmix[count] = 0x80000000; + sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0); + } + + for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) { + card->digmix[initdig[count]] = 0x7fffffff; + sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff); + } + + for (count = 0; count < sizeof(initvol) / sizeof(initvol[0]); count++) { + emu10k1_mixer_wrch(card, initvol[count].mixch, initvol[count].vol); + } + + card->modcnt = 0; // Should this be here or in open() ? + + return; +} + +static int __devinit midi_init(struct emu10k1_card *card) +{ + if ((card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL)) + == NULL) { + printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n"); + return CTSTATUS_ERROR; + } + + memset(card->mpuout, 0, sizeof(struct emu10k1_mpuout)); + + card->mpuout->intr = 1; + card->mpuout->status = FLAGS_AVAILABLE; + card->mpuout->state = CARDMIDIOUT_STATE_DEFAULT; + + tasklet_init(&card->mpuout->tasklet, emu10k1_mpuout_bh, (unsigned long) card); + + spin_lock_init(&card->mpuout->lock); + + if ((card->mpuin = kmalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL)) == NULL) { + kfree(card->mpuout); + printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuin: out of memory\n"); + return CTSTATUS_ERROR; + } + + memset(card->mpuin, 0, sizeof(struct emu10k1_mpuin)); + + card->mpuin->status = FLAGS_AVAILABLE; + + tasklet_init(&card->mpuin->tasklet, emu10k1_mpuin_bh, (unsigned long) card->mpuin); + + spin_lock_init(&card->mpuin->lock); + + /* Reset the MPU port */ + if (emu10k1_mpu_reset(card) != CTSTATUS_SUCCESS) { + ERROR(); + return CTSTATUS_ERROR; + } + + return CTSTATUS_SUCCESS; +} + +static void __devinit voice_init(struct emu10k1_card *card) +{ + struct voice_manager *voicemgr = &card->voicemgr; + struct emu_voice *voice; + int i; + + voicemgr->card = card; + voicemgr->lock = SPIN_LOCK_UNLOCKED; + + voice = voicemgr->voice; + for (i = 0; i < NUM_G; i++) { + voice->card = card; + voice->usage = VOICEMGR_USAGE_FREE; + voice->num = i; + voice->linked_voice = NULL; + voice++; + } + + return; +} + +static void __devinit timer_init(struct emu10k1_card *card) +{ + INIT_LIST_HEAD(&card->timers); + card->timer_delay = TIMER_STOPPED; + card->timer_lock = SPIN_LOCK_UNLOCKED; + + return; +} + +static void __devinit addxmgr_init(struct emu10k1_card *card) +{ + u32 count; + + for (count = 0; count < MAXPAGES; count++) + card->emupagetable[count] = 0; + + /* Mark first page as used */ + /* This page is reserved by the driver */ + card->emupagetable[0] = 0x8001; + card->emupagetable[1] = MAXPAGES - RESERVED - 1; + + return; +} + +static void __devinit fx_init(struct emu10k1_card *card) +{ + int i, j, k, l; + u32 pc = 0; + + for (i = 0; i < 512; i++) + OP(6, 0x40, 0x40, 0x40, 0x40); + + for (i = 0; i < 256; i++) + sblive_writeptr(card, FXGPREGBASE + i, 0, 0); + + pc = 0; + + for (j = 0; j < 2; j++) { + + OP(4, 0x100, 0x40, j, 0x44); + OP(4, 0x101, 0x40, j + 2, 0x44); + + for (i = 0; i < 6; i++) { + k = i * 16 + j; + OP(0, 0x102, 0x40, 0x110 + k, 0x100); + OP(0, 0x102, 0x102, 0x112 + k, 0x101); + OP(0, 0x102, 0x102, 0x114 + k, 0x10 + j); + OP(0, 0x102, 0x102, 0x116 + k, 0x12 + j); + OP(0, 0x102, 0x102, 0x118 + k, 0x14 + j); + OP(0, 0x102, 0x102, 0x11a + k, 0x16 + j); + OP(0, 0x102, 0x102, 0x11c + k, 0x18 + j); + OP(0, 0x102, 0x102, 0x11e + k, 0x1a + j); + + k = 0x190 + i * 8 + j * 4; + OP(0, 0x40, 0x40, 0x102, 0x170 + j); + OP(7, k + 1, k, k + 1, 0x174 + j); + OP(7, k, 0x102, k, 0x172 + j); + OP(7, k + 3, k + 2, k + 3, 0x178 + j); + OP(0, k + 2, 0x56, k + 2, 0x176 + j); + OP(6, k + 2, k + 2, k + 2, 0x40); + + l = 0x1c0 + i * 8 + j * 4; + OP(0, 0x40, 0x40, k + 2, 0x180 + j); + OP(7, l + 1, l, l + 1, 0x184 + j); + OP(7, l, k + 2, l, 0x182 + j); + OP(7, l + 3, l + 2, l + 3, 0x188 + j); + OP(0, l + 2, 0x56, l + 2, 0x186 + j); + OP(4, l + 2, 0x40, l + 2, 0x46); + + OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40); + + } + } + sblive_writeptr(card, DBG, 0, 0); + + return; +} + +static int __devinit hw_init(struct emu10k1_card *card) +{ + int nCh; + +#ifdef TANKMEM + u32 size = 0; +#endif + u32 sizeIdx = 0; + u32 pagecount, tmp; + + /* Disable audio and lock cache */ + sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE); + + /* Reset recording buffers */ + sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, MICBA, 0, 0); + sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, FXBA, 0, 0); + sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, ADCBA, 0, 0); + + /* Disable channel interrupt */ + sblive_writefn0(card, INTE, DISABLE); + sblive_writeptr(card, CLIEL, 0, 0); + sblive_writeptr(card, CLIEH, 0, 0); + sblive_writeptr(card, SOLEL, 0, 0); + sblive_writeptr(card, SOLEH, 0, 0); + + /* Init envelope engine */ + for (nCh = 0; nCh < NUM_G; nCh++) { + sblive_writeptr(card, DCYSUSV, nCh, ENV_OFF); + sblive_writeptr(card, IP, nCh, 0); + sblive_writeptr(card, VTFT, nCh, 0xffff); + sblive_writeptr(card, CVCF, nCh, 0xffff); + sblive_writeptr(card, PTRX, nCh, 0); + sblive_writeptr(card, CPF, nCh, 0); + sblive_writeptr(card, CCR, nCh, 0); + + sblive_writeptr(card, PSST, nCh, 0); + sblive_writeptr(card, DSL, nCh, 0x10); + sblive_writeptr(card, CCCA, nCh, 0); + sblive_writeptr(card, Z1, nCh, 0); + sblive_writeptr(card, Z2, nCh, 0); + sblive_writeptr(card, FXRT, nCh, 0xd01c0000); + + sblive_writeptr(card, ATKHLDM, nCh, 0); + sblive_writeptr(card, DCYSUSM, nCh, 0); + sblive_writeptr(card, IFATN, nCh, 0xffff); + sblive_writeptr(card, PEFE, nCh, 0); + sblive_writeptr(card, FMMOD, nCh, 0); + sblive_writeptr(card, TREMFRQ, nCh, 24); /* 1 Hz */ + sblive_writeptr(card, FM2FRQ2, nCh, 24); /* 1 Hz */ + sblive_writeptr(card, TEMPENV, nCh, 0); + + /*** These are last so OFF prevents writing ***/ + sblive_writeptr(card, LFOVAL2, nCh, 0); + sblive_writeptr(card, LFOVAL1, nCh, 0); + sblive_writeptr(card, ATKHLDV, nCh, 0); + sblive_writeptr(card, ENVVOL, nCh, 0); + sblive_writeptr(card, ENVVAL, nCh, 0); + } + + /* + ** Init to 0x02109204 : + ** Clock accuracy = 0 (1000ppm) + ** Sample Rate = 2 (48kHz) + ** Audio Channel = 1 (Left of 2) + ** Source Number = 0 (Unspecified) + ** Generation Status = 1 (Original for Cat Code 12) + ** Cat Code = 12 (Digital Signal Mixer) + ** Mode = 0 (Mode 0) + ** Emphasis = 0 (None) + ** CP = 1 (Copyright unasserted) + ** AN = 0 (Digital audio) + ** P = 0 (Consumer) + */ + + /* SPDIF0 */ + sblive_writeptr(card, SPCS0, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + + /* SPDIF1 */ + sblive_writeptr(card, SPCS1, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + + /* SPDIF2 & SPDIF3 */ + sblive_writeptr(card, SPCS2, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + + fx_init(card); /* initialize effects engine */ + + card->tankmem = NULL; + +#ifdef TANKMEM + size = TMEMSIZE; + sizeIdx = TMEMSIZEREG; + while (size > 16384) { + if ((card->tankmem = emu10k1_alloc_memphysical(size)) != NULL) + break; + + size /= 2; + sizeIdx -= 1; + } + + if (card->tankmem == NULL) { + card->tmemsize = 0; + return CTSTATUS_ERROR; + } + + card->tmemsize = size; +#else /* !TANKMEM */ + card->tmemsize = 0; +#endif /* TANKMEM */ + + if ((card->virtualpagetable = emu10k1_alloc_memphysical((MAXPAGES - RESERVED) * sizeof(u32))) == NULL) { + ERROR(); + emu10k1_free_memphysical(card->tankmem); + return CTSTATUS_ERROR; + } + + if ((card->silentpage = emu10k1_alloc_memphysical(EMUPAGESIZE)) == NULL) { + ERROR(); + emu10k1_free_memphysical(card->tankmem); + emu10k1_free_memphysical(card->virtualpagetable); + return CTSTATUS_ERROR; + } else + memset(card->silentpage->virtaddx, 0, EMUPAGESIZE); + + for (pagecount = 0; pagecount < (MAXPAGES - RESERVED); pagecount++) + + ((u32 *) card->virtualpagetable->virtaddx)[pagecount] = (card->silentpage->busaddx * 2) | pagecount; + + /* Init page table & tank memory base register */ + sblive_writeptr(card, PTB, 0, card->virtualpagetable->busaddx); +#ifdef TANKMEM + sblive_writeptr(card, TCB, 0, card->tankmem->busaddx); +#else + sblive_writeptr(card, TCB, 0, 0); +#endif + sblive_writeptr(card, TCBS, 0, sizeIdx); + + for (nCh = 0; nCh < NUM_G; nCh++) { + sblive_writeptr(card, MAPA, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + sblive_writeptr(card, MAPB, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + } + + /* Hokay, now enable the AUD bit */ + /* Enable Audio = 1 */ + /* Mute Disable Audio = 0 */ + /* Lock Tank Memory = 1 */ + /* Lock Sound Memory = 0 */ + /* Auto Mute = 1 */ + + sblive_rmwac97(card, AC97_MASTERVOLUME, 0x8000, 0x8000); + + sblive_writeac97(card, AC97_MASTERVOLUME, 0); + sblive_writeac97(card, AC97_PCMOUTVOLUME, 0); + + sblive_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE | HCFG_JOYENABLE); + + /* TOSLink detection */ + card->has_toslink = 0; + + tmp = sblive_readfn0(card, HCFG); + if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) { + sblive_writefn0(card, HCFG, tmp | 0x800); + + udelay(512); + + if (tmp != (sblive_readfn0(card, HCFG) & ~0x800)) { + card->has_toslink = 1; + sblive_writefn0(card, HCFG, tmp); + } + } + + return CTSTATUS_SUCCESS; +} + +static int __devinit emu10k1_init(struct emu10k1_card *card) +{ + /* Init Card */ + if (hw_init(card) != CTSTATUS_SUCCESS) + return CTSTATUS_ERROR; + + voice_init(card); + timer_init(card); + addxmgr_init(card); + + DPD(2, " hw control register -> %x\n", sblive_readfn0(card, HCFG)); + + return CTSTATUS_SUCCESS; +} + +static void __devexit audio_exit(struct emu10k1_card *card) +{ + kfree(card->waveout); + kfree(card->wavein); + return; +} + +static void __devexit midi_exit(struct emu10k1_card *card) +{ + tasklet_unlock_wait(&card->mpuout->tasklet); + kfree(card->mpuout); + + tasklet_unlock_wait(&card->mpuin->tasklet); + kfree(card->mpuin); + + return; +} + +static void __devexit emu10k1_exit(struct emu10k1_card *card) +{ + int ch; + + sblive_writefn0(card, INTE, DISABLE); + + /** Shutdown the chip **/ + for (ch = 0; ch < NUM_G; ch++) + sblive_writeptr(card, DCYSUSV, ch, ENV_OFF); + + for (ch = 0; ch < NUM_G; ch++) { + sblive_writeptr(card, VTFT, ch, 0); + sblive_writeptr(card, CVCF, ch, 0); + sblive_writeptr(card, PTRX, ch, 0); + sblive_writeptr(card, CPF, ch, 0); + } + + /* Reset recording buffers */ + sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, MICBA, 0, 0); + sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, FXBA, 0, 0); + sblive_writeptr(card, FXWC, 0, 0); + sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, ADCBA, 0, 0); + sblive_writeptr(card, TCBS, 0, TCBS_BUFFSIZE_16K); + sblive_writeptr(card, TCB, 0, 0); + sblive_writeptr(card, DBG, 0, 0x8000); + + /* Disable channel interrupt */ + sblive_writeptr(card, CLIEL, 0, 0); + sblive_writeptr(card, CLIEH, 0, 0); + sblive_writeptr(card, SOLEL, 0, 0); + sblive_writeptr(card, SOLEH, 0, 0); + + /* Disable audio and lock cache */ + sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE); + sblive_writeptr(card, PTB, 0, 0); + + emu10k1_free_memphysical(card->silentpage); + emu10k1_free_memphysical(card->virtualpagetable); +#ifdef TANKMEM + emu10k1_free_memphysical(card->tankmem); +#endif + return; +} + +/* Driver initialization routine */ +static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) +{ + struct emu10k1_card *card; + + if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "emu10k1: out of memory\n"); + return -ENOMEM; + } + memset(card, 0, sizeof(struct emu10k1_card)); + +#if LINUX_VERSION_CODE > 0x020320 + if (!pci_dma_supported(pci_dev, EMU10K1_DMA_MASK)) { + printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n"); + kfree(card); + return -ENODEV; + } + + if (pci_enable_device(pci_dev)) { + printk(KERN_ERR "emu10k1: couldn't enable device\n"); + kfree(card); + return -ENODEV; + } + + pci_set_master(pci_dev); + + card->iobase = pci_dev->resource[0].start; + + if (request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]) == NULL) { + printk(KERN_ERR "emu10k1: IO space in use\n"); + kfree(card); + return -ENODEV; + } + pci_dev->driver_data = card; + pci_dev->dma_mask = EMU10K1_DMA_MASK; +#else + pci_set_master(pci_dev); + + card->iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + + if (check_region(card->iobase, EMU10K1_EXTENT)) { + printk(KERN_ERR "emu10k1: IO space in use\n"); + kfree(card); + return -ENODEV; + } + + request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]); +#endif + card->irq = pci_dev->irq; + card->pci_dev = pci_dev; + + /* Reserve IRQ Line */ + if (request_irq(card->irq, emu10k1_interrupt, SA_SHIRQ, card_names[pci_id->driver_data], card)) { + printk(KERN_ERR "emu10k1: IRQ in use\n"); + goto err_irq; + } + + pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev); + + printk(KERN_INFO "emu10k1: %s rev %d found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->chiprev, card->iobase, card->irq); + + spin_lock_init(&card->lock); + card->mixeraddx = card->iobase + AC97DATA; + init_MUTEX(&card->open_sem); + card->open_mode = 0; + init_waitqueue_head(&card->open_wait); + + /* Register devices */ + if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { + printk(KERN_ERR "emu10k1: cannot register first audio device!\n"); + goto err_dev0; + } + + if ((card->audio2_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { + printk(KERN_ERR "emu10k1: cannot register second audio device!\n"); + goto err_dev1; + } + + if ((card->mixer_num = register_sound_mixer(&emu10k1_mixer_fops, -1)) < 0) { + printk(KERN_ERR "emu10k1: cannot register mixer device!\n"); + goto err_dev2; + } + + if ((card->midi_num = register_sound_midi(&emu10k1_midi_fops, -1)) < 0) { + printk(KERN_ERR "emu10k1: cannot register midi device!\n"); + goto err_dev3; + } + + if (emu10k1_init(card) != CTSTATUS_SUCCESS) { + printk(KERN_ERR "emu10k1: cannot initialize device!\n"); + goto err_emu10k1_init; + } + + if (audio_init(card) != CTSTATUS_SUCCESS) { + printk(KERN_ERR "emu10k1: cannot initialize audio!\n"); + goto err_audio_init; + } + + if (midi_init(card) != CTSTATUS_SUCCESS) { + printk(KERN_ERR "emu10k1: cannot initialize midi!\n"); + goto err_midi_init; + } + + mixer_init(card); + + DPD(2, "Hardware initialized. TRAM allocated: %u bytes\n", (unsigned int) card->tmemsize); + + list_add(&card->list, &emu10k1_devs); + + return 0; + + err_midi_init: + audio_exit(card); + + err_audio_init: + emu10k1_exit(card); + + err_emu10k1_init: + unregister_sound_midi(card->midi_num); + + err_dev3: + unregister_sound_mixer(card->mixer_num); + + err_dev2: + unregister_sound_dsp(card->audio2_num); + + err_dev1: + unregister_sound_dsp(card->audio1_num); + + err_dev0: + free_irq(card->irq, card); + + err_irq: + release_region(card->iobase, EMU10K1_EXTENT); + kfree(card); + + return -ENODEV; +} + +static void __devexit emu10k1_remove(struct pci_dev *pci_dev) +{ +#if LINUX_VERSION_CODE > 0x020320 + struct emu10k1_card *card = pci_dev->driver_data; +#else + struct emu10k1_card *card = list_entry(emu10k1_devs.next, struct emu10k1_card, list); +#endif + midi_exit(card); + audio_exit(card); + emu10k1_exit(card); + + unregister_sound_midi(card->midi_num); + unregister_sound_mixer(card->mixer_num); + unregister_sound_dsp(card->audio2_num); + unregister_sound_dsp(card->audio1_num); + + free_irq(card->irq, card); + release_region(card->iobase, EMU10K1_EXTENT); + + list_del(&card->list); + + kfree(card); + return; +} + +MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)"); +MODULE_DESCRIPTION("Creative EMU10K1 PCI Audio Driver v" DRIVER_VERSION "\nCopyright (C) 1999 Creative Technology Ltd."); + +static struct pci_driver emu10k1_pci_driver __initdata = { + name:"emu10k1", + id_table:emu10k1_pci_tbl, + probe:emu10k1_probe, + remove:emu10k1_remove, +}; + +#if LINUX_VERSION_CODE > 0x020320 +static int __init emu10k1_init_module(void) +{ + printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); + + return pci_module_init(&emu10k1_pci_driver); +} + +static void __exit emu10k1_cleanup_module(void) +{ + pci_unregister_driver(&emu10k1_pci_driver); + return; +} + +#else + +static int __init emu10k1_init_module(void) +{ + struct pci_dev *dev = NULL; + const struct pci_device_id *pci_id = emu10k1_pci_driver.id_table; + + printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); + + if (!pci_present()) + return -ENODEV; + + while (pci_id->vendor) { + while ((dev = pci_find_device(pci_id->vendor, pci_id->device, dev))) + emu10k1_probe(dev, pci_id); + + pci_id++; + } + return 0; +} + +static void __exit emu10k1_cleanup_module(void) +{ + struct emu10k1_card *card; + + while (!list_empty(&emu10k1_devs)) { + card = list_entry(emu10k1_devs.next, struct emu10k1_card, list); + + emu10k1_remove(card->pci_dev); + } + + return; +} + +#endif + +module_init(emu10k1_init_module); +module_exit(emu10k1_cleanup_module); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/midi.c linux/drivers/sound/emu10k1/midi.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/midi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/midi.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,446 @@ + +/* + ********************************************************************** + * midi.c - /dev/midi interface for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#define __NO_VERSION__ +#include +#include + +#include "hwaccess.h" +#include "cardmo.h" +#include "cardmi.h" +#include "midi.h" + +static spinlock_t midi_spinlock = SPIN_LOCK_UNLOCKED; + +static void init_midi_hdr(struct midi_hdr *midihdr) +{ + midihdr->bufferlength = MIDIIN_BUFLEN; + midihdr->bytesrecorded = 0; + midihdr->flags = 0; +} + +static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hdr **midihdrptr) +{ + struct midi_hdr *midihdr; + + if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL) { + ERROR(); + return -EINVAL; + } + + init_midi_hdr(midihdr); + + if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) { + ERROR(); + kfree(midihdr); + return CTSTATUS_ERROR; + } + + if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) != CTSTATUS_SUCCESS) { + ERROR(); + kfree(midihdr->data); + kfree(midihdr); + return CTSTATUS_ERROR; + } + + *midihdrptr = midihdr; + list_add_tail(&midihdr->list, &midi_dev->mid_hdrs); + + return CTSTATUS_SUCCESS; +} + +static int emu10k1_midi_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct emu10k1_card *card; + struct emu10k1_mididevice *midi_dev; + struct list_head *entry; + + DPF(2, "emu10k1_midi_open()\n"); + + /* Check for correct device to open */ + list_for_each(entry, &emu10k1_devs) { + card = list_entry(entry, struct emu10k1_card, list); + + if (card->midi_num == minor) + break; + } + + if (entry == &emu10k1_devs) + return -ENODEV; + + MOD_INC_USE_COUNT; + + /* Wait for device to become free */ + down(&card->open_sem); + while (card->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { + if (file->f_flags & O_NONBLOCK) { + up(&card->open_sem); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + up(&card->open_sem); + interruptible_sleep_on(&card->open_wait); + + if (signal_pending(current)) { + MOD_DEC_USE_COUNT; + return -ERESTARTSYS; + } + + down(&card->open_sem); + } + + if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL) { + MOD_DEC_USE_COUNT; + return -EINVAL; + } + + midi_dev->card = card; + midi_dev->mistate = MIDIIN_STATE_STOPPED; + init_waitqueue_head(&midi_dev->oWait); + init_waitqueue_head(&midi_dev->iWait); + midi_dev->ird = 0; + midi_dev->iwr = 0; + midi_dev->icnt = 0; + INIT_LIST_HEAD(&midi_dev->mid_hdrs); + + if (file->f_mode & FMODE_READ) { + struct midi_openinfo dsCardMidiOpenInfo; + struct midi_hdr *midihdr1; + struct midi_hdr *midihdr2; + + dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev; + + if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) + != CTSTATUS_SUCCESS) { + ERROR(); + kfree(midi_dev); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + /* Add two buffers to receive sysex buffer */ + if (midiin_add_buffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) { + kfree(midi_dev); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + if (midiin_add_buffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) { + list_del(&midihdr1->list); + kfree(midihdr1->data); + kfree(midihdr1); + kfree(midi_dev); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + } + + if (file->f_mode & FMODE_WRITE) { + struct midi_openinfo dsCardMidiOpenInfo; + + dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev; + + if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) + != CTSTATUS_SUCCESS) { + ERROR(); + kfree(midi_dev); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + } + + file->private_data = (void *) midi_dev; + + card->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); + + up(&card->open_sem); + + return 0; +} + +static int emu10k1_midi_release(struct inode *inode, struct file *file) +{ + struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data; + struct emu10k1_card *card = midi_dev->card; + + DPF(2, "emu10k1_midi_release()\n"); + + if (file->f_mode & FMODE_WRITE) { + if (!(file->f_flags & O_NONBLOCK)) { + + while (!signal_pending(current) && (card->mpuout->firstmidiq != NULL)) { + DPF(4, "Cannot close - buffers not empty\n"); + + interruptible_sleep_on(&midi_dev->oWait); + + } + } + + emu10k1_mpuout_close(card); + } + + if (file->f_mode & FMODE_READ) { + struct midi_hdr *midihdr; + + if (midi_dev->mistate == MIDIIN_STATE_STARTED) { + emu10k1_mpuin_stop(card); + midi_dev->mistate = MIDIIN_STATE_STOPPED; + } + + emu10k1_mpuin_reset(card); + emu10k1_mpuin_close(card); + + while (!list_empty(&midi_dev->mid_hdrs)) { + midihdr = list_entry(midi_dev->mid_hdrs.next, struct midi_hdr, list); + + list_del(midi_dev->mid_hdrs.next); + kfree(midihdr->data); + kfree(midihdr); + } + } + + kfree(midi_dev); + + down(&card->open_sem); + card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE)); + up(&card->open_sem); + wake_up_interruptible(&card->open_wait); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static ssize_t emu10k1_midi_read(struct file *file, char *buffer, size_t count, loff_t * pos) +{ + struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data; + ssize_t ret = 0; + u16 cnt; + unsigned long flags; + + DPD(4, "emu10k1_midi_read(), count %x\n", (u32) count); + + if (pos != &file->f_pos) + return -ESPIPE; + + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + + if (midi_dev->mistate == MIDIIN_STATE_STOPPED) { + if (emu10k1_mpuin_start(midi_dev->card) + != CTSTATUS_SUCCESS) { + ERROR(); + return -EINVAL; + } + + midi_dev->mistate = MIDIIN_STATE_STARTED; + } + + while (count > 0) { + cnt = MIDIIN_BUFLEN - midi_dev->ird; + + spin_lock_irqsave(&midi_spinlock, flags); + + if (midi_dev->icnt < cnt) + cnt = midi_dev->icnt; + + spin_unlock_irqrestore(&midi_spinlock, flags); + + if (cnt > count) + cnt = count; + + if (cnt <= 0) { + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + DPF(2, " Go to sleep...\n"); + + interruptible_sleep_on(&midi_dev->iWait); + + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + + continue; + } + + if (copy_to_user(buffer, midi_dev->iBuf + midi_dev->ird, cnt)) { + ERROR(); + return ret ? ret : -EFAULT; + } + + midi_dev->ird += cnt; + midi_dev->ird %= MIDIIN_BUFLEN; + + spin_lock_irqsave(&midi_spinlock, flags); + + midi_dev->icnt -= cnt; + + spin_unlock_irqrestore(&midi_spinlock, flags); + + count -= cnt; + buffer += cnt; + ret += cnt; + + if (midi_dev->icnt == 0) + break; + } + + return ret; +} + +static ssize_t emu10k1_midi_write(struct file *file, const char *buffer, size_t count, loff_t * pos) +{ + struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data; + struct midi_hdr *midihdr; + ssize_t ret = 0; + unsigned long flags; + + DPD(4, "emu10k1_midi_write(), count=%x\n", (u32) count); + + if (pos != &file->f_pos) + return -ESPIPE; + + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + + if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL) + return -EINVAL; + + midihdr->bufferlength = count; + midihdr->bytesrecorded = 0; + midihdr->flags = 0; + + if ((midihdr->data = (u8 *) kmalloc(count, GFP_KERNEL)) == NULL) { + ERROR(); + kfree(midihdr); + return -EINVAL; + } + + if (copy_from_user(midihdr->data, buffer, count)) { + kfree(midihdr->data); + kfree(midihdr); + return ret ? ret : -EFAULT; + } + + spin_lock_irqsave(&midi_spinlock, flags); + + if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) != CTSTATUS_SUCCESS) { + ERROR(); + kfree(midihdr->data); + kfree(midihdr); + spin_unlock_irqrestore(&midi_spinlock, flags); + return -EINVAL; + } + + spin_unlock_irqrestore(&midi_spinlock, flags); + + return count; +} + +static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait) +{ + DPF(4, "emu10k1_midi_poll() called\n"); + return 0; +} + +int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned long *pmsg) +{ + struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) refdata; + struct midi_hdr *midihdr = NULL; + unsigned long flags; + int i; + + DPF(4, "emu10k1_midi_callback()\n"); + + spin_lock_irqsave(&midi_spinlock, flags); + + switch (msg) { + case ICARDMIDI_OUTLONGDATA: + midihdr = (struct midi_hdr *) pmsg[2]; + + kfree(midihdr->data); + kfree(midihdr); + wake_up_interruptible(&midi_dev->oWait); + + break; + + case ICARDMIDI_INLONGDATA: + midihdr = (struct midi_hdr *) pmsg[2]; + + for (i = 0; i < midihdr->bytesrecorded; i++) { + midi_dev->iBuf[midi_dev->iwr++] = midihdr->data[i]; + midi_dev->iwr %= MIDIIN_BUFLEN; + } + + midi_dev->icnt += midihdr->bytesrecorded; + + if (midi_dev->mistate == MIDIIN_STATE_STARTED) { + init_midi_hdr(midihdr); + emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr); + wake_up_interruptible(&midi_dev->iWait); + } + break; + + case ICARDMIDI_INDATA: + { + u8 *pBuf = (u8 *) & pmsg[1]; + u16 bytesvalid = pmsg[2]; + + for (i = 0; i < bytesvalid; i++) { + midi_dev->iBuf[midi_dev->iwr++] = pBuf[i]; + midi_dev->iwr %= MIDIIN_BUFLEN; + } + + midi_dev->icnt += bytesvalid; + } + + wake_up_interruptible(&midi_dev->iWait); + break; + + default: /* Unknown message */ + return CTSTATUS_ERROR; + } + + spin_unlock_irqrestore(&midi_spinlock, flags); + + return CTSTATUS_SUCCESS; +} + +/* MIDI file operations */ +struct file_operations emu10k1_midi_fops = { + read:emu10k1_midi_read, + write:emu10k1_midi_write, + poll:emu10k1_midi_poll, + open:emu10k1_midi_open, + release:emu10k1_midi_release, +}; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/midi.h linux/drivers/sound/emu10k1/midi.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/midi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/midi.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,55 @@ +/* + ********************************************************************** + * midi.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _MIDI_H +#define _MIDI_H + +#define FMODE_MIDI_SHIFT 3 +#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) +#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) + +#define MIDIIN_STATE_STARTED 0x00000001 +#define MIDIIN_STATE_STOPPED 0x00000002 + +#define MIDIIN_BUFLEN 1024 + +struct emu10k1_mididevice +{ + struct emu10k1_card *card; + u32 mistate; + wait_queue_head_t oWait; + wait_queue_head_t iWait; + s8 iBuf[MIDIIN_BUFLEN]; + u16 ird, iwr, icnt; + struct list_head mid_hdrs; +}; + +#endif /* _MIDI_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/mixer.c linux/drivers/sound/emu10k1/mixer.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/mixer.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/mixer.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,824 @@ + +/* + ********************************************************************** + * mixer.c - /dev/mixer interface for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + * This program uses some code from es1371.c, Copyright 1998-1999 + * Thomas Sailer + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up stuff + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#define __NO_VERSION__ /* Kernel version only defined once */ +#include +#include + +#include "hwaccess.h" + +#define AC97_PESSIMISTIC +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +#define vol_to_hw_5(swvol) (31 - (((swvol) * 31) / 100)) +#define vol_to_hw_4(swvol) (15 - (((swvol) * 15) / 100)) + +#define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31) +#define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15) + +#ifdef PRIVATE_PCM_VOLUME +struct sblive_pcm_volume_rec sblive_pcm_volume[MAX_PCM_CHANNELS]; +#endif + +/* --------------------------------------------------------------------- */ + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +#ifdef hweight32 +#undef hweight32 +#endif + +extern __inline__ unsigned int hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +/* Mapping arrays */ +static const unsigned int recsrc[] = { + SOUND_MASK_MIC, + SOUND_MASK_CD, + SOUND_MASK_VIDEO, + SOUND_MASK_LINE1, + SOUND_MASK_LINE, + SOUND_MASK_VOLUME, + SOUND_MASK_OGAIN, /* Used to be PHONEOUT */ + SOUND_MASK_PHONEIN, + SOUND_MASK_TREBLE, + SOUND_MASK_BASS, + SOUND_MASK_MONITOR, + SOUND_MASK_PCM, +}; + +static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = { + /* 5 bit stereo */ + [SOUND_MIXER_LINE] = AC97_LINEINVOLUME, + [SOUND_MIXER_CD] = AC97_CDVOLUME, + [SOUND_MIXER_VIDEO] = AC97_VIDEOVOLUME, + [SOUND_MIXER_LINE1] = AC97_AUXVOLUME, + +/* [SOUND_MIXER_PCM] = AC97_PCMOUTVOLUME, */ + /* 5 bit stereo, setting 6th bit equal to maximum attenuation */ + +/* [SOUND_MIXER_VOLUME] = AC97_MASTERVOLUME, */ + [SOUND_MIXER_PHONEOUT] = AC97_HEADPHONEVOLUME, + /* 5 bit mono, setting 6th bit equal to maximum attenuation */ + [SOUND_MIXER_OGAIN] = AC97_MASTERVOLUMEMONO, + /* 5 bit mono */ + [SOUND_MIXER_PHONEIN] = AC97_PHONEVOLUME, + /* 4 bit mono but shifted by 1 */ + [SOUND_MIXER_SPEAKER] = AC97_PCBEEPVOLUME, + /* 5 bit mono, 7th bit = preamp */ + [SOUND_MIXER_MIC] = AC97_MICVOLUME, + /* 4 bit stereo */ + [SOUND_MIXER_RECLEV] = AC97_RECORDGAIN, + /* 4 bit mono */ + [SOUND_MIXER_IGAIN] = AC97_RECORDGAINMIC, + /* test code */ + [SOUND_MIXER_BASS] = AC97_GENERALPUPOSE, + [SOUND_MIXER_TREBLE] = AC97_MASTERTONE, + [SOUND_MIXER_LINE2] = AC97_PCMOUTVOLUME, + [SOUND_MIXER_DIGITAL2] = AC97_MASTERVOLUME +}; + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + +#define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) + +/* FIXME: mixer_rdch() is broken. */ + +static int mixer_rdch(struct emu10k1_card *card, unsigned int ch, int *arg) +{ + u16 reg; + int j; + int nL, nR; + + switch (ch) { + case SOUND_MIXER_LINE: + case SOUND_MIXER_CD: + case SOUND_MIXER_VIDEO: + case SOUND_MIXER_LINE1: + case SOUND_MIXER_PCM: + case SOUND_MIXER_VOLUME: + sblive_readac97(card, volreg[ch], ®); + nL = ((~(reg >> 8) & 0x1f) * 100) / 32; + nR = (~(reg & 0x1f) * 100) / 32; + DPD(2, "mixer_rdch: l=%d, r=%d\n", nL, nR); + return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg); + + case SOUND_MIXER_OGAIN: + case SOUND_MIXER_PHONEIN: + sblive_readac97(card, volreg[ch], ®); + return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101, (int *) arg); + + case SOUND_MIXER_SPEAKER: + sblive_readac97(card, volreg[ch], ®); + return put_user(reg & 0x8000 ? 0 : ~((reg >> 1) & 0xf) * 0x64 / 0x10 * 0x101, (int *) arg); + + case SOUND_MIXER_MIC: + sblive_readac97(card, volreg[ch], ®); + return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101 + ((reg & 0x40) ? 0x1e1e : 0), (int *) arg); + + case SOUND_MIXER_RECLEV: + sblive_readac97(card, volreg[ch], ®); + nL = ((~(reg >> 8) & 0x1f) * 100) / 16; + nR = (~(reg & 0x1f) * 100) / 16; + return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg); + + case SOUND_MIXER_TREBLE: + case SOUND_MIXER_BASS: + return put_user(0x0000, (int *) arg); + default: + return -EINVAL; + } +} + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = { + /* 5 bit stereo */ + [SOUND_MIXER_LINE] = 1, + [SOUND_MIXER_CD] = 2, + [SOUND_MIXER_VIDEO] = 3, + [SOUND_MIXER_LINE1] = 4, + [SOUND_MIXER_PCM] = 5, + /* 6 bit stereo */ + [SOUND_MIXER_VOLUME] = 6, + [SOUND_MIXER_PHONEOUT] = 7, + /* 6 bit mono */ + [SOUND_MIXER_OGAIN] = 8, + [SOUND_MIXER_PHONEIN] = 9, + /* 4 bit mono but shifted by 1 */ + [SOUND_MIXER_SPEAKER] = 10, + /* 6 bit mono + preamp */ + [SOUND_MIXER_MIC] = 11, + /* 4 bit stereo */ + [SOUND_MIXER_RECLEV] = 12, + /* 4 bit mono */ + [SOUND_MIXER_IGAIN] = 13, + [SOUND_MIXER_TREBLE] = 14, + [SOUND_MIXER_BASS] = 15, + [SOUND_MIXER_LINE2] = 16, + [SOUND_MIXER_LINE3] = 17, + [SOUND_MIXER_DIGITAL1] = 18, + [SOUND_MIXER_DIGITAL2] = 19 +}; + +u32 bass_table[41][5] = { + { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 }, + { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d }, + { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee }, + { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c }, + { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b }, + { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 }, + { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f }, + { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 }, + { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 }, + { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 }, + { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 }, + { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be }, + { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b }, + { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c }, + { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b }, + { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 }, + { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a }, + { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 }, + { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 }, + { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e }, + { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee }, + { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 }, + { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 }, + { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 }, + { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 }, + { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e }, + { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 }, + { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 }, + { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 }, + { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 }, + { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 }, + { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca }, + { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 }, + { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 }, + { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 }, + { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 }, + { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a }, + { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f }, + { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 }, + { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 }, + { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 } +}; + +u32 treble_table[41][5] = { + { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 }, + { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 }, + { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 }, + { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca }, + { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 }, + { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 }, + { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 }, + { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 }, + { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 }, + { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df }, + { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff }, + { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 }, + { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c }, + { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 }, + { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 }, + { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 }, + { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 }, + { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d }, + { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 }, + { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 }, + { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f }, + { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb }, + { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 }, + { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 }, + { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd }, + { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 }, + { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad }, + { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 }, + { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 }, + { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c }, + { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 }, + { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 }, + { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 }, + { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 }, + { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 }, + { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 }, + { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d }, + { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b }, + { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 }, + { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd }, + { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 } +}; + +static void set_bass(struct emu10k1_card *card, int l, int r) +{ + int i; + + l = (l * 40 + 50) / 100; + r = (r * 40 + 50) / 100; + for (i = 0; i < 5; i++) { + sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2), 0, bass_table[l][i]); + sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2) + 1, 0, bass_table[r][i]); + } +} + +static void set_treble(struct emu10k1_card *card, int l, int r) +{ + int i; + + l = (l * 40 + 50) / 100; + r = (r * 40 + 50) / 100; + for (i = 0; i < 5; i++) { + sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, treble_table[l][i]); + sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, treble_table[r][i]); + } +} + +u32 db_table[101] = { + 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540, + 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8, + 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1, + 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0, + 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9, + 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb, + 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005, + 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d, + 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd, + 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8, + 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481, + 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333, + 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d, + 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6, + 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d, + 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf, + 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038, + 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a, + 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea, + 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272, + 0x7fffffff, +}; + +static void update_digital(struct emu10k1_card *card) +{ + int i, k, l1, r1, l2, r2, l3, r3, l4, r4; + u64 j; + + i = card->arrwVol[volidx[SOUND_MIXER_VOLUME]]; + l1 = (i & 0xff); + r1 = ((i >> 8) & 0xff); + i = card->arrwVol[volidx[SOUND_MIXER_LINE3]]; + l2 = i & 0xff; + r2 = (i >> 8) & 0xff; + + i = card->arrwVol[volidx[SOUND_MIXER_PCM]]; + l3 = i & 0xff; + r3 = (i >> 8) & 0xff; + + i = card->arrwVol[volidx[SOUND_MIXER_DIGITAL1]]; + l4 = i & 0xff; + r4 = (i >> 8) & 0xff; + + i = (r1 * r2) / 50; + if (r2 > 50) + r2 = 2 * r1 - i; + else { + r2 = r1; + r1 = i; + } + + i = (l1 * l2) / 50; + if (l2 > 50) + l2 = 2 * l1 - i; + else { + l2 = l1; + l1 = i; + } + + for (i = 0; i < 16; i++) { + if (card->digmix[i] != 0x80000000) { + if ((i >= 0) && (i < 4)) + j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r3]) : ((u64) db_table[l1] * (u64) db_table[l3]); + else if ((i == 6) || (i == 7)) + j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r4]) : ((u64) db_table[l1] * (u64) db_table[l4]); + else + j = ((i & 1) ? db_table[r1] : db_table[l1]) << 31; + card->digmix[i] = j >> 31; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]); + } + } + + for (i = 64; i < 80; i++) { + if (card->digmix[i] != 0x80000000) { + if ((i >= 64) && (i < 68)) + j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r3]) : ((u64) db_table[l2] * (u64) db_table[l3]); + else if ((i == 70) || (i == 71)) + j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r4]) : ((u64) db_table[l2] * (u64) db_table[l4]); + else + j = ((i & 1) ? db_table[r2] : db_table[l2]) << 31; + card->digmix[i] = j >> 31; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]); + } + } + + for (i = 16; i <= 80; i += 16) { + if (i != 64) { + for (k = 0; k < 4; k++) + if (card->digmix[i + k] != 0x80000000) { + card->digmix[i + k] = db_table[l3]; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i + k, 0, card->digmix[i + k]); + } + if (card->digmix[i + 6] != 0x80000000) { + card->digmix[i + 6] = db_table[l4]; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 6, 0, card->digmix[i + 6]); + } + if (card->digmix[i + 7] != 0x80000000) { + card->digmix[i + 7] = db_table[r4]; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]); + } + } + } + +} + +#ifdef PRIVATE_PCM_VOLUME + +/* calc & set attenuation factor for given channel */ +static int set_pcm_attn(struct emu10k1_card *card, int ch, int l) +{ +#ifndef PCMLEVEL +#define PCMLEVEL 140 // almost silence +#endif + int vol = IFATN_ATTENUATION_MASK; // silence + + if (l > 0) + vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100); + sblive_writeptr(card, IFATN, ch, IFATN_FILTERCUTOFF_MASK | vol); + DPD(2, "SOUND_MIXER_PCM: channel:%d level:%d attn:%d\n", ch, l, vol); + + return vol; +#undef PCMLEVEL +} + +/* update value of local PCM volume level (using channel attenuation) + * + * return 1: in case its local change + * 0: if the current process doesn't have entry in table + * (it means this process have not opened audio (mixer usually) + */ +static int update_pcm_attn(struct emu10k1_card *card, unsigned l1, unsigned r1) +{ + int i; + int mixer = (r1 << 8) | l1; + + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + sblive_pcm_volume[i].mixer = mixer; + if (sblive_pcm_volume[i].opened) { + if (sblive_pcm_volume[i].channel_r < NUM_G) { + if (sblive_pcm_volume[i].channel_l < NUM_G) + sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, l1); + sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1); + } else { + // mono voice + if (sblive_pcm_volume[i].channel_l < NUM_G) + sblive_pcm_volume[i].attn_l = + set_pcm_attn(card, sblive_pcm_volume[i].channel_l, (l1 >= r1) ? l1 : r1); + // to correctly handle mono voice here we would need + // to go into stereo mode and move the voice to the right & left + // looks a bit overcomlicated... + } + + } + return 1; + } + } + if (i == MAX_PCM_CHANNELS) + card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer; + + return 0; +} +#endif + +int emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val) +{ + int i; + unsigned l1, r1; + u16 wval; + + l1 = val & 0xff; + r1 = (val >> 8) & 0xff; + if (l1 > 100) + l1 = 100; + if (r1 > 100) + r1 = 100; + + DPD(4, "emu10k1_mixer_wrch() called: ch=%u, l1=%u, r1=%u\n", ch, l1, r1); + + if (!volidx[ch]) + return -EINVAL; +#ifdef PRIVATE_PCM_VOLUME + if (ch != SOUND_MIXER_PCM) +#endif + card->arrwVol[volidx[ch]] = (r1 << 8) | l1; + + switch (ch) { + case SOUND_MIXER_VOLUME: + case SOUND_MIXER_DIGITAL1: + case SOUND_MIXER_LINE3: + DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3"); + update_digital(card); + return 0; + case SOUND_MIXER_PCM: + DPF(4, "SOUND_MIXER_PCM\n"); +#ifdef PRIVATE_PCM_VOLUME + if (update_pcm_attn(card, l1, r1)) + return 0; +#endif + update_digital(card); + return 0; + case SOUND_MIXER_DIGITAL2: + case SOUND_MIXER_LINE2: + case SOUND_MIXER_LINE1: + case SOUND_MIXER_LINE: + case SOUND_MIXER_CD: + DPD(4, "SOUND_MIXER_%s:\n", + (ch == SOUND_MIXER_LINE1) ? "LINE1" : + (ch == SOUND_MIXER_LINE2) ? "LINE2" : (ch == SOUND_MIXER_LINE) ? "LINE" : (ch == SOUND_MIXER_DIGITAL2) ? "DIGITAL2" : "CD"); + wval = ((((100 - l1) * 32 + 50) / 100) << 8) | (((100 - r1) * 32 + 50) / 100); + if (wval == 0x2020) + wval = 0x8000; + else + wval -= ((wval & 0x2020) / 0x20); + sblive_writeac97(card, volreg[ch], wval); + return 0; + + case SOUND_MIXER_OGAIN: + case SOUND_MIXER_PHONEIN: + DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_PHONEIN) ? "PHONEIN" : "OGAIN"); + sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((100 - l1) * 32 + 50) / 100); + return 0; + + case SOUND_MIXER_SPEAKER: + DPF(4, "SOUND_MIXER_SPEAKER:\n"); + sblive_writeac97(card, volreg[ch], (l1 < 4) ? 0x8000 : (((100 - l1) * 16 + 50) / 100) << 1); + return 0; + + case SOUND_MIXER_MIC: + DPF(4, "SOUND_MIXER_MIC:\n"); + i = 0; + if (l1 >= 30) + // 20dB / (34.5dB + 12dB + 20dB) * 100 = 30 + { + l1 -= 30; + i = 0x40; + } + sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((((70 - l1) * 0x20 + 35) / 70) | i)); + return 0; + + case SOUND_MIXER_RECLEV: + DPF(4, "SOUND_MIXER_RECLEV:\n"); + + wval = (((l1 * 16 + 50) / 100) << 8) | ((r1 * 16 + 50) / 100); + if (wval == 0) + wval = 0x8000; + else { + if (wval & 0xff) + wval--; + if (wval & 0xff00) + wval -= 0x0100; + } + sblive_writeac97(card, volreg[ch], wval); + return 0; + + case SOUND_MIXER_TREBLE: + DPF(4, "SOUND_MIXER_TREBLE:\n"); + set_treble(card, l1, r1); + return 0; + + case SOUND_MIXER_BASS: + DPF(4, "SOUND_MIXER_BASS:\n"); + set_bass(card, l1, r1); + return 0; + + default: + DPF(2, "Got unknown SOUND_MIXER ioctl\n"); + return -EINVAL; + } +} + +static loff_t emu10k1_mixer_llseek(struct file *file, loff_t offset, int origin) +{ + DPF(2, "sblive_mixer_llseek() called\n"); + return -ESPIPE; +} + +/* Mixer file operations */ + +/* FIXME: Do we need spinlocks in here? */ +static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + static const char id[] = "SBLive"; + static const char name[] = "Creative SBLive"; + int i, val; + struct emu10k1_card *card = (struct emu10k1_card *) file->private_data; + u16 reg; + + switch (cmd) { + + case SOUND_MIXER_INFO:{ + mixer_info info; + + DPF(4, "SOUND_MIXER_INFO\n"); + + strncpy(info.id, id, sizeof(info.id)); + strncpy(info.name, name, sizeof(info.name)); + + info.modify_counter = card->modcnt; + if (copy_to_user((void *) arg, &info, sizeof(info))) + return -EFAULT; + + return 0; + } + break; + case SOUND_OLD_MIXER_INFO:{ + _old_mixer_info info; + + DPF(4, "SOUND_OLD_MIXER_INFO\n"); + + strncpy(info.id, id, sizeof(info.id)); + strncpy(info.name, name, sizeof(info.name)); + + if (copy_to_user((void *) arg, &info, sizeof(info))) + return -EFAULT; + + return 0; + } + break; + + case OSS_GETVERSION: + DPF(4, "OSS_GETVERSION\n"); + return put_user(SOUND_VERSION, (int *) arg); + break; + + case SOUND_MIXER_PRIVATE1: + DPF(4, "SOUND_MIXER_PRIVATE1"); + + if (copy_to_user((void *) arg, card->digmix, sizeof(card->digmix))) + return -EFAULT; + + return 0; + + break; + case SOUND_MIXER_PRIVATE2: + DPF(4, "SOUND_MIXER_PRIVATE2"); + + if (copy_from_user(card->digmix, (void *) arg, sizeof(card->digmix))) + return -EFAULT; + + for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); i++) + sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & 0x80000000) ? 0 : card->digmix[i]); + return 0; + + break; + + default: + break; + } + + if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) + return -EINVAL; + + if (_IOC_DIR(cmd) == _IOC_READ) { + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + DPF(2, "SOUND_MIXER_READ_RECSRC\n"); + sblive_readac97(card, AC97_RECORDSELECT, ®); + return put_user(recsrc[reg & 7], (int *) arg); + + case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ + DPF(4, "SOUND_MIXER_READ_DEVMASK\n"); + return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | + SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | + SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_PHONEIN | SOUND_MASK_MIC | + SOUND_MASK_BASS | SOUND_MASK_TREBLE | + SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER | + SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | + SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg); + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + DPF(2, "SOUND_MIXER_READ_RECMASK\n"); + return put_user(SOUND_MASK_MIC | SOUND_MASK_CD | + SOUND_MASK_LINE1 | SOUND_MASK_LINE | + SOUND_MASK_VOLUME | SOUND_MASK_OGAIN | + SOUND_MASK_PHONEIN | SOUND_MASK_MONITOR | + SOUND_MASK_PCM, (int *) arg); + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + DPF(2, "SOUND_MIXER_READ_STEREODEVS\n"); + return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | + SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | + SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_BASS | SOUND_MASK_TREBLE | + SOUND_MASK_RECLEV | SOUND_MASK_LINE3 | + SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | + SOUND_MASK_LINE2, (int *) arg); + + case SOUND_MIXER_CAPS: + DPF(2, "SOUND_MIXER_READ_CAPS\n"); + return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg); + +#ifdef PRIVATE_PCM_VOLUME + case SOUND_MIXER_PCM: + // needs to be before default: !! + { + int i; + + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg); + } + } + } +#endif + default: + i = _IOC_NR(cmd); + DPD(4, "SOUND_MIXER_READ(%d)\n", i); + if (i >= SOUND_MIXER_NRDEVICES) + return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return mixer_rdch(card, i, (int *) arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + return put_user(card->arrwVol[volidx[i]], (int *) arg); + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } + } + /* End of _IOC_READ */ + if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE)) + return -EINVAL; + + /* _IOC_WRITE */ + card->modcnt++; + + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + DPF(2, "SOUND_MIXER_WRITE_RECSRC\n"); + + get_user_ret(val, (int *) arg, -EFAULT); + i = hweight32(val); + if (i == 0) + return 0; /*val = mixer_recmask(s); */ + else if (i > 1) { + sblive_readac97(card, AC97_RECORDSELECT, ®); + val &= ~recsrc[reg & 7]; + } + + for (i = 0; i < 8; i++) { + if (val & recsrc[i]) { + DPD(2, "Selecting record source to be 0x%04x\n", 0x0101 * i); + sblive_writeac97(card, AC97_RECORDSELECT, 0x0101 * i); + return 0; + } + } + return 0; + + default: + i = _IOC_NR(cmd); + DPD(4, "SOUND_MIXER_WRITE(%d)\n", i); + + if (i >= SOUND_MIXER_NRDEVICES) + return -EINVAL; + get_user_ret(val, (int *) arg, -EFAULT); + if (emu10k1_mixer_wrch(card, i, val)) + return -EINVAL; + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return mixer_rdch(card, i, (int *) arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + return put_user(card->arrwVol[volidx[i]], (int *) arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + + } +} + +static int emu10k1_mixer_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct emu10k1_card *card; + struct list_head *entry; + + DPF(4, "emu10k1_mixer_open()\n"); + + list_for_each(entry, &emu10k1_devs) { + card = list_entry(entry, struct emu10k1_card, list); + + if (card->mixer_num == minor) + break; + } + + if (entry == &emu10k1_devs) + return -ENODEV; + + MOD_INC_USE_COUNT; + + file->private_data = card; + return 0; +} + +static int emu10k1_mixer_release(struct inode *inode, struct file *file) +{ + DPF(3, "emu10k1_mixer_release()\n"); + MOD_DEC_USE_COUNT; + return 0; +} + +struct file_operations emu10k1_mixer_fops = { + llseek:emu10k1_mixer_llseek, + ioctl:emu10k1_mixer_ioctl, + open:emu10k1_mixer_open, + release:emu10k1_mixer_release, +}; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/osutils.c linux/drivers/sound/emu10k1/osutils.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/osutils.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/osutils.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,91 @@ + +/* + ********************************************************************** + * osutils.c - OS Services layer for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * November 2, 1999 Alan Cox cleaned up + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" + +struct memhandle *emu10k1_alloc_memphysical(u32 size) +{ + struct memhandle *handle; + u32 reqpage, order; + + if ((handle = (struct memhandle *) kmalloc(sizeof(struct memhandle), GFP_KERNEL)) == NULL) + return handle; + + DPD(3, "kmalloc: [%p]\n", handle); + + order = 0; + reqpage = size / PAGE_SIZE; + + if (size % PAGE_SIZE) + reqpage++; + + if (reqpage != 0) { + reqpage--; + while (reqpage > 0) { + reqpage >>= 1; + order++; + } + } + + if ((handle->virtaddx = (void *) __get_free_pages(GFP_KERNEL, order)) == NULL) { + kfree(handle); + + DPD(3, "kfree: [%p]\n", handle); + return (void *) NULL; + } + + /* in linux, we can directly access physical address, don't need to do + * phys_to_virt. + * In linux kernel 2.0.36, virt_to_bus does nothing, get_free_pages + * returns physical address. But in kernel 2.2.1 upwards, + * get_free_pages returns virtual address, we need to convert it + * to physical address. Then this physical address can be used to + * program hardware registers. */ + handle->busaddx = virt_to_bus(handle->virtaddx); + handle->order = order; + + DPD(3, "__get_free_pages: [%p] %lx\n", handle->virtaddx, handle->busaddx); + + return handle; +} + +void emu10k1_free_memphysical(struct memhandle *handle) +{ + free_pages((unsigned long) handle->virtaddx, handle->order); + kfree(handle); + + DPD(3, "free_pages: [%p]\n", handle->virtaddx); + DPD(3, "kfree: [%p]\n", handle); + + return; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/recmgr.c linux/drivers/sound/emu10k1/recmgr.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/recmgr.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/recmgr.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,139 @@ + +/* + ********************************************************************** + * recmgr.c -- Recording manager for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" +#include "recmgr.h" + +void emu10k1_start_record(struct record *rec_ptr) +{ + struct emu10k1_card *hw_ptr = rec_ptr->card; + + DPF(2, "emu10k1_start_record()\n"); + DPD(2, "bus addx: %lx\n", rec_ptr->busaddx); + + sblive_writeptr(hw_ptr, rec_ptr->bufaddrreg, 0, rec_ptr->busaddx); + sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, rec_ptr->bufsize); + + if (rec_ptr->adcctl) + sblive_writeptr(hw_ptr, ADCCR, 0, rec_ptr->adcctl); + + return; +} + +void emu10k1_stop_record(struct record *rec_ptr) +{ + struct emu10k1_card *hw_ptr = rec_ptr->card; + + DPF(2, "emu10k1_stop_record()\n"); + + /* Disable record transfer */ + if (rec_ptr->adcctl) + sblive_writeptr(hw_ptr, ADCCR, 0, 0); + + sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, ADCBS_BUFSIZE_NONE); + + return; +} + +void emu10k1_set_record_src(struct record *rec_ptr, u8 recsrc) +{ + DPF(2, "emu10k1_set_record_src()\n"); + + switch (recsrc) { + + case WAVERECORD_AC97: + DPF(2, "recording source: AC97\n"); + rec_ptr->bufsizereg = ADCBS; + rec_ptr->bufaddrreg = ADCBA; + rec_ptr->bufidxreg = ADCIDX_IDX; + + switch (rec_ptr->samplingrate) { + case 0xBB80: + rec_ptr->adcctl = ADCCR_SAMPLERATE_48; + break; + case 0xAC44: + rec_ptr->adcctl = ADCCR_SAMPLERATE_44; + break; + case 0x7D00: + rec_ptr->adcctl = ADCCR_SAMPLERATE_32; + break; + case 0x5DC0: + rec_ptr->adcctl = ADCCR_SAMPLERATE_24; + break; + case 0x5622: + rec_ptr->adcctl = ADCCR_SAMPLERATE_22; + break; + case 0x3E80: + rec_ptr->adcctl = ADCCR_SAMPLERATE_16; + break; + case 0x2B11: + rec_ptr->adcctl = ADCCR_SAMPLERATE_11; + break; + case 0x1F40: + rec_ptr->adcctl = ADCCR_SAMPLERATE_8; + break; + default: + break; + } + + rec_ptr->adcctl |= ADCCR_LCHANENABLE; + + if (rec_ptr->is_stereo) + rec_ptr->adcctl |= ADCCR_RCHANENABLE; + + // rec_ptr->fxwc = 0; + + break; + + case WAVERECORD_MIC: + DPF(2, "recording source: MIC\n"); + rec_ptr->bufsizereg = MICBS; + rec_ptr->bufaddrreg = MICBA; + rec_ptr->bufidxreg = MICIDX_IDX; + rec_ptr->adcctl = 0; + // rec_ptr->fxwc = 0; + break; + + case WAVERECORD_FX: + DPF(2, "recording source: FX\n"); + rec_ptr->bufsizereg = FXBS; + rec_ptr->bufaddrreg = FXBA; + rec_ptr->bufidxreg = FXIDX_IDX; + rec_ptr->adcctl = 0; + // rec_ptr->fxwc = 0x000ffff; + break; + default: + break; + } + + return; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/recmgr.h linux/drivers/sound/emu10k1/recmgr.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/recmgr.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/recmgr.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,62 @@ +/* + ********************************************************************** + * recmgr.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _RECORDMGR_H +#define _RECORDMGR_H + +struct record +{ + struct emu10k1_card *card; + u8 *recbuffer; + u32 recpos; + int is_stereo; + int is_16bit; + u32 recbufsize; + u32 bufsize; + u32 bufsizereg; + u32 bufaddrreg; + u32 bufidxreg; + u32 adcctl; + unsigned long busaddx; + u32 samplingrate; +}; + +/* Recording resources */ +#define WAVERECORD_AC97 0x01 +#define WAVERECORD_MIC 0x02 +#define WAVERECORD_FX 0x03 + +void emu10k1_start_record(struct record *); +void emu10k1_stop_record(struct record *); +void emu10k1_set_record_src(struct record *, u8); + + +#endif /* _RECORDMGR_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/timer.c linux/drivers/sound/emu10k1/timer.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/timer.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/timer.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,176 @@ + +/* + ********************************************************************** + * timer.c + * Copyright (C) 1999, 2000 Creative Labs, inc. + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +/* 3/6/2000 Improved support for different timer delays Rui Sousa */ + +/* 4/3/2000 Implemented timer list using list.h Rui Sousa */ + +#include "hwaccess.h" + +/* Try to schedule only once per fragment */ + +void emu10k1_timer_irqhandler(struct emu10k1_card *card) +{ + struct emu_timer *t; + struct list_head *entry; + + spin_lock(&card->timer_lock); + + list_for_each(entry, &card->timers) { + t = list_entry(entry, struct emu_timer, list); + + if (t->active) { + t->count++; + if (t->count == t->count_max) { + t->count = 0; + tasklet_hi_schedule(&t->tasklet); + } + } + } + + spin_unlock(&card->timer_lock); + + return; +} + +struct emu_timer *emu10k1_timer_install(struct emu10k1_card *card, void (*func) (unsigned long), unsigned long data, u32 delay) +{ + struct emu_timer *timer; + struct emu_timer *t; + struct list_head *entry; + unsigned long flags; + + if ((timer = (struct emu_timer *) kmalloc(sizeof(struct emu_timer), GFP_KERNEL)) == NULL) + return timer; + + if (delay < 5) + delay = 5; + + timer->delay = delay; + tasklet_init(&timer->tasklet, func, data); + timer->active = 0; + + spin_lock_irqsave(&card->timer_lock, flags); + + timer->count_max = timer->delay / (card->timer_delay < 1024 ? card->timer_delay : 1024); + timer->count = timer->count_max - 1; + + list_add(&timer->list, &card->timers); + + if (card->timer_delay > delay) { + if (card->timer_delay == TIMER_STOPPED) + emu10k1_irq_enable(card, INTE_INTERVALTIMERENB); + + card->timer_delay = delay; + delay = (delay < 1024 ? delay : 1024); + + WRITE_FN0(card, TIMER_RATE, delay); + + list_for_each(entry, &card->timers) { + t = list_entry(entry, struct emu_timer, list); + + t->count_max = t->delay / delay; + /* don't want to think much, just force scheduling + on the next interrupt */ + t->count = t->count_max - 1; + } + + DPD(2, "timer rate --> %u\n", delay); + } + + spin_unlock_irqrestore(&card->timer_lock, flags); + + return timer; +} + +void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer) +{ + struct emu_timer *t; + struct list_head *entry; + u32 delay = TIMER_STOPPED; + unsigned long flags; + + spin_lock_irqsave(&card->timer_lock, flags); + + list_del(&timer->list); + + list_for_each(entry, &card->timers) { + t = list_entry(entry, struct emu_timer, list); + + if (t->delay < delay) + delay = t->delay; + } + + if (card->timer_delay != delay) { + card->timer_delay = delay; + + if (delay == TIMER_STOPPED) + emu10k1_irq_disable(card, INTE_INTERVALTIMERENB); + else { + delay = (delay < 1024 ? delay : 1024); + + WRITE_FN0(card, TIMER_RATE, delay); + + list_for_each(entry, &card->timers) { + t = list_entry(entry, struct emu_timer, list); + + t->count_max = t->delay / delay; + t->count = t->count_max - 1; + } + } + + DPD(2, "timer rate --> %u\n", delay); + } + + spin_unlock_irqrestore(&card->timer_lock, flags); + + tasklet_unlock_wait(&timer->tasklet); + kfree(timer); + + return; +} + +void emu10k1_timer_enable(struct emu10k1_card *card, struct emu_timer *timer) +{ + unsigned long flags; + + spin_lock_irqsave(&card->timer_lock, flags); + timer->active = 1; + spin_unlock_irqrestore(&card->timer_lock, flags); + + return; +} + +void emu10k1_timer_disable(struct emu10k1_card *card, struct emu_timer *timer) +{ + unsigned long flags; + + spin_lock_irqsave(&card->timer_lock, flags); + timer->active = 0; + spin_unlock_irqrestore(&card->timer_lock, flags); + + return; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/timer.h linux/drivers/sound/emu10k1/timer.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/timer.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/timer.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,47 @@ +/* + ********************************************************************** + * timer.h + * Copyright (C) 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + + +#ifndef _TIMER_H +#define _TIMER_H + +struct emu_timer +{ + struct list_head list; + struct tasklet_struct tasklet; + int active; + u32 count; /* current number of interrupts */ + u32 count_max; /* number of interrupts needed to schedule the bh */ + u32 delay; /* timer delay */ +}; + +struct emu_timer *emu10k1_timer_install(struct emu10k1_card *, void (*)(unsigned long), unsigned long, u32); +void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *); +void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *); +void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *); + +#define TIMER_STOPPED 0xffffffff + +#endif /* _TIMER_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/voicemgr.c linux/drivers/sound/emu10k1/voicemgr.c --- v2.3.99-pre5/linux/drivers/sound/emu10k1/voicemgr.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/voicemgr.c Fri Apr 21 16:08:45 2000 @@ -0,0 +1,349 @@ + +/* + ********************************************************************** + * voicemgr.c - Voice manager for emu10k1 driver + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "hwaccess.h" + +struct emu_voice *emu10k1_voice_alloc(struct voice_manager *voicemgr, struct voice_allocdesc *voiceallocdesc) +{ + struct emu10k1_card *card = voicemgr->card; + struct emu_voice *voice_tmp = voicemgr->voice; + struct emu_voice *voice = NULL; + int i; + unsigned long flags; + + DPF(2, "emu10k1_voice_alloc()\n"); + + spin_lock_irqsave(&voicemgr->lock, flags); + + if (voiceallocdesc->flags & VOICEMGR_FLAGS_MONO) { + for (i = 0; i < NUM_G; i++) + if (voice_tmp[i].usage == VOICEMGR_USAGE_FREE) { + voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags; + voice_tmp[i].usage = voiceallocdesc->usage; + voice = &voice_tmp[i]; + break; + } + } else { + for (i = 0; i < NUM_G; i += 2) + if ((voice_tmp[i].usage == VOICEMGR_USAGE_FREE) + && (voice_tmp[i + 1].usage == VOICEMGR_USAGE_FREE)) { + voice_tmp[i].linked_voice = &voice_tmp[i + 1]; + voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags; + voice_tmp[i].usage = voiceallocdesc->usage; + voice_tmp[i + 1].flags = VOICEMGR_FLAGS_STEREOSLAVE | voiceallocdesc->flags; + voice_tmp[i + 1].usage = voiceallocdesc->usage; + voice = &voice_tmp[i]; + break; + } + } + + spin_unlock_irqrestore(&voicemgr->lock, flags); + + voice_tmp = voice; + + while (voice_tmp != NULL) { + + DPD(2, " voice allocated -> %d\n", voice_tmp->num); + + sblive_writeptr(card, IFATN, voice_tmp->num, 0xffff); + sblive_writeptr(card, DCYSUSV, voice_tmp->num, ENV_OFF); + sblive_writeptr(card, VTFT, voice_tmp->num, 0xffff); + sblive_writeptr(card, PTRX, voice_tmp->num, 0); + + voice_tmp = voice_tmp->linked_voice; + } + + return voice; +} + +void emu10k1_voice_free(struct voice_manager *voicemgr, struct emu_voice *voice) +{ + struct emu10k1_card *card = voice->card; + struct emu_voice *voice_tmp; + unsigned dcysusv; + u32 cra, sample; + int i; + unsigned long flags; + + DPF(2, "emu10k1_voice_free()\n"); + + voice_tmp = voice; + + while (voice_tmp != NULL) { + + DPD(2, " voice freed -> %d\n", voice_tmp->num); + + sblive_writeptr(card, IFATN, voice_tmp->num, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK); + sblive_writeptr(card, IP, voice_tmp->num, 0); + + dcysusv = sblive_readptr(card, DCYSUSV, voice_tmp->num) & (DCYSUSV_PHASE1_MASK | DCYSUSV_SUSTAINLEVEL_MASK | DCYSUSV_DECAYTIME_MASK); + sblive_writeptr(card, DCYSUSV, voice_tmp->num, dcysusv | ENV_OFF); + + sblive_writeptr(card, VTFT, voice_tmp->num, VTFT_FILTERTARGET_MASK); + sblive_writeptr(card, PTRX_PITCHTARGET, voice_tmp->num, 0); + sblive_writeptr(card, CVCF, voice_tmp->num, CVCF_CURRENTFILTER_MASK); + sblive_writeptr(card, CPF, voice_tmp->num, 0); + + sample = (voice_tmp->flags & VOICEMGR_FLAGS_16BIT) ? 0 : 0x80808080; + cra = sblive_readptr(card, CCR, voice_tmp->num) & CCR_READADDRESS_MASK; + sblive_writeptr(card, CCR, voice_tmp->num, cra); + cra = (cra >> 18) & 0xf; + sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample); + cra = (cra + 0x1) & 0xf; + sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample); + + for (i = 0; i < NUM_FXSENDS; i++) + voice_tmp->sendhandle[i] = 0; + + voice_tmp->flags = 0; + + spin_lock_irqsave(&voicemgr->lock, flags); + voice_tmp->usage = VOICEMGR_USAGE_FREE; + + voice_tmp = voice_tmp->linked_voice; + voice->linked_voice = NULL; + spin_unlock_irqrestore(&voicemgr->lock, flags); + } + + return; +} + +/* Sets up a voices for Wave Playback */ + +void emu10k1_voice_playback_setup(struct emu_voice *voice) +{ + struct emu10k1_card *card = voice->card; + u32 sample, cra = 0, start = 0; + + DPF(2, "emu10k1_voice_playback_setup()\n"); + + while (voice != NULL) { + sblive_writeptr(card, DCYSUSV, voice->num, ENV_OFF); + sblive_writeptr(card, VTFT, voice->num, VTFT_FILTERTARGET_MASK); + sblive_writeptr(card, CVCF, voice->num, CVCF_CURRENTFILTER_MASK); + sblive_writeptr(card, FXRT, voice->num, (voice->flags & VOICEMGR_FLAGS_FXRT2) ? 0xd23c0000 : 0xd01c0000); + + /* Stop CA */ + /* Assumption that PT is alreadt 0 so no harm overwriting */ + sblive_writeptr(card, PTRX, voice->num, (voice->params.send_a << 8) | voice->params.send_b); + + if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) { + if (voice->linked_voice != NULL) { + /* Set stereo bit */ + cra = 64; + sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK); + sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK); + } else { + cra = 32; + sblive_writeptr(card, CPF, voice->num, 0); + } + + if (voice->flags & VOICEMGR_FLAGS_16BIT) + sample = 0; + else { + cra = cra * 2; + sample = 0x80808080; + } + cra -= 4; + + if (voice->linked_voice != NULL) { + /* CCR_READADDRESS_MASK */ + sblive_writeptr(card, CCR, voice->num, 0x3c << 16); + sblive_writeptr(card, CCR, voice->num + 1, cra << 16); + sblive_writeptr(card, CDE, voice->num + 1, sample); + sblive_writeptr(card, CDF, voice->num + 1, sample); + start = voice->params.start + cra / 2; + } else { + sblive_writeptr(card, CCR, voice->num, 0x1c << 16); /* FIXME: Is 0x1c correct? */ + sblive_writeptr(card, CDE, voice->num, sample); + sblive_writeptr(card, CDF, voice->num, sample); + start = voice->params.start + cra; + } + + if (start > voice->params.endloop) { + start -= voice->params.endloop; + + if (voice->linked_voice != NULL) + cra = (cra << 25) | 0x1bc0000 | ((cra - start) << 9); + else + cra = (cra << 25) | 0x11c0000 | ((cra - start) << 9); + + start += voice->params.startloop; + + if (start >= voice->params.endloop) + start = voice->params.endloop - 1; + } else if (voice->linked_voice != NULL) + cra = (cra << 25) | (0x3c << 16); + else + cra = (cra << 25) | (0x1c << 16); + + start |= CCCA_INTERPROM_0; + } + + /* CSL, ST, CA */ + sblive_writeptr(card, DSL, voice->num, voice->params.endloop | (voice->params.send_d << 24)); + sblive_writeptr(card, PSST, voice->num, voice->params.startloop | (voice->params.send_c << 24)); + + if (voice->flags & VOICEMGR_FLAGS_16BIT) + sblive_writeptr(card, CCCA, voice->num, start); + else + sblive_writeptr(card, CCCA, voice->num, start | CCCA_8BITSELECT); + + /* Clear filter delay memory */ + sblive_writeptr(card, Z1, voice->num, 0); + sblive_writeptr(card, Z2, voice->num, 0); + + /* Invalidate maps */ + sblive_writeptr(card, MAPA, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + sblive_writeptr(card, MAPB, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + + /* Fill cache */ + if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) + sblive_writeptr(card, CCR, voice->num, cra); + + sblive_writeptr(card, ATKHLDV, voice->num, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK); + sblive_writeptr(card, LFOVAL1, voice->num, 0x8000); + sblive_writeptr(card, ATKHLDM, voice->num, 0); + sblive_writeptr(card, DCYSUSM, voice->num, DCYSUSM_DECAYTIME_MASK); + sblive_writeptr(card, LFOVAL2, voice->num, 0x8000); + sblive_writeptr(card, IP, voice->num, voice->params.initial_pitch); + sblive_writeptr(card, PEFE, voice->num, 0x7f); + sblive_writeptr(card, FMMOD, voice->num, 0); + sblive_writeptr(card, TREMFRQ, voice->num, 0); + sblive_writeptr(card, FM2FRQ2, voice->num, 0); + sblive_writeptr(card, ENVVAL, voice->num, 0xbfff); + sblive_writeptr(card, ENVVOL, voice->num, 0xbfff); + +#ifdef PRIVATE_PCM_VOLUME + { + int i; + + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].channel_l == voice->num) { + voice->params.initial_attn = (sblive_pcm_volume[i].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l : + // test for mono channel (reverse logic is correct here!) + (sblive_pcm_volume[i].attn_r > + sblive_pcm_volume[i].attn_l) ? sblive_pcm_volume[i].attn_l : sblive_pcm_volume[i].attn_r; + DPD(2, "set left volume %d\n", voice->params.initial_attn); + break; + } else if (sblive_pcm_volume[i].channel_r == voice->num) { + voice->params.initial_attn = sblive_pcm_volume[i].attn_r; + DPD(2, "set right volume %d\n", voice->params.initial_attn); + break; + } + } + } +#endif + sblive_writeptr(card, IFATN, voice->num, IFATN_FILTERCUTOFF_MASK | voice->params.initial_attn); + + voice->params.FC_target = 0xffff; + voice->params.pitch_target = (u16) (IP_TO_CP(voice->params.initial_pitch) >> 16); + + voice = voice->linked_voice; + } + + return; +} + +void emu10k1_voice_start(struct emu_voice *voice) +{ + struct emu10k1_card *card = voice->card; + + DPF(2, "emu10k1_voice_start()\n"); + + while (voice != NULL) { + sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, voice->params.pitch_target); + + if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) + sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->params.pitch_target); + + sblive_writeptr(card, VTFT, voice->num, ((u32) voice->params.volume_target << 16) + | voice->params.FC_target); + sblive_writeptr(card, CVCF, voice->num, ((u32) voice->params.volume_target << 16) + | voice->params.FC_target); + sblive_writeptr(card, DCYSUSV, voice->num, (voice->params.byampl_env_sustain << 8) + | ENV_ON | voice->params.byampl_env_decay); + + /* Using StopOnLoop for MIDI stops the playback + too early, which may cause a DC level to be played + until the note is released. */ + + if (voice->usage == VOICEMGR_USAGE_MIDI) + emu10k1_clear_stop_on_loop(card, voice->num); + else { + if (voice->params.startloop > voice->params.end) + emu10k1_set_stop_on_loop(card, voice->num); + else + emu10k1_clear_stop_on_loop(card, voice->num); + } + voice = voice->linked_voice; + } + + return; +} + +void emu10k1_voice_stop(struct emu_voice *voice) +{ + struct emu10k1_card *card = voice->card; + + DPF(2, "emu10k1_voice_stop()\n"); + + while (voice != NULL) { + sblive_writeptr(card, IFATN, voice->num, 0xffff); + sblive_writeptr(card, IP, voice->num, 0); + sblive_writeptr(card, VTFT, voice->num, 0xffff); + sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, 0); + voice = voice->linked_voice; + } + + return; +} + +void emu10k1_voice_setcontrol(struct emu_voice *voice, struct voice_cntlset *setting, u32 numparam) +{ + struct emu10k1_card *card = voice->card; + int count; + + for (count = 0; count < numparam; count++) + sblive_writeptr(card, setting[count].paramID, voice->num, setting[count].value); + + return; +} + +void emu10k1_voice_getcontrol(struct emu_voice *voice, u32 controlid, u32 * value) +{ + struct emu10k1_card *card = voice->card; + + *value = sblive_readptr(card, controlid, voice->num); + + return; +} diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/emu10k1/voicemgr.h linux/drivers/sound/emu10k1/voicemgr.h --- v2.3.99-pre5/linux/drivers/sound/emu10k1/voicemgr.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/voicemgr.h Fri Apr 21 16:08:45 2000 @@ -0,0 +1,150 @@ +/* + ********************************************************************** + * sblive_voice.h -- EMU Voice Resource Manager header file + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _VOICEMGR_H +#define _VOICEMGR_H +/* struct emu_voice.usage flags */ +#define VOICEMGR_USAGE_FREE 0x00000000 +#define VOICEMGR_USAGE_MIDI 0x00000001 +#define VOICEMGR_USAGE_PLAYBACK 0x00000002 + +/* struct emu_voice.flags flags */ +#define VOICEMGR_FLAGS_MONO 0x00000002 +#define VOICEMGR_FLAGS_16BIT 0x00000004 +#define VOICEMGR_FLAGS_STEREOSLAVE 0x00000008 +#define VOICEMGR_FLAGS_VOICEMASTER 0x80000000 +#define VOICEMGR_FLAGS_FXRT2 0x00000010 + +struct voice_param +{ + /* Sound engine */ + u32 start; + u32 startloop; + u32 endloop; + u32 end; + + u16 current_pitch; + u16 pitch_target; + + u16 current_volume; + u16 volume_target; + + u16 current_FC; + u16 FC_target; + + u8 pan_target; + u8 aux_target; + + /* FX bus amount send */ + + u32 send_a; + u32 send_b; + u32 send_c; + u32 send_d; + + /* Envelope engine */ + u16 ampl_env_delay; + u8 byampl_env_attack; + u8 byampl_env_hold; + u8 byampl_env_decay; + u8 byampl_env_sustain; + u8 byampl_env_release; + + u16 aux_env_delay; + u8 byaux_env_attack; + u8 byaux_env_hold; + u8 byaux_env_decay; + u8 byaux_env_sustain; + u8 byaux_env_release; + + u16 mod_LFO_delay; /* LFO1 */ + u16 vib_LFO_delay; /* LFO2 */ + u8 mod_LFO_freq; /* LFO1 */ + u8 vib_LFO_freq; /* LFO2 */ + + s8 aux_env_to_pitch; + s8 aux_env_to_FC; + s8 mod_LFO_to_pitch; + s8 vib_LFO_to_pitch; + s8 mod_LFO_to_FC; + s8 mod_LFO_to_volume; + + u16 sample_pitch; + u16 initial_pitch; + u8 initial_attn; + u8 initial_FC; +}; + +struct voice_allocdesc +{ + u32 usage; /* playback, Midi */ + u32 flags; /* stereo/mono rec/playback 8/16 bit*/ +}; + +struct emu_voice +{ + struct list_head list; + + struct emu10k1_card *card; + u32 usage; /* Free, MIDI, playback */ + u32 num; /* Voice ID */ + u32 flags; /* Stereo/mono, rec/playback, 8/16 bit */ + + struct voice_param params; + + struct emu_voice *linked_voice; /*for stereo voice*/ + + u32 sendhandle[NUM_FXSENDS]; +}; + +struct voice_manager +{ + struct emu10k1_card *card; + spinlock_t lock; + + struct emu_voice voice[NUM_G]; +}; + +struct voice_cntlset +{ + u32 paramID; + u32 value; +}; + +struct emu_voice *emu10k1_voice_alloc(struct voice_manager *, struct voice_allocdesc *); +void emu10k1_voice_free(struct voice_manager *, struct emu_voice *); +void emu10k1_voice_playback_setup(struct emu_voice *); +void emu10k1_voice_start(struct emu_voice *); +void emu10k1_voice_stop(struct emu_voice *); +void emu10k1_voice_setcontrol(struct emu_voice *, struct voice_cntlset *, u32); +void emu10k1_voice_getcontrol(struct emu_voice *, u32, u32 *); + +#endif /* _VOICEMGR_H */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.3.99-pre5/linux/drivers/sound/es1370.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/sound/es1370.c Fri Apr 21 13:26:35 2000 @@ -1268,6 +1268,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int es1370_poll(struct file *file, struct poll_table_struct *wait) { struct es1370_state *s = (struct es1370_state *)file->private_data; @@ -1820,6 +1821,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int es1370_poll_dac(struct file *file, struct poll_table_struct *wait) { struct es1370_state *s = (struct es1370_state *)file->private_data; @@ -2276,6 +2278,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int es1370_midi_poll(struct file *file, struct poll_table_struct *wait) { struct es1370_state *s = (struct es1370_state *)file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.3.99-pre5/linux/drivers/sound/es1371.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/es1371.c Fri Apr 21 13:26:09 2000 @@ -1402,6 +1402,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int es1371_poll(struct file *file, struct poll_table_struct *wait) { struct es1371_state *s = (struct es1371_state *)file->private_data; @@ -1951,6 +1952,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int es1371_poll_dac(struct file *file, struct poll_table_struct *wait) { struct es1371_state *s = (struct es1371_state *)file->private_data; @@ -2397,6 +2399,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int es1371_midi_poll(struct file *file, struct poll_table_struct *wait) { struct es1371_state *s = (struct es1371_state *)file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.3.99-pre5/linux/drivers/sound/esssolo1.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/sound/esssolo1.c Fri Apr 21 13:27:03 2000 @@ -1149,6 +1149,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait) { struct solo1_state *s = (struct solo1_state *)file->private_data; @@ -1783,6 +1784,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int solo1_midi_poll(struct file *file, struct poll_table_struct *wait) { struct solo1_state *s = (struct solo1_state *)file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c --- v2.3.99-pre5/linux/drivers/sound/i810_audio.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/i810_audio.c Mon Apr 24 13:39:34 2000 @@ -0,0 +1,1860 @@ +/* + * Intel i810 and friends ICH driver for Linux + * Alan Cox + * + * Built from: + * Low level code: Zach Brown (original nonworking i810 OSS driver) + * Jaroslav Kysela (working ALSA driver) + * + * Framework: Thomas Sailer + * Extended by: Zach Brown + * and others.. + * + * Hardware Provided By: + * Analog Devices (A major AC97 codec maker) + * Intel Corp (you've probably heard of them already) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Intel 810 theory of operation + * + * The chipset provides three DMA channels that talk to an AC97 + * CODEC (AC97 is a digital/analog mixer standard). At its simplest + * you get 48Khz audio with basic volume and mixer controls. At the + * best you get rate adaption in the codec. We set the card up so + * that we never take completion interrupts but instead keep the card + * chasing its tail around a ring buffer. This is needed for mmap + * mode audio and happens to work rather well for non-mmap modes too. + * + * The board has one output channel for PCM audio (supported) and + * a stereo line in and mono microphone input. Again these are normally + * locked to 48Khz only. Right now recording is not finished. + * + * There is no midi support, no synth support. Use timidity. To get + * esd working you need to use esd -r 48000 as it won't probe 48KHz + * by default. mpg123 can't handle 48Khz only audio so use xmms. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PCI_DEVICE_ID_INTEL_82801 +#define PCI_DEVICE_ID_INTEL_82801 0x2415 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82901 +#define PCI_DEVICE_ID_INTEL_82901 0x2425 +#endif +#ifndef PCI_DEVICE_ID_INTEL_440MX +#define PCI_DEVICE_ID_INTEL_440MX 0x7195 +#endif + +#define ADC_RUNNING 1 +#define DAC_RUNNING 2 + +#define I810_FMT_16BIT 1 +#define I810_FMT_STEREO 2 +#define I810_FMT_MASK 3 + +/* the 810's array of pointers to data buffers */ + +struct sg_item { +#define BUSADDR_MASK 0xFFFFFFFE + u32 busaddr; +#define CON_IOC 0x80000000 /* interrupt on completion */ +#define CON_BUFPAD 0x40000000 /* pad underrun with last sample, else 0 */ +#define CON_BUFLEN_MASK 0x0000ffff /* buffer length in samples */ + u32 control; +}; + +/* an instance of the i810 channel */ +#define SG_LEN 32 +struct i810_channel +{ + /* these sg guys should probably be allocated + seperately as nocache. Must be 8 byte aligned */ + struct sg_item sg[SG_LEN]; /* 32*8 */ + u32 offset; /* 4 */ + u32 port; /* 4 */ + u32 used; + u32 num; +}; + +/* + * we have 3 seperate dma engines. pcm in, pcm out, and mic. + * each dma engine has controlling registers. These goofy + * names are from the datasheet, but make it easy to write + * code while leafing through it. + */ + +#define ENUM_ENGINE(PRE,DIG) \ +enum { \ + ##PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \ + ##PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \ + ##PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \ + ##PRE##_SR = 0x##DIG##6, /* Status Register */ \ + ##PRE##_PICB = 0x##DIG##8, /* Position In Current Buffer */ \ + ##PRE##_PIV = 0x##DIG##a, /* Prefetched Index Value */ \ + ##PRE##_CR = 0x##DIG##b /* Control Register */ \ +} + +ENUM_ENGINE(OFF,0); /* Offsets */ +ENUM_ENGINE(PI,0); /* PCM In */ +ENUM_ENGINE(PO,1); /* PCM Out */ +ENUM_ENGINE(MC,2); /* Mic In */ + +enum { + GLOB_CNT = 0x2c, /* Global Control */ + GLOB_STA = 0x30, /* Global Status */ + CAS = 0x34 /* Codec Write Semaphore Register */ +}; + +/* interrupts for a dma engine */ +#define DMA_INT_FIFO (1<<4) /* fifo under/over flow */ +#define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */ +#define DMA_INT_LVI (1<<2) /* last valid done */ +#define DMA_INT_CELV (1<<1) /* last valid is current */ +#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI) + +/* interrupts for the whole chip */ +#define INT_SEC (1<<11) +#define INT_PRI (1<<10) +#define INT_MC (1<<7) +#define INT_PO (1<<6) +#define INT_PI (1<<5) +#define INT_MO (1<<2) +#define INT_NI (1<<1) +#define INT_GPI (1<<0) +#define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI) + + +#define DRIVER_VERSION "0.01" + +/* magic numbers to protect our data structures */ +#define I810_CARD_MAGIC 0x5072696E /* "Prin" */ +#define I810_STATE_MAGIC 0x63657373 /* "cess" */ +#define I810_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */ +#define NR_HW_CH 3 + +/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ +#define NR_AC97 2 + +/* minor number of /dev/dspW */ +#define SND_DEV_DSP8 1 + +/* minor number of /dev/dspW */ +#define SND_DEV_DSP16 1 + +static const unsigned sample_size[] = { 1, 2, 2, 4 }; +static const unsigned sample_shift[] = { 0, 1, 1, 2 }; + +enum { + ICH82801AA = 0, + ICH82901AB, + INTEL440MX +}; + +static char * card_names[] = { + "Intel ICH 82801AA", + "Intel ICH 82901AB", + "Intel 440MX" +}; + +static struct pci_device_id i810_pci_tbl [] __initdata = { + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82901, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82901AB}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_440MX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX}, + {0,} +}; + +MODULE_DEVICE_TABLE (pci, i810_pci_tbl); + +/* "software" or virtual channel, an instance of opened /dev/dsp */ +struct i810_state { + unsigned int magic; + struct i810_card *card; /* Card info */ + + /* single open lock mechanism, only used for recording */ + struct semaphore open_sem; + wait_queue_head_t open_wait; + + /* file mode */ + mode_t open_mode; + + /* virtual channel number */ + int virt; + + struct dmabuf { + /* wave sample stuff */ + unsigned int rate; + unsigned char fmt, enable; + + /* hardware channel */ + struct i810_channel *channel; + + /* OSS buffer management stuff */ + void *rawbuf; + dma_addr_t dma_handle; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + + /* our buffer acts like a circular ring */ + unsigned hwptr; /* where dma last started, updated by update_ptr */ + unsigned swptr; /* where driver last clear/filled, updated by read/write */ + int count; /* bytes to be comsumed or been generated by dma machine */ + unsigned total_bytes; /* total bytes dmaed by hardware */ + + unsigned error; /* number of over/underruns */ + wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */ + + /* redundant, but makes calculations easier */ + unsigned fragsize; + unsigned dmasize; + unsigned fragsamples; + + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned endcleared:1; + unsigned update_flag; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + } dmabuf; +}; + + +struct i810_card { + struct i810_channel channel[3]; + unsigned int magic; + + /* We keep i810 cards in a linked list */ + struct i810_card *next; + + /* The i810 has a certain amount of cross channel interaction + so we use a single per card lock */ + spinlock_t lock; + + /* PCI device stuff */ + struct pci_dev * pci_dev; + u16 pci_id; + + /* soundcore stuff */ + int dev_audio; + + /* structures for abstraction of hardware facilities, codecs, banks and channels*/ + struct ac97_codec *ac97_codec[NR_AC97]; + struct i810_state *states[NR_HW_CH]; + + u16 ac97_features; + + /* hardware resources */ + unsigned long iobase; + unsigned long ac97base; + u32 irq; + + /* Function support */ + struct i810_channel *(*alloc_pcm_channel)(struct i810_card *); + struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *); + void (*free_pcm_channel)(struct i810_card *, int chan); +}; + +static struct i810_card *devs = NULL; + +static int i810_open_mixdev(struct inode *inode, struct file *file); +static int i810_release_mixdev(struct inode *inode, struct file *file); +static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg); +static loff_t i810_llseek(struct file *file, loff_t offset, int origin); + +extern __inline__ unsigned ld2(unsigned int x) +{ + unsigned r = 0; + + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; +} + +static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg); +static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data); + +static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card) +{ + if(card->channel[1].used==1) + return NULL; + card->channel[1].used=1; + card->channel[1].offset = 0; + card->channel[1].port = 0x10; + card->channel[1].num=1; + return &card->channel[1]; +} + +static struct i810_channel *i810_alloc_rec_pcm_channel(struct i810_card *card) +{ + if(card->channel[0].used==1) + return NULL; + card->channel[0].used=1; + card->channel[0].offset = 0; + card->channel[0].port = 0x00; + card->channel[1].num=0; + return &card->channel[0]; +} + +static void i810_free_pcm_channel(struct i810_card *card, int channel) +{ + card->channel[channel].used=0; +} + +/* set playback sample rate */ +static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate) +{ + struct dmabuf *dmabuf = &state->dmabuf; + u16 dacp, rp; + struct ac97_codec *codec=state->card->ac97_codec[0]; + + if(!(state->card->ac97_features&0x0001)) + return 48000; + + if (rate > 48000) + rate = 48000; + if (rate < 4000) + rate = 4000; + + /* Power down the DAC */ + dacp=i810_ac97_get(codec, AC97_POWER_CONTROL); + i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0200); + + /* Load the rate and read the effective rate */ + i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate); + rp=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE); + + printk("DAC rate set to %d Returned %d\n", + rate, (int)rp); + + rate=rp; + + /* Power it back up */ + i810_ac97_set(codec, AC97_POWER_CONTROL, dacp); + + dmabuf->rate = rate; +#ifdef DEBUG + printk("i810_audio: called i810_set_dac_rate : rate = %d\n", rate); +#endif + + return rate; +} + +/* set recording sample rate */ +static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate) +{ + struct dmabuf *dmabuf = &state->dmabuf; + u16 dacp, rp; + struct ac97_codec *codec=state->card->ac97_codec[0]; + + if(!(state->card->ac97_features&0x0001)) + return 48000; + + if (rate > 48000) + rate = 48000; + if (rate < 4000) + rate = 4000; + + /* Power down the ADC */ + dacp=i810_ac97_get(codec, AC97_POWER_CONTROL); + i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100); + + /* Load the rate and read the effective rate */ + i810_ac97_set(codec, AC97_PCM_LR_ADC_RATE, rate); + rp=i810_ac97_get(codec, AC97_PCM_LR_ADC_RATE); + + printk("ADC rate set to %d Returned %d\n", + rate, (int)rp); + + rate=rp; + + /* Power it back up */ + i810_ac97_set(codec, AC97_POWER_CONTROL, dacp); + + dmabuf->rate = rate; +#ifdef DEBUG + printk("i810_audio: called i810_set_adc_rate : rate = %d\n", rate); +#endif + + return rate; + +} + +/* prepare channel attributes for playback */ +static void i810_play_setup(struct i810_state *state) +{ +// struct dmabuf *dmabuf = &state->dmabuf; +// struct i810_channel *channel = dmabuf->channel; + /* Fixed format. .. */ + //if (dmabuf->fmt & I810_FMT_16BIT) + //if (dmabuf->fmt & I810_FMT_STEREO) +} + +/* prepare channel attributes for recording */ +static void i810_rec_setup(struct i810_state *state) +{ +// u16 w; +// struct i810_card *card = state->card; +// struct dmabuf *dmabuf = &state->dmabuf; +// struct i810_channel *channel = dmabuf->channel; + + /* Enable AC-97 ADC (capture) */ +// if (dmabuf->fmt & I810_FMT_16BIT) { +// if (dmabuf->fmt & I810_FMT_STEREO) +} + + +/* get current playback/recording dma buffer pointer (byte offset from LBA), + called with spinlock held! */ + +extern __inline__ unsigned i810_get_dma_addr(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + u32 offset; + struct i810_channel *c = dmabuf->channel; + + if (!dmabuf->enable) + return 0; + offset = inb(state->card->iobase+c->port+OFF_CIV); + offset++; + offset&=31; + /* Offset has to compensate for the fact we finished the segment + on the IRQ so we are at next_segment,0 */ +// printk("BANK%d ", offset); + offset *= (dmabuf->dmasize/SG_LEN); +// printk("DMASZ=%d", dmabuf->dmasize); +// offset += 1024-(4*inw(state->card->iobase+c->port+OFF_PICB)); +// printk("OFF%d ", offset); + return offset; +} + +static void resync_dma_ptrs(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct i810_channel *c = dmabuf->channel; + int offset; + + offset = inb(state->card->iobase+c->port+OFF_CIV); + offset *= (dmabuf->dmasize/SG_LEN); + + dmabuf->hwptr=dmabuf->swptr = offset; +} + +/* Stop recording (lock held) */ +extern __inline__ void __stop_adc(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct i810_card *card = state->card; + + dmabuf->enable &= ~ADC_RUNNING; + outb(0, card->iobase + PI_CR); +} + +static void stop_adc(struct i810_state *state) +{ + struct i810_card *card = state->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + __stop_adc(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +static void start_adc(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct i810_card *card = state->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) { + dmabuf->enable |= ADC_RUNNING; + outb((1<<4) | 1<<2 | 1, card->iobase + PI_CR); + } + spin_unlock_irqrestore(&card->lock, flags); +} + +/* stop playback (lock held) */ +extern __inline__ void __stop_dac(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct i810_card *card = state->card; + + dmabuf->enable &= ~DAC_RUNNING; + outb(0, card->iobase + PO_CR); +} + +static void stop_dac(struct i810_state *state) +{ + struct i810_card *card = state->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + __stop_dac(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +static void start_dac(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct i810_card *card = state->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) { + if(!(dmabuf->enable&DAC_RUNNING)) + { + dmabuf->enable |= DAC_RUNNING; + outb((1<<4) | 1<<2 | 1, card->iobase + PO_CR); + } + } + spin_unlock_irqrestore(&card->lock, flags); +} + +#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) +#define DMABUF_MINORDER 1 + +/* allocate DMA buffer, playback and recording buffer should be allocated seperately */ +static int alloc_dmabuf(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + void *rawbuf; + int order; + unsigned long map, mapend; + + /* alloc as big a chunk as we can, FIXME: is this necessary ?? */ + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) + if ((rawbuf = pci_alloc_consistent(state->card->pci_dev, + PAGE_SIZE << order, + &dmabuf->dma_handle))) + break; + if (!rawbuf) + return -ENOMEM; + +#ifdef DEBUG + printk("i810_audio: allocated %ld (order = %d) bytes at %p\n", + PAGE_SIZE << order, order, rawbuf); +#endif + + dmabuf->ready = dmabuf->mapped = 0; + dmabuf->rawbuf = rawbuf; + dmabuf->buforder = order; + + /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ + mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1); + for (map = MAP_NR(rawbuf); map <= mapend; map++) + set_bit(PG_reserved, &mem_map[map].flags); + + return 0; +} + +/* free DMA buffer */ +static void dealloc_dmabuf(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long map, mapend; + + if (dmabuf->rawbuf) { + /* undo marking the pages as reserved */ + mapend = MAP_NR(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); + for (map = MAP_NR(dmabuf->rawbuf); map <= mapend; map++) + clear_bit(PG_reserved, &mem_map[map].flags); + pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder, + dmabuf->rawbuf, dmabuf->dma_handle); + } + dmabuf->rawbuf = NULL; + dmabuf->mapped = dmabuf->ready = 0; +} + +static int prog_dmabuf(struct i810_state *state, unsigned rec) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct sg_item *sg; + unsigned bytepersec; + unsigned bufsize; + unsigned long flags; + int ret; + unsigned fragsize; + int i; + + spin_lock_irqsave(&state->card->lock, flags); + resync_dma_ptrs(state); + dmabuf->total_bytes = 0; + dmabuf->count = dmabuf->error = 0; + spin_unlock_irqrestore(&state->card->lock, flags); + + /* allocate DMA buffer if not allocated yet */ + if (!dmabuf->rawbuf) + if ((ret = alloc_dmabuf(state))) + return ret; + + /* FIXME: figure out all this OSS fragment stuff */ + bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt]; + bufsize = PAGE_SIZE << dmabuf->buforder; + if (dmabuf->ossfragshift) { + if ((1000 << dmabuf->ossfragshift) < bytepersec) + dmabuf->fragshift = ld2(bytepersec/1000); + else + dmabuf->fragshift = dmabuf->ossfragshift; + } else { + /* lets hand out reasonable big ass buffers by default */ + dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); + } + dmabuf->numfrag = bufsize >> dmabuf->fragshift; + while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) { + dmabuf->fragshift--; + dmabuf->numfrag = bufsize >> dmabuf->fragshift; + } + dmabuf->fragsize = 1 << dmabuf->fragshift; + if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag) + dmabuf->numfrag = dmabuf->ossmaxfrags; + dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt]; + dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; + + memset(dmabuf->rawbuf, (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80, + dmabuf->dmasize); + + /* + * Now set up the ring + */ + + sg=&dmabuf->channel->sg[0]; + fragsize = bufsize / SG_LEN; + + /* + * Load up 32 sg entries and take an interrupt at half + * way (we might want more interrupts later..) + */ + + for(i=0;i<32;i++) + { + sg->busaddr=virt_to_bus(dmabuf->rawbuf+fragsize*i); + sg->control=(fragsize>>1); + sg->control|=CON_IOC; + sg++; + } + spin_lock_irqsave(&state->card->lock, flags); + outl(virt_to_bus(&dmabuf->channel->sg[0]), state->card->iobase+dmabuf->channel->port+OFF_BDBAR); + outb(16, state->card->iobase+dmabuf->channel->port+OFF_LVI); + outb(0, state->card->iobase+dmabuf->channel->port+OFF_CIV); + if (rec) { + i810_rec_setup(state); + } else { + i810_play_setup(state); + } + spin_unlock_irqrestore(&state->card->lock, flags); + + /* set the ready flag for the dma buffer */ + dmabuf->ready = 1; + +#ifdef DEBUG + printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, " + "fragsize = %d dmasize = %d\n", + dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, + dmabuf->fragsize, dmabuf->dmasize); +#endif + + return 0; +} + +/* we are doing quantum mechanics here, the buffer can only be empty, half or full filled i.e. + |------------|------------| or |xxxxxxxxxxxx|------------| or |xxxxxxxxxxxx|xxxxxxxxxxxx| + but we almost always get this + |xxxxxx------|------------| or |xxxxxxxxxxxx|xxxxx-------| + so we have to clear the tail space to "silence" + |xxxxxx000000|------------| or |xxxxxxxxxxxx|xxxxxx000000| +*/ +static void i810_clear_tail(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned swptr; + unsigned char silence = (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80; + unsigned int len; + unsigned long flags; + + spin_lock_irqsave(&state->card->lock, flags); + swptr = dmabuf->swptr; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize) + return; + + if (swptr < dmabuf->dmasize/2) + len = dmabuf->dmasize/2 - swptr; + else + len = dmabuf->dmasize - swptr; + + memset(dmabuf->rawbuf + swptr, silence, len); + + spin_lock_irqsave(&state->card->lock, flags); + dmabuf->swptr += len; + dmabuf->count += len; + spin_unlock_irqrestore(&state->card->lock, flags); + + /* restart the dma machine in case it is halted */ + start_dac(state); +} + +static int drain_dac(struct i810_state *state, int nonblock) +{ + DECLARE_WAITQUEUE(wait, current); + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + unsigned long tmo; + int count; + + if (dmabuf->mapped || !dmabuf->ready) + return 0; + + add_wait_queue(&dmabuf->wait, &wait); + for (;;) { + /* It seems that we have to set the current state to TASK_INTERRUPTIBLE + every time to make the process really go to sleep */ + current->state = TASK_INTERRUPTIBLE; + + spin_lock_irqsave(&state->card->lock, flags); + count = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (count <= 0) + break; + + if (signal_pending(current)) + break; + + if (nonblock) { + remove_wait_queue(&dmabuf->wait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + + tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; + tmo >>= sample_shift[dmabuf->fmt]; + if (!schedule_timeout(tmo ? tmo : 1) && tmo){ + printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n"); + break; + } + } + remove_wait_queue(&dmabuf->wait, &wait); + current->state = TASK_RUNNING; + if (signal_pending(current)) + return -ERESTARTSYS; + + return 0; +} + +/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ +static void i810_update_ptr(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned hwptr, swptr; + int clear_cnt = 0; + int diff; + unsigned char silence; +// unsigned half_dmasize; + + /* update hardware pointer */ + hwptr = i810_get_dma_addr(state); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; +// printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + + /* error handling and process wake up for DAC */ + if (dmabuf->enable == ADC_RUNNING) { + if (dmabuf->mapped) { + dmabuf->count -= diff; + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + } else { + dmabuf->count += diff; + + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun, we have no way to recover + it here, just stop the machine and let the process force hwptr + and swptr to sync */ + __stop_adc(state); + dmabuf->error++; + } + else if (!dmabuf->endcleared) { + swptr = dmabuf->swptr; + silence = (dmabuf->fmt & I810_FMT_16BIT ? 0 : 0x80); + if (dmabuf->count < (signed) dmabuf->fragsize) + { + clear_cnt = dmabuf->fragsize; + if ((swptr + clear_cnt) > dmabuf->dmasize) + clear_cnt = dmabuf->dmasize - swptr; + memset (dmabuf->rawbuf + swptr, silence, clear_cnt); + dmabuf->endcleared = 1; + } + } + wake_up(&dmabuf->wait); + } + } + /* error handling and process wake up for DAC */ + if (dmabuf->enable == DAC_RUNNING) { + if (dmabuf->mapped) { + dmabuf->count += diff; + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + } else { + dmabuf->count -= diff; + + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun, we have no way to recover + it here, just stop the machine and let the process force hwptr + and swptr to sync */ + __stop_dac(state); + printk("DMA overrun on send\n"); + dmabuf->error++; + } + wake_up(&dmabuf->wait); + } + } +} + +static void i810_channel_interrupt(struct i810_card *card) +{ + int i; + +// printk("CHANNEL IRQ .. "); + for(i=0;istates[i]; + struct i810_channel *c; + unsigned long port = card->iobase; + u16 status; + + if(!state) + continue; + if(!state->dmabuf.ready) + continue; + c=state->dmabuf.channel; + + port+=c->port; + +// printk("PORT %lX (", port); + + status = inw(port + OFF_SR); + +// printk("ST%d ", status); + + if(status & DMA_INT_LVI) + { + /* Back to the start */ +// printk("LVI - STOP"); + outb((inb(port+OFF_CIV)-1)&31, port+OFF_LVI); + i810_update_ptr(state); + outb(0, port + OFF_CR); + } + if(status & DMA_INT_COMPLETE) + { + int x; + /* Keep the card chasing its tail */ + outb(x=((inb(port+OFF_CIV)-1)&31), port+OFF_LVI); + i810_update_ptr(state); +// printk("COMP%d ",x); + } +// printk(")"); + outw(status & DMA_INT_MASK, port + OFF_SR); + } +// printk("\n"); +} + +static void i810_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct i810_card *card = (struct i810_card *)dev_id; + u32 status; + + spin_lock(&card->lock); + + status = inl(card->iobase + GLOB_STA); + if(!(status & INT_MASK)) + return; /* not for us */ + +// printk("Interrupt %X: ", status); + if(status & (INT_PO|INT_PI|INT_MC)) + i810_channel_interrupt(card); + + /* clear 'em */ + outl(status & INT_MASK, card->iobase + GLOB_STA); + spin_unlock(&card->lock); +} + +static loff_t i810_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to + the user's buffer. it is filled by the dma machine and drained by this loop. */ +static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct i810_state *state = (struct i810_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + +#ifdef DEBUG + printk("i810_audio: i810_read called, count = %d\n", count); +#endif + + if (ppos != &file->f_pos) + return -ESPIPE; + if (dmabuf->mapped) + return -ENXIO; + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + + while (count > 0) { + spin_lock_irqsave(&state->card->lock, flags); + if (dmabuf->count > (signed) dmabuf->dmasize) { + /* buffer overrun, we are recovering from sleep_on_timeout, + resync hwptr and swptr, make process flush the buffer */ + dmabuf->count = dmabuf->dmasize; + dmabuf->swptr = dmabuf->hwptr; + } + swptr = dmabuf->swptr; + cnt = dmabuf->dmasize - swptr; + if (dmabuf->count < cnt) + cnt = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (cnt > count) + cnt = count; + if (cnt <= 0) { + unsigned long tmo; + /* buffer is empty, start the dma machine and wait for data to be + recorded */ + start_adc(state); + if (file->f_flags & O_NONBLOCK) { + if (!ret) ret = -EAGAIN; + return ret; + } + /* This isnt strictly right for the 810 but it'll do */ + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); + tmo >>= sample_shift[dmabuf->fmt]; + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer overrun. And worse, there is + NOTHING we can do to prevent it. */ + if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { +#ifdef DEBUG + printk(KERN_ERR "i810_audio: recording schedule timeout, " + "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, + dmabuf->hwptr, dmabuf->swptr); +#endif + /* a buffer overrun, we delay the recovery untill next time the + while loop begin and we REALLY have space to record */ + } + if (signal_pending(current)) { + ret = ret ? ret : -ERESTARTSYS; + return ret; + } + continue; + } + + if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { + if (!ret) ret = -EFAULT; + return ret; + } + + swptr = (swptr + cnt) % dmabuf->dmasize; + + spin_lock_irqsave(&state->card->lock, flags); + dmabuf->swptr = swptr; + dmabuf->count -= cnt; + spin_unlock_irqrestore(&state->card->lock, flags); + + count -= cnt; + buffer += cnt; + ret += cnt; + start_adc(state); + } + return ret; +} + +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to + the soundcard. it is drained by the dma machine and filled by this loop. */ +static ssize_t i810_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct i810_state *state = (struct i810_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + +#ifdef DEBUG + printk("i810_audio: i810_write called, count = %d\n", count); +#endif + + if (ppos != &file->f_pos) + return -ESPIPE; + if (dmabuf->mapped) + return -ENXIO; + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + + while (count > 0) { + spin_lock_irqsave(&state->card->lock, flags); + if (dmabuf->count < 0) { + /* buffer underrun, we are recovering from sleep_on_timeout, + resync hwptr and swptr */ + dmabuf->count = 0; + dmabuf->swptr = dmabuf->hwptr; + } + swptr = dmabuf->swptr; + cnt = dmabuf->dmasize - swptr; + if (dmabuf->count + cnt > dmabuf->dmasize) + cnt = dmabuf->dmasize - dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (cnt > count) + cnt = count; + if (cnt <= 0) { + unsigned long tmo; + /* buffer is full, start the dma machine and wait for data to be + played */ + start_dac(state); + if (file->f_flags & O_NONBLOCK) { + if (!ret) ret = -EAGAIN; + return ret; + } + /* Not strictly correct but works */ + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); + tmo >>= sample_shift[dmabuf->fmt]; + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer underrun. And worse, there is + NOTHING we can do to prevent it. */ + if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { +#ifdef DEBUG + printk(KERN_ERR "i810_audio: playback schedule timeout, " + "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, + dmabuf->hwptr, dmabuf->swptr); +#endif + /* a buffer underrun, we delay the recovery untill next time the + while loop begin and we REALLY have data to play */ + } + if (signal_pending(current)) { + if (!ret) ret = -ERESTARTSYS; + return ret; + } + continue; + } + if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { + if (!ret) ret = -EFAULT; + return ret; + } + + swptr = (swptr + cnt) % dmabuf->dmasize; + + spin_lock_irqsave(&state->card->lock, flags); + dmabuf->swptr = swptr; + dmabuf->count += cnt; + dmabuf->endcleared = 0; + spin_unlock_irqrestore(&state->card->lock, flags); + + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(state); + } + return ret; +} + +/* No kernel lock - we have our own spinlock */ +static unsigned int i810_poll(struct file *file, struct poll_table_struct *wait) +{ + struct i810_state *state = (struct i810_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + unsigned int mask = 0; + + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &dmabuf->wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &dmabuf->wait, wait); + + spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); + if (file->f_mode & FMODE_READ) { + if (dmabuf->count >= (signed)dmabuf->fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (dmabuf->mapped) { + if (dmabuf->count >= (signed)dmabuf->fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&state->card->lock, flags); + + return mask; +} + +static int i810_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct i810_state *state = (struct i810_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + int ret; + unsigned long size; + + if (vma->vm_flags & VM_WRITE) { + if ((ret = prog_dmabuf(state, 0)) != 0) + return ret; + } else if (vma->vm_flags & VM_READ) { + if ((ret = prog_dmabuf(state, 1)) != 0) + return ret; + } else + return -EINVAL; + + if (vma->vm_pgoff != 0) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << dmabuf->buforder)) + return -EINVAL; + if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf), + size, vma->vm_page_prot)) + return -EAGAIN; + dmabuf->mapped = 1; + + return 0; +} + +static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct i810_state *state = (struct i810_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + + mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) || + ((file->f_mode & FMODE_READ) && dmabuf->mapped); +#ifdef DEBUG + printk("i810_audio: i810_ioctl, command = %2d, arg = 0x%08x\n", + _IOC_NR(cmd), arg ? *(int *)arg : 0); +#endif + + switch (cmd) + { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_RESET: + /* FIXME: spin_lock ? */ + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + synchronize_irq(); + dmabuf->ready = 0; + resync_dma_ptrs(state); + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + synchronize_irq(); + resync_dma_ptrs(state); + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; + } + return 0; + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return drain_dac(state, file->f_flags & O_NONBLOCK); + return 0; + + case SNDCTL_DSP_SPEED: /* set smaple rate */ + get_user_ret(val, (int *)arg, -EFAULT); + if (val >= 0) { + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + spin_lock_irqsave(&state->card->lock, flags); + i810_set_dac_rate(state, val); + spin_unlock_irqrestore(&state->card->lock, flags); + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + spin_lock_irqsave(&state->card->lock, flags); + i810_set_adc_rate(state, val); + spin_unlock_irqrestore(&state->card->lock, flags); + } + } + return put_user(dmabuf->rate, (int *)arg); + + case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ + get_user_ret(val, (int *)arg, -EFAULT); + if(val==0) + return -EINVAL; + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + dmabuf->fmt = I810_FMT_STEREO; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + dmabuf->fmt = I810_FMT_STEREO; + } + return 0; + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf(state, 0))) + return val; + return put_user(dmabuf->fragsize, (int *)arg); + } + if (file->f_mode & FMODE_READ) { + if ((val = prog_dmabuf(state, 1))) + return val; + return put_user(dmabuf->fragsize, (int *)arg); + } + + case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ + return put_user(AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Select sample format */ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != AFMT_QUERY) { + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + } + } + return put_user(AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_CHANNELS: + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 0) { + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + } + } + return put_user(2, (int *)arg); + + case SNDCTL_DSP_POST: + /* FIXME: the same as RESET ?? */ + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + if (dmabuf->subdivision) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + dmabuf->subdivision = val; + return 0; + + case SNDCTL_DSP_SETFRAGMENT: + get_user_ret(val, (int *)arg, -EFAULT); + + dmabuf->ossfragshift = val & 0xffff; + dmabuf->ossmaxfrags = (val >> 16) & 0xffff; + if (dmabuf->ossfragshift < 4) + dmabuf->ossfragshift = 4; + if (dmabuf->ossfragshift > 15) + dmabuf->ossfragshift = 15; + if (dmabuf->ossmaxfrags < 4) + dmabuf->ossmaxfrags = 4; + + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); + abinfo.fragsize = dmabuf->fragsize; + abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.fragstotal = dmabuf->numfrag; + abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); + abinfo.fragsize = dmabuf->fragsize; + abinfo.bytes = dmabuf->count; + abinfo.fragstotal = dmabuf->numfrag; + abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND, + (int *)arg); + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & FMODE_READ && dmabuf->enable) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && dmabuf->enable) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + start_adc(state); + } else + stop_adc(state); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + return ret; + start_dac(state); + } else + stop_dac(state); + } + return 0; + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count >> dmabuf->fragshift; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) + dmabuf->count &= dmabuf->fragsize-1; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count >> dmabuf->fragshift; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) + dmabuf->count &= dmabuf->fragsize-1; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_SETDUPLEX: + return -EINVAL; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); + val = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + return put_user(val, (int *)arg); + + case SOUND_PCM_READ_RATE: + return put_user(dmabuf->rate, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + return put_user((dmabuf->fmt & I810_FMT_STEREO) ? 2 : 1, + (int *)arg); + + case SOUND_PCM_READ_BITS: + return put_user(AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_MAPINBUF: + case SNDCTL_DSP_MAPOUTBUF: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_WRITE_FILTER: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + } + return -EINVAL; +} + +static int i810_open(struct inode *inode, struct file *file) +{ + int i = 0; + int minor = MINOR(inode->i_rdev); + struct i810_card *card = devs; + struct i810_state *state = NULL; + struct dmabuf *dmabuf = NULL; + + /* find an avaiable virtual channel (instance of /dev/dsp) */ + while (card != NULL) { + for (i = 0; i < NR_HW_CH; i++) { + if (card->states[i] == NULL) { + state = card->states[i] = (struct i810_state *) + kmalloc(sizeof(struct i810_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + memset(state, 0, sizeof(struct i810_state)); + dmabuf = &state->dmabuf; + goto found_virt; + } + } + card = card->next; + } + /* no more virtual channel avaiable */ + if (!state) + return -ENODEV; + + found_virt: + /* found a free virtual channel, allocate hardware channels */ + if(file->f_mode & FMODE_READ) + dmabuf->channel = card->alloc_rec_pcm_channel(card); + else + dmabuf->channel = card->alloc_pcm_channel(card); + + if (dmabuf->channel == NULL) { + kfree (card->states[i]); + card->states[i] = NULL;; + return -ENODEV; + } + + /* initialize the virtual channel */ + state->virt = i; + state->card = card; + state->magic = I810_STATE_MAGIC; + init_waitqueue_head(&dmabuf->wait); + init_MUTEX(&state->open_sem); + file->private_data = state; + + down(&state->open_sem); + + /* set default sample format. According to OSS Programmer's Guide /dev/dsp + should be default to unsigned 8-bits, mono, with sample rate 8kHz and + /dev/dspW will accept 16-bits sample */ + if (file->f_mode & FMODE_WRITE) { + dmabuf->fmt &= ~I810_FMT_MASK; + dmabuf->fmt |= I810_FMT_16BIT; + dmabuf->ossfragshift = 0; + dmabuf->ossmaxfrags = 0; + dmabuf->subdivision = 0; + i810_set_dac_rate(state, 48000); + } + + if (file->f_mode & FMODE_READ) { + dmabuf->fmt &= ~I810_FMT_MASK; + dmabuf->fmt |= I810_FMT_16BIT; + dmabuf->ossfragshift = 0; + dmabuf->ossmaxfrags = 0; + dmabuf->subdivision = 0; + i810_set_adc_rate(state, 48000); + } + + state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + up(&state->open_sem); + + MOD_INC_USE_COUNT; + return 0; +} + +static int i810_release(struct inode *inode, struct file *file) +{ + struct i810_state *state = (struct i810_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + + if (file->f_mode & FMODE_WRITE) { + i810_clear_tail(state); + drain_dac(state, file->f_flags & O_NONBLOCK); + } + + /* stop DMA state machine and free DMA buffers/channels */ + down(&state->open_sem); + + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dealloc_dmabuf(state); + state->card->free_pcm_channel(state->card, dmabuf->channel->num); + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dealloc_dmabuf(state); + state->card->free_pcm_channel(state->card, dmabuf->channel->num); + } + + kfree(state->card->states[state->virt]); + state->card->states[state->virt] = NULL; + state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + + /* we're covered by the open_sem */ + up(&state->open_sem); + + MOD_DEC_USE_COUNT; + return 0; +} + +static /*const*/ struct file_operations i810_audio_fops = { + llseek: i810_llseek, + read: i810_read, + write: i810_write, + poll: i810_poll, + ioctl: i810_ioctl, + mmap: i810_mmap, + open: i810_open, + release: i810_release, +}; + +/* Write AC97 codec registers */ + +static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg) +{ + struct i810_card *card = dev->private_data; + int count = 100; + + while(count-- && (inb(card->iobase + CAS) & 1)) + udelay(1); + return inw(card->ac97base + (reg&0x7f)); +} + +static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data) +{ + struct i810_card *card = dev->private_data; + int count = 100; + + while(count-- && (inb(card->iobase + CAS) & 1)) + udelay(1); + outw(data, card->ac97base + (reg&0x7f)); +} + + +/* OSS /dev/mixer file operation methods */ + +static int i810_open_mixdev(struct inode *inode, struct file *file) +{ + int i; + int minor = MINOR(inode->i_rdev); + struct i810_card *card = devs; + + for (card = devs; card != NULL; card = card->next) + for (i = 0; i < NR_AC97; i++) + if (card->ac97_codec[i] != NULL && + card->ac97_codec[i]->dev_mixer == minor) + goto match; + + if (!card) + return -ENODEV; + + match: + file->private_data = card->ac97_codec[i]; + + MOD_INC_USE_COUNT; + return 0; +} + +static int i810_release_mixdev(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ac97_codec *codec = (struct ac97_codec *)file->private_data; + + return codec->mixer_ioctl(codec, cmd, arg); +} + +static /*const*/ struct file_operations i810_mixer_fops = { + llseek: i810_llseek, + ioctl: i810_ioctl_mixdev, + open: i810_open_mixdev, + release: i810_release_mixdev, +}; + +/* AC97 codec initialisation. */ +static int __init i810_ac97_init(struct i810_card *card) +{ + int num_ac97 = 0; + int ready_2nd = 0; + struct ac97_codec *codec; + u16 eid; + + outl(0, card->iobase + GLOB_CNT); + udelay(500); + outl(1<<1, card->iobase + GLOB_CNT); + + for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(codec, 0, sizeof(struct ac97_codec)); + + /* initialize some basic codec information, other fields will be filled + in ac97_probe_codec */ + codec->private_data = card; + codec->id = num_ac97; + + codec->codec_read = i810_ac97_get; + codec->codec_write = i810_ac97_set; + + if (ac97_probe_codec(codec) == 0) + break; + + eid = i810_ac97_get(codec, AC97_EXTENDED_ID); + + if(eid==0xFFFFFF) + { + printk(KERN_WARNING "i810_audio: no codec attached ?\n"); + kfree(codec); + break; + } + + card->ac97_features = eid; + + if(!(eid&0x0001)) + printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n"); + + if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) { + printk(KERN_ERR "i810_audio: couldn't register mixer!\n"); + kfree(codec); + break; + } + + /* Now check the codec for useful features to make up for + the dumbness of the 810 hardware engine */ + + card->ac97_codec[num_ac97] = codec; + + /* if there is no secondary codec at all, don't probe any more */ + if (!ready_2nd) + return num_ac97+1; + } + return num_ac97; +} + +/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered + untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ + +static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) +{ + struct i810_card *card; + + if (!pci_dma_supported(pci_dev, I810_DMA_MASK)) { + printk(KERN_ERR "intel810: architecture does not support" + " 32bit PCI busmaster DMA\n"); + return -ENODEV; + } + + if ((card = kmalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "i810_audio: out of memory\n"); + return -ENOMEM; + } + memset(card, 0, sizeof(*card)); + + card->iobase = pci_dev->resource[1].start; + card->ac97base = pci_dev->resource[0].start; + card->pci_dev = pci_dev; + card->pci_id = pci_id->device; + card->irq = pci_dev->irq; + card->next = devs; + card->magic = I810_CARD_MAGIC; + spin_lock_init(&card->lock); + devs = card; + + pci_set_master(pci_dev); + pci_enable_device(pci_dev); + + printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, IRQ %d\n", + card_names[pci_id->driver_data], card->iobase, card->ac97base, + card->irq); + + card->alloc_pcm_channel = i810_alloc_pcm_channel; + card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel; + card->free_pcm_channel = i810_free_pcm_channel; + + /* claim our iospace and irq */ + request_region(card->iobase, 64, card_names[pci_id->driver_data]); + request_region(card->ac97base, 256, card_names[pci_id->driver_data]); + + if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ, + card_names[pci_id->driver_data], card)) { + printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq); + release_region(card->iobase, 64); + release_region(card->ac97base, 256); + kfree(card); + return -ENODEV; + } + /* register /dev/dsp */ + if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) { + printk(KERN_ERR "i810_audio: couldn't register DSP device!\n"); + release_region(card->iobase, 64); + release_region(card->ac97base, 256); + free_irq(card->irq, card); + kfree(card); + return -ENODEV; + } + + + /* initialize AC97 codec and register /dev/mixer */ + if (i810_ac97_init(card) <= 0) { + unregister_sound_dsp(card->dev_audio); + release_region(card->iobase, 64); + release_region(card->ac97base, 256); + free_irq(card->irq, card); + kfree(card); + return -ENODEV; + } + pci_dev->driver_data = card; + pci_dev->dma_mask = I810_DMA_MASK; + +// printk("resetting codec?\n"); + outl(0, card->iobase + GLOB_CNT); + udelay(500); +// printk("bringing it back?\n"); + outl(1<<1, card->iobase + GLOB_CNT); + return 0; +} + +static void __exit i810_remove(struct pci_dev *pci_dev) +{ + int i; + struct i810_card *card = pci_dev->driver_data; + /* free hardware resources */ + free_irq(card->irq, devs); + release_region(card->iobase, 64); + release_region(card->ac97base, 256); + + /* unregister audio devices */ + for (i = 0; i < NR_AC97; i++) + if (devs->ac97_codec[i] != NULL) { + unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); + kfree (card->ac97_codec[i]); + } + unregister_sound_dsp(card->dev_audio); + kfree(card); +} + +MODULE_AUTHOR(""); +MODULE_DESCRIPTION("Intel 810 audio support"); + +#define I810_MODULE_NAME "intel810_audio" + +static struct pci_driver i810_pci_driver = { + name: I810_MODULE_NAME, + id_table: i810_pci_tbl, + probe: i810_probe, + remove: i810_remove, +}; + +static int __init i810_init_module (void) +{ + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + + printk(KERN_INFO "Intel 810 + AC97 Audio, version " + DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); + + if (!pci_register_driver(&i810_pci_driver)) { + pci_unregister_driver(&i810_pci_driver); + return -ENODEV; + } + return 0; +} + +static void __exit i810_cleanup_module (void) +{ + pci_unregister_driver(&i810_pci_driver); +} + +module_init(i810_init_module); +module_exit(i810_cleanup_module); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c --- v2.3.99-pre5/linux/drivers/sound/maestro.c Thu Feb 10 17:11:14 2000 +++ linux/drivers/sound/maestro.c Fri Apr 21 16:14:14 2000 @@ -21,7 +21,7 @@ * Based heavily on SonicVibes.c: * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) * - * Heavily modified by Zach Brown based on lunch + * Heavily modified by Zach Brown based on lunch * with ESS engineers. Many thanks to Howard Kim for providing * contacts and hardware. Honorable mention goes to Eric * Brombaugh for all sorts of things. Best regards to the @@ -105,8 +105,28 @@ * being used now is quite dirty and assumes we're on a uni-processor * machine. Much of it will need to be cleaned up for SMP ACPI or * similar. + * + * We also pay attention to PCI power management now. The driver + * will power down units of the chip that it knows aren't needed. + * The WaveProcessor and company are only powered on when people + * have /dev/dsp*s open. On removal the driver will + * power down the maestro entirely. There could still be + * trouble with BIOSen that magically change power states + * themselves, but we'll see. * * History + * (still based on v0.14) Mar 29 2000 - Zach Brown + * move to 2.3 power management interface, which + * required hacking some suspend/resume/check paths + * make static compilation work + * v0.14 - Jan 28 2000 - Zach Brown + * add PCI power management through ACPI regs. + * we now shut down on machine reboot/halt + * leave scary PCI config items alone (isa stuff, mostly) + * enable 1921s, it seems only mine was broke. + * fix swapped left/right pcm dac. har har. + * up bob freq, increase buffers, fix pointers at underflow + * silly compilation problems * v0.13 - Nov 18 1999 - Zach Brown * fix nec Versas? man would that be cool. * v0.12 - Nov 12 1999 - Zach Brown @@ -162,13 +182,11 @@ * bob freq code, region sanity, jitter sync fix; all from Eric * * TODO - * some people get indir reg timeouts? * fix bob frequency * endianness * do smart things with ac97 2.0 bits. * docking and dual codecs and 978? * leave 54->61 open - * resolve 2.3/2.2 stuff * * it also would be fun to have a mode that would not use pci dma at all * but would copy into the wavecache on board memory and use that @@ -190,6 +208,7 @@ #define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC) #define SILLY_OFFSET(VMA) ((VMA)->vm_offset) + #else #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->resource[0].start) @@ -197,6 +216,7 @@ #define SILLY_MAKE_INIT(FUNC) __init FUNC #define SILLY_OFFSET(VMA) ((VMA)->vm_pgoff) + #endif #include @@ -213,15 +233,12 @@ #include #include #include +#include #include #include #include static int maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *d); -static int in_suspend=0; -wait_queue_head_t suspend_queue; -static void check_suspend(void); -#define CHECK_SUSPEND check_suspend(); #include "maestro.h" @@ -231,14 +248,18 @@ #ifdef M_DEBUG static int debug=0; -static int dsps_order=0; #define M_printk(args...) {if (debug) printk(args);} #else #define M_printk(x) #endif +/* we try to setup 2^(dsps_order) /dev/dsp devices */ +static int dsps_order=0; +/* wether or not we mess around with power management */ +static int use_pm=2; /* set to 1 for force */ + /* --------------------------------------------------------------------- */ -#define DRIVER_VERSION "0.13" +#define DRIVER_VERSION "0.14" #ifndef PCI_VENDOR_ESS #define PCI_VENDOR_ESS 0x125D @@ -282,6 +303,46 @@ #define NR_APUS 64 #define NR_APU_REGS 16 +/* acpi states */ +enum { + ACPI_D0=0, + ACPI_D1, + ACPI_D2, + ACPI_D3 +}; + +/* bits in the acpi masks */ +#define ACPI_12MHZ ( 1 << 15) +#define ACPI_24MHZ ( 1 << 14) +#define ACPI_978 ( 1 << 13) +#define ACPI_SPDIF ( 1 << 12) +#define ACPI_GLUE ( 1 << 11) +#define ACPI__10 ( 1 << 10) /* reserved */ +#define ACPI_PCIINT ( 1 << 9) +#define ACPI_HV ( 1 << 8) /* hardware volume */ +#define ACPI_GPIO ( 1 << 7) +#define ACPI_ASSP ( 1 << 6) +#define ACPI_SB ( 1 << 5) /* sb emul */ +#define ACPI_FM ( 1 << 4) /* fm emul */ +#define ACPI_RB ( 1 << 3) /* ringbus / aclink */ +#define ACPI_MIDI ( 1 << 2) +#define ACPI_GP ( 1 << 1) /* game port */ +#define ACPI_WP ( 1 << 0) /* wave processor */ + +#define ACPI_ALL (0xffff) +#define ACPI_SLEEP (~(ACPI_SPDIF|ACPI_ASSP|ACPI_SB|ACPI_FM| \ + ACPI_MIDI|ACPI_GP|ACPI_WP)) +#define ACPI_NONE (ACPI__10) + +/* these masks indicate which units we care about at + which states */ +u16 acpi_state_mask[] = { + [ACPI_D0] = ACPI_ALL, + [ACPI_D1] = ACPI_SLEEP, + [ACPI_D2] = ACPI_SLEEP, + [ACPI_D3] = ACPI_NONE +}; + static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; @@ -303,6 +364,10 @@ [TYPE_MAESTRO2E] = (50000000L / 1024L) }; +static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf); + +static struct notifier_block maestro_nb = {maestro_notifier, NULL, 0}; + /* --------------------------------------------------------------------- */ struct ess_state { @@ -357,6 +422,7 @@ /* pointer to each dsp?s piece of the apu->src buffer page */ void *mixbuf; + }; struct ess_card { @@ -383,6 +449,11 @@ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; } mix; + int power_regs; + + int in_suspend; + wait_queue_head_t suspend_queue; + struct ess_state channels[MAX_DSPS]; u16 maestro_map[NR_IDRS]; /* Register map */ /* we have to store this junk so that we can come back from a @@ -397,7 +468,7 @@ int dmaorder; /* hardware resources */ - struct pci_dev pcidev; /* uck.. */ + struct pci_dev *pcidev; u32 iobase; u32 irq; @@ -434,6 +505,8 @@ /* --------------------------------------------------------------------- */ +static void check_suspend(struct ess_card *card); + static struct ess_card *devs = NULL; /* --------------------------------------------------------------------- */ @@ -443,14 +516,15 @@ * ESS Maestro AC97 codec programming interface. */ -static void maestro_ac97_set(int io, u8 cmd, u16 val) +static void maestro_ac97_set(struct ess_card *card, u8 cmd, u16 val) { + int io = card->iobase; int i; /* * Wait for the codec bus to be free */ - CHECK_SUSPEND; + check_suspend(card); for(i=0;i<10000;i++) { @@ -466,13 +540,14 @@ mdelay(1); } -static u16 maestro_ac97_get(int io, u8 cmd) +static u16 maestro_ac97_get(struct ess_card *card, u8 cmd) { + int io = card->iobase; int sanity=10000; u16 data; int i; - CHECK_SUSPEND; + check_suspend(card); /* * Wait for the codec bus to be free */ @@ -564,7 +639,7 @@ int ret=0; struct ac97_mixer_hw *mh = &ac97_hw[mixer]; - val = maestro_ac97_get(card->iobase , mh->offset); + val = maestro_ac97_get(card, mh->offset); if(AC97_STEREO_MASK & (1< log */ -unsigned char lin2log[101] = +static unsigned char lin2log[101] = { 0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 , 50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 , @@ -649,19 +724,19 @@ } else if (mixer == SOUND_MIXER_SPEAKER) { val = (((100 - left) * mh->scale) / 100) << 1; } else if (mixer == SOUND_MIXER_MIC) { - val = maestro_ac97_get(card->iobase , mh->offset) & ~0x801f; + val = maestro_ac97_get(card, mh->offset) & ~0x801f; val |= (((100 - left) * mh->scale) / 100); /* the low bit is optional in the tone sliders and masking it lets is avoid the 0xf 'bypass'.. */ } else if (mixer == SOUND_MIXER_BASS) { - val = maestro_ac97_get(card->iobase , mh->offset) & ~0x0f00; + val = maestro_ac97_get(card , mh->offset) & ~0x0f00; val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00; } else if (mixer == SOUND_MIXER_TREBLE) { - val = maestro_ac97_get(card->iobase , mh->offset) & ~0x000f; + val = maestro_ac97_get(card , mh->offset) & ~0x000f; val |= (((100 - left) * mh->scale) / 100) & 0x000e; } - maestro_ac97_set(card->iobase , mh->offset, val); + maestro_ac97_set(card , mh->offset, val); M_printk(" -> %x\n",val); } @@ -708,7 +783,7 @@ static int ac97_recmask_io(struct ess_card *card, int read, int mask) { - unsigned int val = ac97_oss_mask[ maestro_ac97_get(card->iobase, 0x1a) & 0x7 ]; + unsigned int val = ac97_oss_mask[ maestro_ac97_get(card, 0x1a) & 0x7 ]; if (read) return val; @@ -723,7 +798,7 @@ M_printk("maestro: setting ac97 recmask to 0x%x\n",val); - maestro_ac97_set(card->iobase,0x1a,val); + maestro_ac97_set(card,0x1a,val); return 0; }; @@ -736,7 +811,7 @@ * The PT101 setup is untested. */ -static u16 maestro_ac97_init(struct ess_card *card, int iobase) +static u16 maestro_ac97_init(struct ess_card *card) { u16 vend1, vend2, caps; @@ -747,13 +822,13 @@ card->mix.write_mixer = ac97_write_mixer; card->mix.recmask_io = ac97_recmask_io; - vend1 = maestro_ac97_get(iobase, 0x7c); - vend2 = maestro_ac97_get(iobase, 0x7e); + vend1 = maestro_ac97_get(card, 0x7c); + vend2 = maestro_ac97_get(card, 0x7e); - caps = maestro_ac97_get(iobase, 0x00); + caps = maestro_ac97_get(card, 0x00); printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x caps: 0x%x pwr: 0x%x\n", - vend1,vend2,caps,maestro_ac97_get(iobase,0x26) & 0xf); + vend1,vend2,caps,maestro_ac97_get(card,0x26) & 0xf); if (! (caps & 0x4) ) { /* no bass/treble nobs */ @@ -765,10 +840,14 @@ switch ((long)(vend1 << 16) | vend2) { case 0x545200ff: /* TriTech */ /* no idea what this does */ - maestro_ac97_set(iobase,0x2a,0x0001); - maestro_ac97_set(iobase,0x2c,0x0000); - maestro_ac97_set(iobase,0x2c,0xffff); + maestro_ac97_set(card,0x2a,0x0001); + maestro_ac97_set(card,0x2c,0x0000); + maestro_ac97_set(card,0x2c,0xffff); break; +#if 0 /* i thought the problems I was seeing were with + the 1921, but apparently they were with the pci board + it was on, so this code is commented out. + lets see if this holds true. */ case 0x83847609: /* ESS 1921 */ /* writing to 0xe (mic) or 0x1a (recmask) seems to hang this codec */ @@ -776,20 +855,21 @@ card->mix.record_sources = 0; card->mix.recmask_io = NULL; #if 0 /* don't ask. I have yet to see what these actually do. */ - maestro_ac97_set(iobase,0x76,0xABBA); /* o/~ Take a chance on me o/~ */ + maestro_ac97_set(card,0x76,0xABBA); /* o/~ Take a chance on me o/~ */ udelay(20); - maestro_ac97_set(iobase,0x78,0x3002); + maestro_ac97_set(card,0x78,0x3002); udelay(20); - maestro_ac97_set(iobase,0x78,0x3802); + maestro_ac97_set(card,0x78,0x3802); udelay(20); #endif break; +#endif default: break; } - maestro_ac97_set(iobase, 0x1E, 0x0404); + maestro_ac97_set(card, 0x1E, 0x0404); /* null misc stuff */ - maestro_ac97_set(iobase, 0x20, 0x0000); + maestro_ac97_set(card, 0x20, 0x0000); return 0; } @@ -923,7 +1003,7 @@ { unsigned long flags; - CHECK_SUSPEND; + check_suspend(s->card); spin_lock_irqsave(&s->card->lock,flags); __maestro_write(s->card,reg,data); @@ -944,7 +1024,7 @@ if(READABLE_MAP & (1<card); spin_lock_irqsave(&s->card->lock,flags); __maestro_read(s->card,reg); @@ -1003,7 +1083,7 @@ { unsigned long flags; - CHECK_SUSPEND; + check_suspend(s->card); if(channel&ESS_CHAN_HARD) channel&=~ESS_CHAN_HARD; @@ -1032,7 +1112,7 @@ unsigned long flags; u16 v; - CHECK_SUSPEND; + check_suspend(s->card); if(channel&ESS_CHAN_HARD) channel&=~ESS_CHAN_HARD; @@ -1060,7 +1140,7 @@ { long ioaddr = s->card->iobase; unsigned long flags; - CHECK_SUSPEND; + check_suspend(s->card); spin_lock_irqsave(&s->card->lock,flags); @@ -1075,7 +1155,7 @@ long ioaddr = s->card->iobase; unsigned long flags; u16 value; - CHECK_SUSPEND; + check_suspend(s->card); spin_lock_irqsave(&s->card->lock,flags); outw(reg, ioaddr+0x10); @@ -1198,7 +1278,7 @@ } /* stop output apus */ -extern inline void stop_dac(struct ess_state *s) +static void stop_dac(struct ess_state *s) { /* XXX have to lock around this? */ if (! (s->enable & DAC_RUNNING)) return; @@ -1304,11 +1384,12 @@ /* XXX think about endianess when writing these registers */ M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa); - /* Load the buffer into the wave engine */ + /* start of sample */ apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8); apu_set_register(ess, channel, 5, pa&0xFFFF); + /* sample end */ apu_set_register(ess, channel, 6, (pa+size)&0xFFFF); - /* setting loop == sample len */ + /* setting loop len == sample len */ apu_set_register(ess, channel, 7, size); /* clear effects/env.. */ @@ -1328,7 +1409,7 @@ if(mode&ESS_FMT_STEREO) { /* set panning: left or right */ - apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0)); + apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0 : 0x10)); ess->apu_mode[channel] += 0x10; } else apu_set_register(ess, channel, 10, 0x8F08); @@ -1539,7 +1620,7 @@ int divide; /* XXX make freq selector much smarter, see calc_bob_rate */ - int freq = 150; /* requested frequency - calculate what we want here. */ + int freq = 200; /* compute ideal interrupt frequency for buffer size & play rate */ /* first, find best prescaler value to match freq */ @@ -1647,6 +1728,7 @@ db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; + /* this algorithm is a little nuts.. where did /1000 come from? */ bytepersec = rate << sample_shift[fmt]; bufs = PAGE_SIZE << db->buforder; if (db->ossfragshift) { @@ -1675,13 +1757,11 @@ memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize); spin_lock_irqsave(&s->lock, flags); - if (rec) { - ess_rec_setup(s, fmt, s->rateadc, - db->rawbuf, db->numfrag << db->fragshift); - } else { - ess_play_setup(s, fmt, s->ratedac, - db->rawbuf, db->numfrag << db->fragshift); - } + if (rec) + ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize); + else + ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize); + spin_unlock_irqrestore(&s->lock, flags); db->ready = 1; @@ -1720,8 +1800,7 @@ /* oh boy should this all be re-written. everything in the current code paths think that the various counters/pointers are expressed in bytes to the user but we have two apus doing stereo stuff so we fix it up here.. it propogates to all the various - counters from here. Notice that this means that mono recording is very very - broken right now. */ + counters from here. */ if ( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) { hwptr = (get_dmac(s)*2) % s->dma_adc.dmasize; } else { @@ -1751,7 +1830,7 @@ hwptr = get_dmaa(s) % s->dma_dac.dmasize; /* the apu only reports the length it has seen, not the length of the memory that has been used (the WP - knows that */ + knows that) */ if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT)) hwptr<<=1; @@ -1768,14 +1847,15 @@ s->dma_dac.count -= diff; /* M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */ if (s->dma_dac.count <= 0) { + M_printk("underflow! diff: %d count: %d hw: %d sw: %d\n", diff, s->dma_dac.count, + hwptr, s->dma_dac.swptr); /* FILL ME wrindir(s, SV_CIENABLE, s->enable); */ /* XXX how on earth can calling this with the lock held work.. */ stop_dac(s); /* brute force everyone back in sync, sigh */ s->dma_dac.count = 0; - s->dma_dac.swptr = 0; - s->dma_dac.hwptr = 0; + s->dma_dac.swptr = hwptr; s->dma_dac.error++; } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { clear_advance(s); @@ -1783,6 +1863,8 @@ } if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) { wake_up(&s->dma_dac.wait); +/* printk("waking up DAC count: %d sw: %d hw: %d\n",s->dma_dac.count, s->dma_dac.swptr, + hwptr);*/ } } } @@ -2023,10 +2105,10 @@ } static /*const*/ struct file_operations ess_mixer_fops = { - llseek: ess_llseek, - ioctl: ess_ioctl_mixdev, - open: ess_open_mixdev, - release: ess_release_mixdev, + llseek: ess_llseek, + ioctl: ess_ioctl_mixdev, + open: ess_open_mixdev, + release: ess_release_mixdev, }; /* --------------------------------------------------------------------- */ @@ -2153,8 +2235,7 @@ goto rec_return_free; } if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { - if(! in_suspend) - printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, s->dma_adc.hwptr, s->dma_adc.swptr); stop_adc(s); @@ -2253,8 +2334,7 @@ goto return_free; } if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { - if(! in_suspend) - printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, s->dma_dac.hwptr, s->dma_dac.swptr); stop_dac(s); @@ -2277,6 +2357,7 @@ if (!ret) ret = -EFAULT; goto return_free; } +/* printk("wrote %d bytes at sw: %d cnt: %d while hw: %d\n",cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);*/ swptr = (swptr + cnt) % s->dma_dac.dmasize; @@ -2294,6 +2375,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait) { struct ess_state *s = (struct ess_state *)file->private_data; @@ -2613,6 +2695,7 @@ case SNDCTL_DSP_SETFRAGMENT: get_user_ret(val, (int *)arg, -EFAULT); + M_printk("maestro: SETFRAGMENT: %0x\n",val); if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -2678,6 +2761,36 @@ wave_set_register(s, 0x01FF , packed_phys); } +/* + * this guy makes sure we're in the right power + * state for what we want to be doing + */ +static void maestro_power(struct ess_card *card, int tostate) +{ + u16 active_mask = acpi_state_mask[tostate]; + u8 state; + + if(!use_pm) return; + + pci_read_config_byte(card->pcidev, card->power_regs+0x4, &state); + state&=3; + + /* make sure we're in the right state */ + if(state != tostate) { + M_printk(KERN_WARNING "maestro: dev %02x:%02x.%x switching from D%d to D%d\n", + card->pcidev->bus->number, + PCI_SLOT(card->pcidev->devfn), + PCI_FUNC(card->pcidev->devfn), + state,tostate); + pci_write_config_byte(card->pcidev, card->power_regs+0x4, tostate); + } + + /* and make sure the units we care about are on + XXX we might want to do this before state flipping? */ + pci_write_config_word(card->pcidev, 0x54, ~ active_mask); + pci_write_config_word(card->pcidev, 0x56, ~ active_mask); +} + /* we allocate a large power of two for all our memory. this is cut up into (not to scale :): |silly fifo word | 512byte mixbuf per adc | dac/adc * channels | @@ -2690,7 +2803,7 @@ unsigned long mapend,map; /* alloc as big a chunk as we can */ - for (order = (dsps_order + (15-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--) + for (order = (dsps_order + (16-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--) if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order))) break; @@ -2709,12 +2822,6 @@ s->card->dmapages = rawbuf; s->card->dmaorder = order; - /* play bufs are in the same first region as record bufs */ - set_base_registers(s,rawbuf); - - M_printk("maestro: writing %lx (%lx) to the wp\n",virt_to_bus(rawbuf), - ((virt_to_bus(rawbuf))&0xFFE00000)>>12); - for(i=0;icard->channels[i]; @@ -2733,7 +2840,7 @@ happily scribble away.. */ ess->mixbuf = rawbuf + (512 * (i+1)); - M_printk("maestro: setup apu %d: %p %p %p\n",i,ess->dma_dac.rawbuf, + M_printk("maestro: setup apu %d: dac: %p adc: %p mix: %p\n",i,ess->dma_dac.rawbuf, ess->dma_adc.rawbuf, ess->mixbuf); } @@ -2819,6 +2926,20 @@ return -ENOMEM; } + /* we're covered by the open_sem */ + if( ! s->card->dsps_open ) { + maestro_power(s->card,ACPI_D0); + start_bob(s); + } + s->card->dsps_open++; + M_printk("maestro: open, %d bobs now\n",s->card->dsps_open); + + /* ok, lets write WC base regs now that we've + powered up the chip */ + M_printk("maestro: writing 0x%lx (bus 0x%lx) to the wp\n",virt_to_bus(s->card->dmapages), + ((virt_to_bus(s->card->dmapages))&0xFFE00000)>>12); + set_base_registers(s,s->card->dmapages); + if (file->f_mode & FMODE_READ) { /* fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT); @@ -2842,13 +2963,6 @@ set_fmt(s, fmtm, fmts); s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - /* we're covered by the open_sem */ - if( ! s->card->dsps_open ) { - start_bob(s); - } - s->card->dsps_open++; - M_printk("maestro: open, %d bobs now\n",s->card->dsps_open); - up(&s->open_sem); MOD_INC_USE_COUNT; return 0; @@ -2874,8 +2988,10 @@ /* we're covered by the open_sem */ M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1); if( --s->card->dsps_open <= 0) { + s->card->dsps_open = 0; stop_bob(s); free_buffers(s); + maestro_power(s->card,ACPI_D2); } up(&s->open_sem); wake_up(&s->open_wait); @@ -2884,56 +3000,42 @@ } static struct file_operations ess_audio_fops = { - llseek: ess_llseek, - read: ess_read, - write: ess_write, - poll: ess_poll, - ioctl: ess_ioctl, - mmap: ess_mmap, - open: ess_open, - release: ess_release, + llseek: ess_llseek, + read: ess_read, + write: ess_write, + poll: ess_poll, + ioctl: ess_ioctl, + mmap: ess_mmap, + open: ess_open, + release: ess_release, }; static int maestro_config(struct ess_card *card) { - struct pci_dev *pcidev = &card->pcidev; + struct pci_dev *pcidev = card->pcidev; struct ess_state *ess = &card->channels[0]; int apu,iobase = card->iobase; u16 w; u32 n; - /* - * Disable ACPI + /* We used to muck around with pci config space that + * we had no business messing with. We don't know enough + * about the machine to know which DMA mode is appropriate, + * etc. We were guessing wrong on some machines and making + * them unhappy. We now trust in the BIOS to do things right, + * which almost certainly means a new host of problems will + * arise with broken BIOS implementations. screw 'em. + * We're already intolerant of machines that don't assign + * IRQs. */ - - pci_write_config_dword(pcidev, 0x54, 0x00000000); - pci_write_config_dword(pcidev, 0x56, 0x00000000); - /* - * Use TDMA for now. TDMA works on all boards, so while its - * not the most efficient its the simplest. - */ + /* do config work at full power */ + maestro_power(card,ACPI_D0); pci_read_config_word(pcidev, 0x50, &w); - /* Clear DMA bits */ - w&=~(1<<10|1<<9|1<<8); - - /* TDMA on */ - w|= (1<<8); - - /* - * Some of these are undocumented bits - */ - - w&=~(1<<13)|(1<<14); /* PIC Snoop mode bits */ - w&=~(1<<11); /* Safeguard off */ - w|= (1<<7); /* Posted write */ - w|= (1<<6); /* ISA timing on */ - /* XXX huh? claims to be reserved.. */ - w&=~(1<<5); /* Don't swap left/right */ - w&=~(1<<1); /* Subtractive decode off */ + w&=~(1<<5); /* Don't swap left/right (undoc)*/ pci_write_config_word(pcidev, 0x50, w); @@ -2946,19 +3048,9 @@ w&=~(1<<6); /* Debounce off */ w&=~(1<<5); /* GPIO 4:5 */ w|= (1<<4); /* Disconnect from the CHI. Enabling this made a dell 7500 work. */ - w&=~(1<<3); /* IDMA off (undocumented) */ w&=~(1<<2); /* MIDI fix off (undoc) */ w&=~(1<<1); /* reserved, always write 0 */ - w&=~(1<<0); /* IRQ to ISA off (undoc) */ pci_write_config_word(pcidev, 0x52, w); - - /* - * DDMA off - */ - - pci_read_config_word(pcidev, 0x60, &w); - w&=~(1<<0); - pci_write_config_word(pcidev, 0x60, w); /* * Legacy mode @@ -2971,8 +3063,6 @@ pci_write_config_word(pcidev, 0x40, w); - /* stake our claim on the iospace */ - request_region(iobase, 256, card_names[card->card_type]); sound_reset(iobase); @@ -3140,6 +3230,39 @@ } +/* this guy tries to find the pci power management + * register bank. this should really be in core + * code somewhere. 1 on success. */ +int +parse_power(struct ess_card *card, struct pci_dev *pcidev) +{ + u32 n; + u16 w; + u8 next; + int max = 64; /* an a 8bit guy pointing to 32bit guys + can only express so much. */ + + card->power_regs = 0; + + /* check to see if we have a capabilities list in + the config register */ + pci_read_config_word(pcidev, PCI_STATUS, &w); + if(! w & PCI_STATUS_CAP_LIST) return 0; + + /* walk the list, starting at the head. */ + pci_read_config_byte(pcidev,PCI_CAPABILITY_LIST,&next); + + while(next && max--) { + pci_read_config_dword(pcidev, next & ~3, &n); + if((n & 0xff) == PCI_CAP_ID_PM) { + card->power_regs = next; + break; + } + next = ((n>>8) & 0xff); + } + + return card->power_regs ? 1 : 0; +} static int maestro_install(struct pci_dev *pcidev, int card_type) @@ -3149,7 +3272,7 @@ int i; struct ess_card *card; struct ess_state *ess; - struct pm_dev *pmdev; + struct pm_dev *pmdev; int num = 0; /* don't pick up weird modem maestros */ @@ -3158,15 +3281,15 @@ iobase = SILLY_PCI_BASE_ADDRESS(pcidev); - if(check_region(iobase, 256)) + /* stake our claim on the iospace */ + if( request_region(iobase, 256, card_names[card_type]) == NULL ) { printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase); return 0; } /* this was tripping up some machines */ - if(pcidev->irq == 0) - { + if(pcidev->irq == 0) { printk(KERN_WARNING "maestro: pci subsystem reports irq 0, this might not be correct.\n"); } @@ -3181,13 +3304,16 @@ } memset(card, 0, sizeof(*card)); - memcpy(&card->pcidev,pcidev,sizeof(card->pcidev)); + card->pcidev = pcidev; - pmdev = pm_register(PM_PCI_DEV, - PM_PCI_ID(pcidev), - maestro_pm_callback); - if (pmdev) - pmdev->data = card; + pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(pcidev), + maestro_pm_callback); + if (pmdev) + pmdev->data = card; + + if (register_reboot_notifier(&maestro_nb)) { + printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n"); + } card->iobase = iobase; card->card_type = card_type; @@ -3195,6 +3321,7 @@ card->next = devs; card->magic = ESS_CARD_MAGIC; spin_lock_init(&card->lock); + init_waitqueue_head(&card->suspend_queue); devs = card; /* init our groups of 6 apus */ @@ -3246,13 +3373,37 @@ pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n); printk(KERN_INFO "maestro: subvendor id: 0x%08x\n",n); + /* turn off power management unless: + * - the user explicitly asks for it + * or + * - we're not a 2e, lesser chipps seem to have problems. + * - we're not on our _very_ small whitelist. some implemenetations + * really dont' like the pm code, others require it. + * feel free to expand this as required. + */ +#define SUBSYSTEM_VENDOR(x) (x&0xffff) + if( (use_pm != 1) && + ((card_type != TYPE_MAESTRO2E) || (SUBSYSTEM_VENDOR(n) != 0x1028))) + use_pm = 0; + + if(!use_pm) + printk(KERN_INFO "maestro: not attempting power management.\n"); + else { + if(!parse_power(card,pcidev)) + printk(KERN_INFO "maestro: no PCI power managment interface found.\n"); + else { + pci_read_config_dword(pcidev, card->power_regs, &n); + printk(KERN_INFO "maestro: PCI power managment capability: 0x%x\n",n>>16); + } + } + maestro_config(card); - if(maestro_ac97_get(iobase, 0x00)==0x0080) { + if(maestro_ac97_get(card, 0x00)==0x0080) { printk(KERN_ERR "maestro: my goodness! you seem to have a pt101 codec, which is quite rare.\n" "\tyou should tell someone about this.\n"); } else { - maestro_ac97_init(card,iobase); + maestro_ac97_init(card); } if ((card->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) { @@ -3273,9 +3424,12 @@ unregister_sound_dsp(s->dev_audio); } release_region(card->iobase, 256); + unregister_reboot_notifier(&maestro_nb); kfree(card); return 0; } + /* now go to sleep 'till something interesting happens */ + maestro_power(card,ACPI_D2); printk(KERN_INFO "maestro: %d channels configured.\n", num); return 1; @@ -3305,8 +3459,6 @@ printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order); } - init_waitqueue_head(&suspend_queue); - /* * Find the ESS Maestro 2. */ @@ -3340,56 +3492,78 @@ return 0; } -/* --------------------------------------------------------------------- */ - -#ifdef MODULE -MODULE_AUTHOR("Zach Brown , Alan Cox "); -MODULE_DESCRIPTION("ESS Maestro Driver"); -#ifdef M_DEBUG -MODULE_PARM(debug,"i"); -#endif -MODULE_PARM(dsps_order,"i"); - -void cleanup_module(void) +static void nuke_maestros(void) { - struct ess_card *s; + struct ess_card *card; + /* we do these unconditionally, which is probably wrong */ pm_unregister_all(maestro_pm_callback); + unregister_reboot_notifier(&maestro_nb); - while ((s = devs)) { + while ((card = devs)) { int i; devs = devs->next; /* XXX maybe should force stop bob, but should be all stopped by _release by now */ - free_irq(s->irq, s); - unregister_sound_mixer(s->dev_mixer); + free_irq(card->irq, card); + unregister_sound_mixer(card->dev_mixer); for(i=0;ichannels[i]; + struct ess_state *ess = &card->channels[i]; if(ess->dev_audio != -1) unregister_sound_dsp(ess->dev_audio); } - release_region(s->iobase, 256); - kfree(s); + /* Goodbye, Mr. Bond. */ + maestro_power(card,ACPI_D3); + release_region(card->iobase, 256); + kfree(card); } + devs = NULL; +} + +static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf) +{ + /* this notifier is called when the kernel is really shut down. */ + M_printk("maestro: shutting down\n"); + nuke_maestros(); + return NOTIFY_OK; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE +MODULE_AUTHOR("Zach Brown , Alan Cox "); +MODULE_DESCRIPTION("ESS Maestro Driver"); +#ifdef M_DEBUG +MODULE_PARM(debug,"i"); +#endif +MODULE_PARM(dsps_order,"i"); +MODULE_PARM(use_pm,"i"); + +void cleanup_module(void) { M_printk("maestro: unloading\n"); + nuke_maestros(); } -#endif /* MODULE */ +#else /* MODULE */ +__initcall(init_maestro); +#endif + +/* --------------------------------------------------------------------- */ void -check_suspend(void) +check_suspend(struct ess_card *card) { DECLARE_WAITQUEUE(wait, current); - if(!in_suspend) return; + if(!card->in_suspend) return; - in_suspend++; - add_wait_queue(&suspend_queue, &wait); + card->in_suspend++; + add_wait_queue(&(card->suspend_queue), &wait); current->state = TASK_UNINTERRUPTIBLE; schedule(); - remove_wait_queue(&suspend_queue, &wait); + remove_wait_queue(&(card->suspend_queue), &wait); current->state = TASK_RUNNING; } @@ -3397,113 +3571,138 @@ maestro_suspend(struct ess_card *card) { unsigned long flags; - int i,j; + int i,j; - save_flags(flags); - cli(); + save_flags(flags); + cli(); /* over-kill */ - M_printk("maestro: pm in dev %p\n",card); + M_printk("maestro: apm in dev %p\n",card); - for(i=0;ichannels[i]; + /* we have to read from the apu regs, need + to power it up */ + maestro_power(card,ACPI_D0); - if(s->dev_audio == -1) - continue; - - M_printk("maestro: stopping apus for device %d\n",i); - stop_dac(s); - stop_adc(s); - for(j=0;j<6;j++) - card->apu_map[s->apu[j]][5]=apu_get_register(s,j,5); - - } + for(i=0;ichannels[i]; - /* get rid of interrupts? */ - if( card->dsps_open > 0) - stop_bob(&card->channels[0]); + if(s->dev_audio == -1) + continue; - in_suspend=1; + M_printk("maestro: stopping apus for device %d\n",i); + stop_dac(s); + stop_adc(s); + for(j=0;j<6;j++) + card->apu_map[s->apu[j]][5]=apu_get_register(s,j,5); - restore_flags(flags); + } + + /* get rid of interrupts? */ + if( card->dsps_open > 0) + stop_bob(&card->channels[0]); - /* we'll let the bios do the rest of the power down.. */ + card->in_suspend++; + restore_flags(flags); + + /* we trust in the bios to power down the chip on suspend. + * XXX I'm also not sure that in_suspend will protect + * against all reg accesses from here on out. + */ return 0; } static int maestro_resume(struct ess_card *card) { unsigned long flags; - int i; + int i; save_flags(flags); - cli(); - in_suspend=0; - M_printk("maestro: resuming\n"); - - /* first lets just bring everything back. .*/ - - M_printk("maestro: pm in dev %p\n",card); - - maestro_config(card); - /* need to restore the base pointers.. */ - if(card->dmapages) - set_base_registers(&card->channels[0],card->dmapages); - - mixer_push_state(card); - - for(i=0;ichannels[i]; - int chan,reg; - - if(s->dev_audio == -1) - continue; - - for(chan = 0 ; chan < 6 ; chan++) { - wave_set_register(s,s->apu[chan]<<3,s->apu_base[chan]); - for(reg = 1 ; reg < NR_APU_REGS ; reg++) - apu_set_register(s,chan,reg,s->card->apu_map[s->apu[chan]][reg]); - } - for(chan = 0 ; chan < 6 ; chan++) - apu_set_register(s,chan,0,s->card->apu_map[s->apu[chan]][0] & 0xFF0F); - } + cli(); /* over-kill */ + + card->in_suspend = 0; + + M_printk("maestro: resuming card at %p\n",card); + + /* restore all our config */ + maestro_config(card); + /* need to restore the base pointers.. */ + if(card->dmapages) + set_base_registers(&card->channels[0],card->dmapages); + + mixer_push_state(card); + + /* set each channels' apu control registers before + * restoring audio + */ + for(i=0;ichannels[i]; + int chan,reg; + + if(s->dev_audio == -1) + continue; + + for(chan = 0 ; chan < 6 ; chan++) { + wave_set_register(s,s->apu[chan]<<3,s->apu_base[chan]); + for(reg = 1 ; reg < NR_APU_REGS ; reg++) + apu_set_register(s,chan,reg,s->card->apu_map[s->apu[chan]][reg]); + } + for(chan = 0 ; chan < 6 ; chan++) + apu_set_register(s,chan,0,s->card->apu_map[s->apu[chan]][0] & 0xFF0F); + } /* now we flip on the music */ - M_printk("maestro: pm in dev %p\n",card); - for(i=0;ichannels[i]; - - /* these use the apu_mode, and can handle - spurious calls */ - start_dac(s); - start_adc(s); - } - if( card->dsps_open > 0) - start_bob(&card->channels[0]); + if( card->dsps_open <= 0) { + /* this card's idle */ + maestro_power(card,ACPI_D2); + } else { + /* ok, we're actually playing things on + this card */ + maestro_power(card,ACPI_D0); + start_bob(&card->channels[0]); + for(i=0;ichannels[i]; + + /* these use the apu_mode, and can handle + spurious calls */ + start_dac(s); + start_adc(s); + } + } restore_flags(flags); - wake_up(&suspend_queue); + /* all right, we think things are ready, + wake up people who were using the device + when we suspended */ + wake_up(&(card->suspend_queue)); return 0; } int -maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) { - struct ess_card *card = (struct ess_card*) dev->data; - if (card) { - M_printk("maestro: pm event received: 0x%x\n", rqst); - - switch (rqst) { - case PM_SUSPEND: - maestro_suspend(card); - break; - case PM_RESUME: - maestro_resume(card); - break; - } - } +maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + struct ess_card *card = (struct ess_card*) dev->data; + + if ( ! card ) goto out; + M_printk("maestro: pm event 0x%x received for card %p\n", rqst, card); + + switch (rqst) { + case PM_SUSPEND: + maestro_suspend(card); + break; + case PM_RESUME: + maestro_resume(card); + break; + /* + * we'd also like to find out about + * power level changes because some biosen + * do mean things to the maestro when they + * change their power state. + */ + } +out: return 0; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v2.3.99-pre5/linux/drivers/sound/midibuf.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/midibuf.c Fri Apr 21 13:28:34 2000 @@ -394,6 +394,7 @@ } } +/* No kernel lock - fine */ unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait) { unsigned int mask = 0; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.3.99-pre5/linux/drivers/sound/sb_card.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/sb_card.c Fri Apr 14 10:09:51 2000 @@ -10,7 +10,6 @@ * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * - * * 26-11-1999 Patched to compile without ISA PnP support in the * kernel - Daniel Stone (tamriel@ductape.net) * @@ -37,6 +36,10 @@ * 26-03-2000 Fixed acer, esstype and sm_games module options. * Alessandro Zummo * + * 12-04-2000 ISAPnP cleanup, reorg, fixes, and multiple card support. + * Thanks to Gaël Quéri and Alessandro Zummo for testing and fixes. + * Paul E. Laufer + * */ #include @@ -51,7 +54,14 @@ #include "sb_mixer.h" #include "sb.h" -static int sbmpu = 0; +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +#define SB_CARDS_MAX 4 +#else +#define SB_CARDS_MAX 1 +#endif + +static int sbmpu[SB_CARDS_MAX] = {0}; +static int sb_cards_num = 0; extern void *smw_free; @@ -75,7 +85,6 @@ { if(!sb_dsp_init(hw_config)) hw_config->slots[0] = -1; - SOUND_LOCK; } static int __init probe_sb(struct address_info *hw_config) @@ -84,7 +93,7 @@ if (hw_config->io_base == -1 || hw_config->dma == -1 || hw_config->irq == -1) { - printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n"); + printk(KERN_ERR "sb: I/O, IRQ, and DMA are mandatory\n"); return -EINVAL; } @@ -149,14 +158,6 @@ } #endif - /* This is useless since it is done by sb_dsp_detect - azummo */ - - if (check_region(hw_config->io_base, 16)) - { - printk(KERN_ERR "sb_card: I/O port 0x%x is already in use\n\n", hw_config->io_base); - return 0; - } - /* Setup extra module options */ sbmo.acer = acer; @@ -166,25 +167,33 @@ return sb_dsp_detect(hw_config, 0, 0, &sbmo); } -static void __exit unload_sb(struct address_info *hw_config) +static void __exit unload_sb(struct address_info *hw_config, int card) { if(hw_config->slots[0]!=-1) - sb_dsp_unload(hw_config, sbmpu); + sb_dsp_unload(hw_config, sbmpu[card]); } -static struct address_info cfg; -static struct address_info cfg_mpu; +static struct address_info cfg[SB_CARDS_MAX]; +static struct address_info cfg_mpu[SB_CARDS_MAX]; -struct pci_dev *sb_dev = NULL, - *mpu_dev = NULL; +struct pci_dev *sb_dev[SB_CARDS_MAX] = {NULL}, + *mpu_dev[SB_CARDS_MAX] = {NULL}, + *opl_dev[SB_CARDS_MAX] = {NULL}; #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE static int isapnp = 1; static int isapnpjump = 0; -static int activated = 1; +static int multiple = 0; +static int reverse = 0; +static int uart401 = 0; + +static int audio_activated[SB_CARDS_MAX] = {0}; +static int mpu_activated[SB_CARDS_MAX] = {0}; +static int opl_activated[SB_CARDS_MAX] = {0}; #else static int isapnp = 0; +static int multiple = 1; #endif MODULE_DESCRIPTION("Soundblaster driver"); @@ -202,8 +211,14 @@ #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE MODULE_PARM(isapnp, "i"); MODULE_PARM(isapnpjump, "i"); +MODULE_PARM(multiple, "i"); +MODULE_PARM(reverse, "i"); +MODULE_PARM(uart401, "i"); MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled"); MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); +MODULE_PARM_DESC(multiple, "When set to 0, will not search for multiple cards"); +MODULE_PARM_DESC(reverse, "When set to 1, will reverse ISAPnP search order"); +MODULE_PARM_DESC(uart401, "When set to 1, will attempt to detect and enable the mpu on some clones"); #endif MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); @@ -218,6 +233,211 @@ #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +/* Please add new entries at the end of the table */ +static struct { + char *name; + unsigned short card_vendor, card_device, + audio_vendor, audio_function, + mpu_vendor, mpu_function, + opl_vendor, opl_function; + short dma, dma2, mpu_io, mpu_irq; /* see sb_init() */ +} sb_isapnp_list[] __initdata = { + {"Sound Blaster 16", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0024), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster 16", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0026), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster 16", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0027), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster 16", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0029), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster 16", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster Vibra16S", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster Vibra16C", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0070), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster Vibra16CL", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0080), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster Vibra16X", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00F0), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0039), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0042), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0043), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0044), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0054), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009C), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 64", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009D), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 64 Gold", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009E), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 64", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C1), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 64", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C3), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 64", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C5), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 64", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C7), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 64", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00E4), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), + 0,0,0,0, + 0,1,1,-1}, + {"ESS 1868", + ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1868), + ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), + 0,0,0,0, + 0,1,2,-1}, + {"ESS 1868", + ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1868), + ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), + 0,0,0,0, + 0,1,2,-1}, + {"ESS 1869 PnP AudioDrive", + ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x0003), + ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), + 0,0,0,0, + 0,1,2,-1}, + {"ESS 1869", + ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1869), + ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), + 0,0,0,0, + 0,1,2,-1}, + {"ESS 1878", + ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1878), + ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), + 0,0,0,0, + 0,1,2,-1}, + {"ESS 1879", + ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1879), + ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), + 0,0,0,0, + 0,1,2,-1}, + {"CMI 8330 SoundPRO", + ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001), + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), + 0,1,0,-1}, + {"Diamond DT0197H", + ISAPNP_VENDOR('R','W','B'), ISAPNP_DEVICE(0x1688), + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), + 0,-1,0,0}, + {"ALS007", + ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0007), + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), + 0,-1,0,0}, + {"ALS100", + ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001), + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), + 1,0,0,0}, + {"ALS110", + ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0110), + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x1001), + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x1001), + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), + 1,0,0,0}, + {"ALS120", + ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0120), + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x2001), + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001), + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), + 1,0,0,0}, + {"ALS200", + ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0200), + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0020), + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0020), + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), + 1,0,0,0}, + {"RTL3000", + ISAPNP_VENDOR('R','T','L'), ISAPNP_DEVICE(0x3000), + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x2001), + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001), + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), + 1,0,0,0}, + {0} +}; + /* That's useful. */ #define show_base(devname, resname, resptr) printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, (resptr)->start) @@ -227,14 +447,10 @@ int err; /* Device already active? Let's use it */ - if(dev->active) - { - activated = 0; return(dev); - } - if((err = dev->activate(dev)) < 0) - { + + if((err = dev->activate(dev)) < 0) { printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", devname, resname, err); dev->deactivate(dev); @@ -244,320 +460,153 @@ return(dev); } -/* Card's specific initialization functions - */ - -static struct pci_dev *sb_init_generic(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) +static struct pci_dev *sb_init(struct pci_bus *bus, struct address_info *hw_config, struct address_info *mpu_config, int slot, int card) { - if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL))) - { - sb_dev->prepare(sb_dev); - - if((sb_dev = activate_dev("Soundblaster", "sb", sb_dev))) - { - hw_config->io_base = sb_dev->resource[0].start; - hw_config->irq = sb_dev->irq_resource[0].start; - hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = sb_dev->dma_resource[1].start; - mpu_config->io_base = sb_dev->resource[1].start; - } - } - return(sb_dev); -} -static struct pci_dev *sb_init_ess(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) -{ - if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL))) + /* Configure Audio device */ + if((sb_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].audio_vendor, sb_isapnp_list[slot].audio_function, NULL))) { - sb_dev->prepare(sb_dev); - - if((sb_dev = activate_dev("ESS", "sb", sb_dev))) - { - hw_config->io_base = sb_dev->resource[0].start; - hw_config->irq = sb_dev->irq_resource[0].start; - hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = sb_dev->dma_resource[1].start; - mpu_config->io_base = sb_dev->resource[2].start; + int ret; + ret = sb_dev[card]->prepare(sb_dev[card]); + /* If device is active, assume configured with /proc/isapnp + * and use anyway. Some other way to check this? */ + if(ret && ret != -EBUSY) { + printk(KERN_ERR "sb: ISAPnP found device that could not be autoconfigured.\n"); + return(NULL); } - } - return(sb_dev); -} - -static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) -{ - /* - * The CMI8330/C3D is a very 'stupid' chip... where did they get al those @@@ ? - * It's ISAPnP section is badly designed and has many flaws, i'll do my best - * to workaround them. I strongly suggest you to buy a real soundcard. - * The CMI8330 on my motherboard has also the bad habit to activate - * the rear channel of my amplifier instead of the front one. - */ - - /* @X@0001:Soundblaster. - */ - - if((sb_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) - { - sb_dev->prepare(sb_dev); + if(ret == -EBUSY) + audio_activated[card] = 1; - if((sb_dev = activate_dev("CMI8330", "sb", sb_dev))) + if((sb_dev[card] = activate_dev(sb_isapnp_list[slot].name, "sb", sb_dev[card]))) { - hw_config->io_base = sb_dev->resource[0].start; - hw_config->irq = sb_dev->irq_resource[0].start; - hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = sb_dev->dma_resource[1].start; + hw_config->io_base = sb_dev[card]->resource[0].start; + hw_config->irq = sb_dev[card]->irq_resource[0].start; + hw_config->dma = sb_dev[card]->dma_resource[sb_isapnp_list[slot].dma].start; + if(sb_isapnp_list[slot].dma2 != -1) + hw_config->dma2 = sb_dev[card]->dma_resource[sb_isapnp_list[slot].dma2].start; + else + hw_config->dma2 = -1; + } else + return(NULL); + } else + return(NULL); - show_base("CMI8330", "sb", &sb_dev->resource[0]); - } + /* Cards with separate OPL3 device (ALS, CMI, etc.) + * This is just to activate the device... */ + if(sb_isapnp_list[slot].opl_vendor || sb_isapnp_list[slot].opl_function) { + if((opl_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].opl_vendor, sb_isapnp_list[slot].opl_function, NULL))) { + int ret = opl_dev[card]->prepare(opl_dev[card]); + /* If device is active, assume configured with + * /proc/isapnp and use anyway */ + if(ret && ret != -EBUSY) { + printk(KERN_ERR "sb: OPL device could not be autoconfigured.\n"); + return(sb_dev[card]); + } + if(ret == -EBUSY) + opl_activated[card] = 1; - if(!sb_dev) return(NULL); + /* Some have irq and dma for opl. the opl3 driver wont + * use 'em so don't configure 'em and hope it works -PEL */ + opl_dev[card]->irq_resource[0].flags = 0; + opl_dev[card]->dma_resource[0].flags = 0; + + opl_dev[card] = activate_dev(sb_isapnp_list[slot].name, "opl3", opl_dev[card]); + } else + printk(KERN_ERR "sb: %s isapnp panic: opl3 device not found\n", sb_isapnp_list[slot].name); + } + + /* Cards with MPU as part of Audio device (CTL and ESS) */ + if(!sb_isapnp_list[slot].mpu_vendor) { + mpu_config->io_base = sb_dev[card]->resource[sb_isapnp_list[slot].mpu_io].start; + return(sb_dev[card]); } - else - printk(KERN_ERR "sb: CMI8330 panic: sb base not found\n"); - - /* @H@0001:mpu - */ - - if((mpu_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL))) - { - mpu_dev->prepare(mpu_dev); - - /* This disables the interrupt on this resource. Do we need it ? - */ - - mpu_dev->irq_resource[0].flags = 0; - - if((mpu_dev = activate_dev("CMI8330", "mpu", mpu_dev))) - { - show_base("CMI8330", "mpu", &mpu_dev->resource[0]); - mpu_config->io_base = mpu_dev->resource[0].start; + + /* Cards with separate MPU device (ALS, CMI, etc.) */ + if(!uart401) + return(sb_dev[card]); + if((mpu_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].mpu_vendor, sb_isapnp_list[slot].mpu_function, NULL))) + { + int ret = mpu_dev[card]->prepare(mpu_dev[card]); + /* If device is active, assume configured with /proc/isapnp + * and use anyway */ + if(ret && ret != -EBUSY) { + printk(KERN_ERR "sb: MPU device could not be autoconfigured.\n"); + return(sb_dev[card]); } - } - else - printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n"); - - printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo \n"); - - return(sb_dev); -} - -static struct pci_dev *sb_init_diamond(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) -{ - /* - * Diamonds DT0197H - * very similar to the CMI8330 above - */ - - /* @@@0001:Soundblaster. - */ - - if((sb_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) - { - sb_dev->prepare(sb_dev); + if(ret == -EBUSY) + mpu_activated[card] = 1; - if((sb_dev = activate_dev("DT0197H", "sb", sb_dev))) - { - hw_config->io_base = sb_dev->resource[0].start; - hw_config->irq = sb_dev->irq_resource[0].start; - hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = -1; - - show_base("DT0197H", "sb", &sb_dev->resource[0]); - } - - if(!sb_dev) return(NULL); - } - else - printk(KERN_ERR "sb: DT0197H panic: sb base not found\n"); - - /* @X@0001:mpu - */ - - if((mpu_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) - { - mpu_dev->prepare(mpu_dev); - - if((mpu_dev = activate_dev("DT0197H", "mpu", mpu_dev))) - { - show_base("DT0197H", "mpu", &mpu_dev->resource[0]); - mpu_config->io_base = mpu_dev->resource[0].start; - } - } - else - printk(KERN_ERR "sb: DT0197H panic: mpu not found\n"); - - printk(KERN_INFO "sb: DT0197H mail reports to Torsten Werner \n"); - - return(sb_dev); -} - -static struct pci_dev *sb_init_als(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) -{ - /* - * ALS100 - * very similar to both ones above above - */ - - /* @@@0001:Soundblaster. - */ - - if((sb_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) - { - sb_dev->prepare(sb_dev); + /* Some cards ask for irq but don't need them - azummo */ + if(sb_isapnp_list[slot].mpu_irq == -1) + mpu_dev[card]->irq_resource[0].flags = 0; - if((sb_dev = activate_dev("ALS100", "sb", sb_dev))) - { - hw_config->io_base = sb_dev->resource[0].start; - hw_config->irq = sb_dev->irq_resource[0].start; - hw_config->dma = sb_dev->dma_resource[1].start; - hw_config->dma2 = sb_dev->dma_resource[0].start; - - show_base("ALS100", "sb", &sb_dev->resource[0]); + if((mpu_dev[card] = activate_dev(sb_isapnp_list[slot].name, "mpu", mpu_dev[card]))) { + mpu_config->io_base = mpu_dev[card]->resource[sb_isapnp_list[slot].mpu_io].start; + if(sb_isapnp_list[slot].mpu_irq != -1) + mpu_config->irq = mpu_dev[card]->irq_resource[sb_isapnp_list[slot].mpu_irq].start; } - - if(!sb_dev) return(NULL); } else - printk(KERN_ERR "sb: ALS100 panic: sb base not found\n"); - - /* @X@0001:mpu - */ - - if((mpu_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) - { - mpu_dev->prepare(mpu_dev); - - if((mpu_dev = activate_dev("ALS100", "mpu", mpu_dev))) - { - show_base("ALS100", "mpu", &mpu_dev->resource[0]); - mpu_config->io_base = mpu_dev->resource[0].start; - } - } - else - printk(KERN_ERR "sb: ALS100 panic: mpu not found\n"); - - printk(KERN_INFO "sb: ALS100 mail reports to Torsten Werner \n"); - - return(sb_dev); + printk(KERN_ERR "sb: %s isapnp panic: mpu not found\n", sb_isapnp_list[slot].name); + + return(sb_dev[card]); } -#define SBF_DEV 0x01 /* Please notice that cards without this flag are on the top in the list */ - - -static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; } -sb_isapnp_list[] __initdata = { - {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" }, - {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0, &sb_init_diamond, "Diamond DT0197H" }, - {ISAPNP_VENDOR('A','L','S'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_als, "ALS 100" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), SBF_DEV, &sb_init_ess, "ESS 1688" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" }, - {0} -}; - -static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot) +static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, int slot, int card) { - struct pci_dev *idev = NULL; - - /* You missed the init func? That's bad. */ - if(sb_isapnp_list[slot].initfunc) - { - char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name; - - printk(KERN_INFO "sb: %s detected\n", busname); + char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name; - /* Initialize this baby. */ + printk(KERN_INFO "sb: %s detected\n", busname); - if((idev = sb_isapnp_list[slot].initfunc(bus, card, hw_config, mpu_config))) - { - /* We got it. */ + /* Initialize this baby. */ - printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n", - busname, - hw_config->io_base, hw_config->irq, hw_config->dma, - hw_config->dma2); - return 1; - } - else - printk(KERN_INFO "sb: Failed to initialize %s\n", busname); + if(sb_init(bus, hw_config, mpu_config, slot, card)) { + /* We got it. */ + + printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n", + busname, + hw_config->io_base, hw_config->irq, hw_config->dma, + hw_config->dma2); + return 1; } else - printk(KERN_ERR "sb: Bad entry in sb_card.c PnP table\n"); + printk(KERN_INFO "sb: Failed to initialize %s\n", busname); return 0; } -/* Actually this routine will detect and configure only the first card with successful - initialization. isapnpjump could be used to jump to a specific entry. - Please always add entries at the end of the array. - Should this be fixed? - azummo -*/ - -int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info *mpu_config) +int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info *mpu_config, int card) { + static int first = 1; int i; /* Count entries in sb_isapnp_list */ - for (i = 0; sb_isapnp_list[i].vendor != 0; i++); + for (i = 0; sb_isapnp_list[i].card_vendor != 0; i++); + i--; /* Check and adjust isapnpjump */ - if( isapnpjump < 0 || isapnpjump > ( i - 1 ) ) - { - printk(KERN_ERR "sb: Valid range for isapnpjump is 0-%d. Adjusted to 0.\n", i-1); - isapnpjump = 0; + if( isapnpjump < 0 || isapnpjump > i) { + isapnpjump = reverse ? i : 0; + printk(KERN_ERR "sb: Valid range for isapnpjump is 0-%d. Adjusted to %d.\n", i, isapnpjump); } - - for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) { - if(!(sb_isapnp_list[i].flags & SBF_DEV)) - { - struct pci_bus *bus = NULL; - - while ((bus = isapnp_find_card( - sb_isapnp_list[i].vendor, - sb_isapnp_list[i].function, - bus))) { + if(!first || !reverse) + i = isapnpjump; + first = 0; + while(sb_isapnp_list[i].card_vendor != 0) { + static struct pci_bus *bus = NULL; + + while ((bus = isapnp_find_card( + sb_isapnp_list[i].card_vendor, + sb_isapnp_list[i].card_device, + bus))) { - if(sb_isapnp_init(hw_config, mpu_config, bus, NULL, i)) - return 0; - } - } - } - - /* No cards found. I'll try now to search inside every card for a logical device - * that matches any entry marked with SBF_DEV in the table. - */ - - for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) { - - if(sb_isapnp_list[i].flags & SBF_DEV) - { - struct pci_dev *card = NULL; - - while ((card = isapnp_find_dev(NULL, - sb_isapnp_list[i].vendor, - sb_isapnp_list[i].function, - card))) { - - if(sb_isapnp_init(hw_config, mpu_config, card->bus, card, i)) - return 0; + if(sb_isapnp_init(hw_config, mpu_config, bus, i, card)) { + isapnpjump = i; /* start next search from here */ + return 0; } } + i += reverse ? -1 : 1; } return -ENODEV; @@ -566,62 +615,80 @@ static int __init init_sb(void) { - printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + int card, max = multiple ? SB_CARDS_MAX : 1; - /* Please remember that even with CONFIG_ISAPNP defined one should still be - able to disable PNP support for this single driver! - */ - -#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE - if(isapnp && (sb_isapnp_probe(&cfg, &cfg_mpu) < 0) ) { - printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n"); - isapnp = 0; - } + printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + + for(card = 0; card < max; card++, sb_cards_num++) { +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + /* Please remember that even with CONFIG_ISAPNP defined one + * should still be able to disable PNP support for this + * single driver! */ + if(isapnp && (sb_isapnp_probe(&cfg[card], &cfg_mpu[card], card) < 0) ) { + if(!sb_cards_num) { + printk(KERN_NOTICE "sb: No ISAPnP cards found, trying standard ones...\n"); + isapnp = 0; + } else + break; + } #endif - if( isapnp == 0 ) { - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma16; - } + if(!isapnp) { + cfg[card].io_base = io; + cfg[card].irq = irq; + cfg[card].dma = dma; + cfg[card].dma2 = dma16; + } - cfg.card_subtype = type; + cfg[card].card_subtype = type; - if (!probe_sb(&cfg)) - return -ENODEV; - attach_sb_card(&cfg); + if (!probe_sb(&cfg[card])) + return -ENODEV; + attach_sb_card(&cfg[card]); - if(cfg.slots[0]==-1) - return -ENODEV; + if(cfg[card].slots[0]==-1) + return -ENODEV; - if (isapnp == 0) - cfg_mpu.io_base = mpu_io; - if (probe_sbmpu(&cfg_mpu)) - sbmpu = 1; - if (sbmpu) - attach_sbmpu(&cfg_mpu); + if (!isapnp) + cfg_mpu[card].io_base = mpu_io; + if (probe_sbmpu(&cfg_mpu[card])) + sbmpu[card] = 1; + if (sbmpu[card]) + attach_sbmpu(&cfg_mpu[card]); + } + + SOUND_LOCK; + + if(isapnp) + printk(KERN_NOTICE "sb: %d Soundblaster PnP card(s) found.\n", sb_cards_num); + return 0; } static void __exit cleanup_sb(void) { + int i; + if (smw_free) { vfree(smw_free); smw_free = NULL; } - unload_sb(&cfg); - if (sbmpu) - unload_sbmpu(&cfg_mpu); - SOUND_LOCK_END; -#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE - if(activated) - { - if(sb_dev) sb_dev->deactivate(sb_dev); - if(mpu_dev) mpu_dev->deactivate(mpu_dev); - } + for(i = 0; i < sb_cards_num; i++) { + unload_sb(&cfg[i], i); + if (sbmpu[i]) + unload_sbmpu(&cfg_mpu[i]); + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if(!audio_activated[i] && sb_dev[i]) + sb_dev[i]->deactivate(sb_dev[i]); + if(!mpu_activated[i] && mpu_dev[i]) + mpu_dev[i]->deactivate(mpu_dev[i]); + if(!opl_activated[i] && opl_dev[i]) + opl_dev[i]->deactivate(opl_dev[i]); #endif + } + SOUND_LOCK_END; } module_init(init_sb); @@ -630,7 +697,7 @@ #ifndef MODULE static int __init setup_sb(char *str) { - /* io, irq, dma, dma2 */ + /* io, irq, dma, dma2 - just the basics */ int ints[5]; str = get_options(str, ARRAY_SIZE(ints), ints); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.3.99-pre5/linux/drivers/sound/sb_common.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/sb_common.c Tue Apr 11 19:13:15 2000 @@ -1258,7 +1258,8 @@ return 0; } hw_config->name = "Sound Blaster 16"; - hw_config->irq = -devc->irq; + if (hw_config->irq < 3 || hw_config->irq == devc->irq) + hw_config->irq = -devc->irq; if (devc->minor > 12) /* What is Vibra's version??? */ sb16_set_mpu_port(devc, hw_config); break; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.3.99-pre5/linux/drivers/sound/sequencer.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/sequencer.c Fri Apr 21 13:29:03 2000 @@ -1561,6 +1561,7 @@ return put_user(val, (int *)arg); } +/* No kernel lock - we're using the global irq lock here */ unsigned int sequencer_poll(int dev, struct file *file, poll_table * wait) { unsigned long flags; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.3.99-pre5/linux/drivers/sound/sonicvibes.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/sound/sonicvibes.c Fri Apr 21 13:29:35 2000 @@ -1475,6 +1475,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int sv_poll(struct file *file, struct poll_table_struct *wait) { struct sv_state *s = (struct sv_state *)file->private_data; @@ -2069,6 +2070,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int sv_midi_poll(struct file *file, struct poll_table_struct *wait) { struct sv_state *s = (struct sv_state *)file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- v2.3.99-pre5/linux/drivers/sound/sound_core.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/sound_core.c Wed Apr 12 09:47:28 2000 @@ -370,10 +370,11 @@ /** * unregister_sound_special - unregister a special sound device - * @unit: Unit number to allocate + * @unit: unit number to allocate * - * Release a sound device that was allocated with register_sound_special. - * The unit passed is the return value from the register function. + * Release a sound device that was allocated with + * register_sound_special(). The unit passed is the return value from + * the register function. */ @@ -386,9 +387,9 @@ /** * unregister_sound_mixer - unregister a mixer - * @unit: Unit number to allocate + * @unit: unit number to allocate * - * Release a sound device that was allocated with register_sound_mixer. + * Release a sound device that was allocated with register_sound_mixer(). * The unit passed is the return value from the register function. */ @@ -401,9 +402,9 @@ /** * unregister_sound_midi - unregister a midi device - * @unit: Unit number to allocate + * @unit: unit number to allocate * - * Release a sound device that was allocated with register_sound_midi. + * Release a sound device that was allocated with register_sound_midi(). * The unit passed is the return value from the register function. */ @@ -416,9 +417,9 @@ /** * unregister_sound_dsp - unregister a DSP device - * @unit: Unit number to allocate + * @unit: unit number to allocate * - * Release a sound device that was allocated with register_sound_dsp. + * Release a sound device that was allocated with register_sound_dsp(). * The unit passed is the return value from the register function. * * Both of the allocated units are released together automatically. @@ -434,9 +435,9 @@ /** * unregister_sound_synth - unregister a synth device - * @unit: Unit number to allocate + * @unit: unit number to allocate * - * Release a sound device that was allocated with register_sound_synth. + * Release a sound device that was allocated with register_sound_synth(). * The unit passed is the return value from the register function. */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.3.99-pre5/linux/drivers/sound/soundcard.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/soundcard.c Wed Apr 12 09:47:28 2000 @@ -605,7 +605,7 @@ static void destroy_special_devices(void) { - unregister_sound_special(6); + unregister_sound_special(1); unregister_sound_special(8); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.3.99-pre5/linux/drivers/sound/trident.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/sound/trident.c Mon Apr 24 13:39:34 2000 @@ -29,6 +29,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.14.2 Mar 29 2000 Ching Ling Lee + * Add clear to silence advance in trident_update_ptr + * fix invalid data of the end of the sound + * v0.14.1 Mar 24 2000 Ching Ling Lee + * ALi 5451 support added, playback and recording O.K. + * ALi 5451 originally developed and structured based on sonicvibes, and + * suggested to merge into this file by Alan Cox. * v0.14 Mar 15 2000 Ollie Lho * 5.1 channel output support with channel binding. What's the Matrix ? * v0.13.1 Mar 10 2000 Ollie Lho @@ -74,6 +81,7 @@ * new pci device driver interface for 2.4 kernel (done) */ +#include #include #include #include @@ -127,13 +135,15 @@ enum { TRIDENT_4D_DX = 0, TRIDENT_4D_NX, - SIS_7018 + SIS_7018, + ALI_5451 }; static char * card_names[] = { "Trident 4DWave DX", "Trident 4DWave NX", - "SiS 7018 PCI Audio" + "SiS 7018 PCI Audio", + "ALi Audio Accelerator" }; static struct pci_device_id trident_pci_tbl [] __initdata = { @@ -143,6 +153,9 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_NX}, {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7018}, + {PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5451, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI_5451}, + {0,} }; MODULE_DEVICE_TABLE (pci, trident_pci_tbl); @@ -170,7 +183,7 @@ /* hardware channel */ struct trident_channel *channel; - /* OSS buffer manangemeent stuff */ + /* OSS buffer management stuff */ void *rawbuf; dma_addr_t dma_handle; unsigned buforder; @@ -194,6 +207,8 @@ /* OSS stuff */ unsigned mapped:1; unsigned ready:1; + unsigned endcleared:1; + unsigned update_flag; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; @@ -252,6 +267,7 @@ /* PCI device stuff */ struct pci_dev * pci_dev; u16 pci_id; + u8 revision; /* soundcore stuff */ int dev_audio; @@ -264,6 +280,12 @@ /* hardware resources */ unsigned long iobase; u32 irq; + + /* Function support */ + struct trident_channel *(*alloc_pcm_channel)(struct trident_card *); + struct trident_channel *(*alloc_rec_pcm_channel)(struct trident_card *); + void (*free_pcm_channel)(struct trident_card *, int chan); + void (*address_interrupt)(struct trident_card *); }; /* table to map from CHANNELMASK to channel attribute for SiS 7018 */ @@ -281,6 +303,9 @@ static struct trident_card *devs = NULL; +static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val); +static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg); + static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val); static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg); @@ -301,6 +326,7 @@ case PCI_DEVICE_ID_SI_7018: global_control |= (ENDLP_IE | MIDLP_IE| BANK_B_EN); break; + case PCI_DEVICE_ID_ALI_5451: case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: global_control |= (ENDLP_IE | MIDLP_IE); @@ -463,6 +489,46 @@ return NULL; } +static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card) +{ + struct trident_pcm_bank *bank; + int idx; + + bank = &card->banks[BANK_A]; + + if (bank->bitmap == ~0UL) { + /* no more free channels avaliable */ + printk(KERN_ERR "trident: no more channels available on Bank B.\n"); + return NULL; + } + for (idx = 0; idx <= 31; idx++) { + if (!(bank->bitmap & (1 << idx))) { + struct trident_channel *channel = &bank->channels[idx]; + bank->bitmap |= 1 << idx; + channel->num = idx; + return channel; + } + } + return NULL; +} + +static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card) +{ + struct trident_pcm_bank *bank; + int idx = ALI_PCM_IN_CHANNEL; + + bank = &card->banks[BANK_A]; + + if (!(bank->bitmap & (1 << idx))) { + struct trident_channel *channel = &bank->channels[idx]; + bank->bitmap |= 1 << idx; + channel->num = idx; + return channel; + } + return NULL; +} + + static void trident_free_pcm_channel(struct trident_card *card, int channel) { int bank; @@ -478,7 +544,24 @@ } } +static void ali_free_pcm_channel(struct trident_card *card, int channel) +{ + int bank; + + if (channel > 31) + return; + + bank = channel >> 5; + channel = channel & 0x1f; + + if (card->banks[bank].bitmap & (1 << (channel))) { + card->banks[bank].bitmap &= ~(1 << (channel)); + } +} + + /* called with spin lock held */ + static int trident_load_channel_registers(struct trident_card *card, u32 *data, unsigned int channel) { int i; @@ -491,6 +574,9 @@ /* output the channel registers */ for (i = 0; i < CHANNEL_REGS; i++) { outl(data[i], TRID_REG(card, CHANNEL_START + 4*i)); + if (i == 2) + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) + i++; //skip i=3 } return TRUE; @@ -509,6 +595,11 @@ switch (state->card->pci_id) { + case PCI_DEVICE_ID_ALI_5451: + data[0] = 0; /* Current Sample Offset */ + data[2] = (channel->eso << 16) | (channel->delta & 0xffff); + data[3] = 0; + break; case PCI_DEVICE_ID_SI_7018: data[0] = 0; /* Current Sample Offset */ data[2] = (channel->eso << 16) | (channel->delta & 0xffff); @@ -654,6 +745,7 @@ /* Enable AC-97 ADC (capture) */ switch (card->pci_id) { + case PCI_DEVICE_ID_ALI_5451: case PCI_DEVICE_ID_SI_7018: /* for 7018, the ac97 is always in playback/record (duplex) mode */ break; @@ -717,6 +809,7 @@ switch (state->card->pci_id) { + case PCI_DEVICE_ID_ALI_5451: case PCI_DEVICE_ID_SI_7018: case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: /* 16 bits ESO, CSO for 7018 and DX */ @@ -1029,8 +1122,11 @@ static void trident_update_ptr(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; - unsigned hwptr; + unsigned hwptr, swptr; + int clear_cnt = 0; int diff; + unsigned char silence; + unsigned half_dmasize; /* update hardware pointer */ hwptr = trident_get_dma_addr(state); @@ -1054,6 +1150,31 @@ __stop_adc(state); dmabuf->error++; } + else if (!dmabuf->endcleared) { + swptr = dmabuf->swptr; + silence = (dmabuf->fmt & TRIDENT_FMT_16BIT ? 0 : 0x80); + if (dmabuf->update_flag & ALI_ADDRESS_INT_UPDATE) { + /* We must clear end data of 1/2 dmabuf if needed. + According to 1/2 algorithm of Address Engine Interrupt, + check the validation of the data of half dmasize. */ + half_dmasize = dmabuf->dmasize / 2; + if ((diff = hwptr - half_dmasize) < 0 ) + diff = hwptr; + if ((dmabuf->count + diff) < half_dmasize) { + //there is invalid data in the end of half buffer + if ((clear_cnt = half_dmasize - swptr) < 0) + clear_cnt += half_dmasize; + memset (dmabuf->rawbuf + swptr, silence, clear_cnt); //clear the invalid data + dmabuf->endcleared = 1; + } + } else if (dmabuf->count < (signed) dmabuf->fragsize) { + clear_cnt = dmabuf->fragsize; + if ((swptr + clear_cnt) > dmabuf->dmasize) + clear_cnt = dmabuf->dmasize - swptr; + memset (dmabuf->rawbuf + swptr, silence, clear_cnt); + dmabuf->endcleared = 1; + } + } /* since dma machine only interrupts at ESO and ESO/2, we sure have at least half of dma buffer free, so wake up the process unconditionally */ wake_up(&dmabuf->wait); @@ -1080,13 +1201,54 @@ wake_up(&dmabuf->wait); } } + dmabuf->update_flag &= ~ALI_ADDRESS_INT_UPDATE; } -static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void trident_address_interrupt(struct trident_card *card) { + int i; struct trident_state *state; - struct trident_card *card = (struct trident_card *)dev_id; + + /* Update the pointers for all channels we are running. */ + /* FIXME: should read interrupt status only once */ + for (i = 0; i < NR_HW_CH; i++) { + if (trident_check_channel_interrupt(card, 63 - i)) { + trident_ack_channel_interrupt(card, 63 - i); + if ((state = card->states[i]) != NULL) { + trident_update_ptr(state); + } else { + printk("trident: spurious channel irq %d.\n", + 63 - i); + trident_stop_voice(card, 63 - i); + trident_disable_voice_irq(card, 63 - i); + } + } + } +} + +static void ali_address_interrupt(struct trident_card *card) +{ int i; + struct trident_state *state; + + for (i = 0; i < NR_HW_CH; i++) { + if (trident_check_channel_interrupt(card, i)) { + trident_ack_channel_interrupt(card, i); + if ((state = card->states[i]) != NULL) { + state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE; + trident_update_ptr(state); + } else { + printk("ali: spurious channel irq %d.\n", i); + trident_stop_voice(card, i); + trident_disable_voice_irq(card, i); + } + } + } +} + +static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct trident_card *card = (struct trident_card *)dev_id; u32 event; spin_lock(&card->lock); @@ -1097,21 +1259,7 @@ #endif if (event & ADDRESS_IRQ) { - /* Update the pointers for all channels we are running. */ - /* FIXME: should read interrupt status only once */ - for (i = 0; i < NR_HW_CH; i++) { - if (trident_check_channel_interrupt(card, 63 - i)) { - trident_ack_channel_interrupt(card, 63 - i); - if ((state = card->states[i]) != NULL) { - trident_update_ptr(state); - } else { - printk("trident: spurious channel irq %d.\n", - 63 - i); - trident_stop_voice(card, 63 - i); - trident_disable_voice_irq(card, 63 - i); - } - } - } + card->address_interrupt(card); } /* manually clear interrupt status, bad hardware design, blame T^2 */ @@ -1151,6 +1299,9 @@ return -EFAULT; ret = 0; + if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) + outl ( inl (TRID_REG (state->card, ALI_GLOBAL_CONTROL)) | ALI_PCM_IN_ENABLE, TRID_REG (state->card, ALI_GLOBAL_CONTROL)); + while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); if (dmabuf->count > (signed) dmabuf->dmasize) { @@ -1250,6 +1401,10 @@ return -EFAULT; ret = 0; + if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) + if (dmabuf->channel->num == ALI_PCM_IN_CHANNEL) + outl ( inl (TRID_REG (state->card, ALI_GLOBAL_CONTROL)) & ALI_PCM_IN_DISABLE, TRID_REG (state->card, ALI_GLOBAL_CONTROL)); + while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); if (dmabuf->count < 0) { @@ -1312,6 +1467,7 @@ spin_lock_irqsave(&state->card->lock, flags); dmabuf->swptr = swptr; dmabuf->count += cnt; + dmabuf->endcleared = 0; spin_unlock_irqrestore(&state->card->lock, flags); count -= cnt; @@ -1322,6 +1478,7 @@ return ret; } +/* No kernel lock - we have our own spinlock */ static unsigned int trident_poll(struct file *file, struct poll_table_struct *wait) { struct trident_state *state = (struct trident_state *)file->private_data; @@ -1733,7 +1890,12 @@ found_virt: /* found a free virtual channel, allocate hardware channels */ - if ((dmabuf->channel = trident_alloc_pcm_channel(card)) == NULL) { + if(file->f_mode & FMODE_READ) + dmabuf->channel = card->alloc_rec_pcm_channel(card); + else + dmabuf->channel = card->alloc_pcm_channel(card); + + if (dmabuf->channel == NULL) { kfree (card->states[i]); card->states[i] = NULL;; return -ENODEV; @@ -1767,7 +1929,12 @@ } if (file->f_mode & FMODE_READ) { - /* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample, + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { + card->states[ALI_PCM_IN_CHANNEL] = state; + card->states[i] = NULL; + state->virt = ALI_PCM_IN_CHANNEL; + } + /* FIXME: Trident 4d can only record in signed 16-bits stereo, 48kHz sample, to be dealed with in trident_set_adc_rate() ?? */ dmabuf->fmt &= ~TRIDENT_FMT_MASK; if ((minor & 0x0f) == SND_DEV_DSP16) @@ -1809,12 +1976,12 @@ if (file->f_mode & FMODE_WRITE) { stop_dac(state); dealloc_dmabuf(state); - trident_free_pcm_channel(state->card, dmabuf->channel->num); + state->card->free_pcm_channel(state->card, dmabuf->channel->num); } if (file->f_mode & FMODE_READ) { stop_adc(state); dealloc_dmabuf(state); - trident_free_pcm_channel(state->card, dmabuf->channel->num); + state->card->free_pcm_channel(state->card, dmabuf->channel->num); } kfree(state->card->states[state->virt]); @@ -1944,6 +2111,101 @@ return ((u16) (data >> 16)); } +/* Write AC97 codec registers for ALi*/ +static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) +{ + struct trident_card *card = (struct trident_card *)codec->private_data; + unsigned int address, mask; + unsigned int wCount1 = 0xffff; + unsigned int wCount2= 0xffff; + unsigned long chk1, chk2; + unsigned long flags; + u32 data; + + data = ((u32) val) << 16; + + address = ALI_AC97_WRITE; + mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY; + if (codec->id) + mask |= ALI_AC97_SECONDARY; + if (card->revision == 0x02) + mask |= ALI_AC97_WRITE_MIXER_REGISTER; + + spin_lock_irqsave(&card->lock, flags); + while (wCount1--) { + if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_WRITE) == 0) { + data |= (mask | (reg & AC97_REG_ADDR)); + + chk1 = inl(TRID_REG(card, ALI_STIMER)); + chk2 = inl(TRID_REG(card, ALI_STIMER)); + while (wCount2-- && (chk1 == chk2)) + chk2 = inl(TRID_REG(card, ALI_STIMER)); + if (wCount2 == 0) { + spin_unlock_irqrestore(&card->lock, flags); + return; + } + outl(data, TRID_REG(card, address)); //write! + spin_unlock_irqrestore(&card->lock, flags); + return; //success + } + inw(TRID_REG(card, address)); //wait a read cycle + } + + printk(KERN_ERR "ali: AC97 CODEC write timed out.\n"); + spin_unlock_irqrestore(&card->lock, flags); + return; +} + +/* Read AC97 codec registers for ALi*/ +static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg) +{ + struct trident_card *card = (struct trident_card *)codec->private_data; + unsigned int address, mask; + unsigned int wCount1 = 0xffff; + unsigned int wCount2= 0xffff; + unsigned long chk1, chk2; + unsigned long flags; + u32 data; + + address = ALI_AC97_READ; + if (card->revision == 0x02) { + address = ALI_AC97_WRITE; + mask &= ALI_AC97_READ_MIXER_REGISTER; + } + mask = ALI_AC97_READ_ACTION | ALI_AC97_AUDIO_BUSY; + if (codec->id) + mask |= ALI_AC97_SECONDARY; + + spin_lock_irqsave(&card->lock, flags); + data = (mask | (reg & AC97_REG_ADDR)); + while (wCount1--) { + if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_READ) == 0) { + chk1 = inl(TRID_REG(card, ALI_STIMER)); + chk2 = inl(TRID_REG(card, ALI_STIMER)); + while (wCount2-- && (chk1 == chk2)) + chk2 = inl(TRID_REG(card, ALI_STIMER)); + if (wCount2 == 0) { + printk(KERN_ERR "ali: AC97 CODEC read timed out.\n"); + spin_unlock_irqrestore(&card->lock, flags); + return 0; + } + outl(data, TRID_REG(card, address)); //read! + wCount2 = 0xffff; + while (wCount2--) { + if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_READ) == 0) { + data = inl(TRID_REG(card, address)); + spin_unlock_irqrestore(&card->lock, flags); + return ((u16) (data >> 16)); + } + } + } + inw(TRID_REG(card, address)); //wait a read cycle + } + spin_unlock_irqrestore(&card->lock, flags); + printk(KERN_ERR "ali: AC97 CODEC read timed out.\n"); + return 0; +} + /* OSS /dev/mixer file operation methods */ static int trident_open_mixdev(struct inode *inode, struct file *file) { @@ -1999,6 +2261,11 @@ really exist */ switch (card->pci_id) { + case PCI_DEVICE_ID_ALI_5451: + outl(PCMOUT|SECONDARY_ID, TRID_REG(card, SI_SERIAL_INTF_CTRL)); + ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL)); + ready_2nd &= SI_AC97_SECONDARY_READY; + break; case PCI_DEVICE_ID_SI_7018: /* disable AC97 GPIO interrupt */ outl(0x00, TRID_REG(card, SI_AC97_GPIO)); @@ -2032,10 +2299,16 @@ in ac97_probe_codec */ codec->private_data = card; codec->id = num_ac97; - /* controller specific low level AC97 access function */ - codec->codec_read = trident_ac97_get; - codec->codec_write = trident_ac97_set; + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { + codec->codec_read = ali_ac97_get; + codec->codec_write = ali_ac97_set; + } + else { + codec->codec_read = trident_ac97_get; + codec->codec_write = trident_ac97_set; + } + if (ac97_probe_codec(codec) == 0) break; @@ -2061,12 +2334,14 @@ { unsigned long iobase; struct trident_card *card; + u8 revision; if (!pci_dma_supported(pci_dev, TRIDENT_DMA_MASK)) { printk(KERN_ERR "trident: architecture does not support" " 30bit PCI busmaster DMA\n"); return -ENODEV; } + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); iobase = pci_dev->resource[0].start; if (check_region(iobase, 256)) { @@ -2084,6 +2359,7 @@ card->iobase = iobase; card->pci_dev = pci_dev; card->pci_id = pci_id->device; + card->revision = revision; card->irq = pci_dev->irq; card->next = devs; card->magic = TRIDENT_CARD_MAGIC; @@ -2100,6 +2376,20 @@ printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->iobase, card->irq); + if(card->pci_id == PCI_DEVICE_ID_ALI_5451) + { + card->alloc_pcm_channel = ali_alloc_pcm_channel; + card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel; + card->free_pcm_channel = ali_free_pcm_channel; + card->address_interrupt = ali_address_interrupt; + } + else + { + card->alloc_pcm_channel = trident_alloc_pcm_channel; + card->alloc_rec_pcm_channel = trident_alloc_pcm_channel; + card->free_pcm_channel = trident_free_pcm_channel; + card->address_interrupt = trident_address_interrupt; + } /* claim our iospace and irq */ request_region(card->iobase, 256, card_names[pci_id->driver_data]); if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, @@ -2111,7 +2401,7 @@ } /* register /dev/dsp */ if ((card->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0) { - printk(KERN_ERR "trident: coundn't register DSP device!\n"); + printk(KERN_ERR "trident: couldn't register DSP device!\n"); release_region(iobase, 256); free_irq(card->irq, card); kfree(card); @@ -2127,6 +2417,16 @@ } outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL)); + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) + { + /* edited by HMSEO for GT sound */ +#ifdef CONFIG_ALPHA_NAUTILUS + ac97_data = trident_ac97_get (card->ac97_codec[0], AC97_POWER_CONTROL); + trident_ac97_set (card->ac97_codec[0], AC97_POWER_CONTROL, ac97_data | ALI_EAPD_POWER_DOWN); +#endif + /* edited by HMSEO for GT sound*/ + } + pci_dev->driver_data = card; pci_dev->dma_mask = TRIDENT_DMA_MASK; @@ -2145,12 +2445,12 @@ trident_disable_loop_interrupts(card); /* free hardware resources */ - free_irq(card->irq, devs); + free_irq(card->irq, card); release_region(card->iobase, 256); /* unregister audio devices */ for (i = 0; i < NR_AC97; i++) - if (devs->ac97_codec[i] != NULL) { + if (card->ac97_codec[i] != NULL) { unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); kfree (card->ac97_codec[i]); } @@ -2159,8 +2459,8 @@ kfree(card); } -MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho"); -MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver"); +MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho, Ching Ling Lee"); +MODULE_DESCRIPTION("Trident 4DWave/SiS 7018/ALi 5451 PCI Audio Driver"); #define TRIDENT_MODULE_NAME "trident" @@ -2176,7 +2476,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version " + printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451 PCI Audio, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); if (!pci_register_driver(&trident_pci_driver)) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/trident.h linux/drivers/sound/trident.h --- v2.3.99-pre5/linux/drivers/sound/trident.h Sun Mar 19 18:35:30 2000 +++ linux/drivers/sound/trident.h Wed Apr 12 09:47:28 2000 @@ -32,6 +32,10 @@ #define PCI_VENDOR_ID_SI 0x0139 #endif +#ifndef PCI_VENDOR_ID_ALI +#define PCI_VENDOR_ID_ALI 0x10b9 +#endif + #ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_DX #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 #endif @@ -44,6 +48,10 @@ #define PCI_DEVICE_ID_SI_7018 0x7018 #endif +#ifndef PCI_DEVICE_ID_ALI_5451 +#define PCI_DEVICE_ID_ALI_5451 0x5451 +#endif + #ifndef FALSE #define FALSE 0 #define TRUE 1 @@ -81,6 +89,28 @@ T4D_AINT_B = 0xd8, T4D_AINTEN_B = 0xdc }; +enum ali_op_registers { + ALI_GLOBAL_CONTROL = 0xd4, + ALI_STIMER = 0xc8 +}; + +enum ali_global_control_bit { + ALI_PCM_IN_ENABLE = 0x80000000, + ALI_PCM_IN_DISABLE = 0x7fffffff +}; + +enum ali_pcm_in_channel_num { + ALI_PCM_IN_CHANNEL = 31 +}; + +enum ali_ac97_power_control_bit { + ALI_EAPD_POWER_DOWN = 0x8000 +}; + +enum ali_update_ptr_flags { + ALI_ADDRESS_INT_UPDATE = 0x01 +}; + /* S/PDIF Operational Registers for 4D-NX */ enum nx_spdif_registers { NX_SPCTRL_SPCSO = 0x24, NX_SPLBA = 0x28, @@ -113,8 +143,20 @@ SI_SERIAL_INTF_CTRL = 0x48, SI_AC97_GPIO = 0x4c }; +enum ali_ac97_registers { + ALI_AC97_WRITE = 0x40, ALI_AC97_READ = 0x44 +}; + /* Bit mask for operational registers */ #define AC97_REG_ADDR 0x000000ff + +enum ali_ac97_bits { + ALI_AC97_BUSY_WRITE = 0x8000, ALI_AC97_BUSY_READ = 0x8000, + ALI_AC97_WRITE_ACTION = 0x8000, ALI_AC97_READ_ACTION = 0x8000, + ALI_AC97_AUDIO_BUSY = 0x4000, ALI_AC97_SECONDARY = 0x0080, + ALI_AC97_READ_MIXER_REGISTER = 0xfeff, + ALI_AC97_WRITE_MIXER_REGISTER = 0x0100 +}; enum sis7018_ac97_bits { SI_AC97_BUSY_WRITE = 0x8000, SI_AC97_BUSY_READ = 0x8000, diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c --- v2.3.99-pre5/linux/drivers/sound/vidc.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/vidc.c Tue Apr 25 17:38:33 2000 @@ -84,7 +84,7 @@ static void vidc_mksound(unsigned int hz, unsigned int ticks) { - printk("BEEP - %d %d!\n", hz, ticks); +// printk("BEEP - %d %d!\n", hz, ticks); } static void diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/vwsnd.c linux/drivers/sound/vwsnd.c --- v2.3.99-pre5/linux/drivers/sound/vwsnd.c Thu Feb 10 17:11:14 2000 +++ linux/drivers/sound/vwsnd.c Fri Apr 21 13:30:35 2000 @@ -2409,6 +2409,7 @@ return ret; } +/* No kernel lock - fine */ static unsigned int vwsnd_audio_poll(struct file *file, struct poll_table_struct *wait) { diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.3.99-pre5/linux/drivers/usb/Config.in Tue Apr 11 15:09:19 2000 +++ linux/drivers/usb/Config.in Fri Apr 21 14:03:01 2000 @@ -33,6 +33,7 @@ bool ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO bool ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA + bool ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET fi bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG fi diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.3.99-pre5/linux/drivers/usb/acm.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/usb/acm.c Fri Apr 21 14:02:49 2000 @@ -52,10 +52,6 @@ #define DEBUG #include -void tty_register_devfs (struct tty_driver *driver, unsigned int flags, - unsigned minor); -void tty_unregister_devfs (struct tty_driver *driver, unsigned minor); - /* * CMSPAR, some architectures can't have space and mark parity. */ @@ -261,7 +257,8 @@ if (urb->status) dbg("nonzero write bulk status received: %d", urb->status); - queue_task(&acm->tqueue, &tq_scheduler); + queue_task(&acm->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); } static void acm_softint(void *private) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/audio.c linux/drivers/usb/audio.c --- v2.3.99-pre5/linux/drivers/usb/audio.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/usb/audio.c Fri Apr 21 13:20:39 2000 @@ -2108,6 +2108,7 @@ return ret; } +/* Called without the kernel lock - fine */ static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait) { struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c --- v2.3.99-pre5/linux/drivers/usb/dc2xx.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/usb/dc2xx.c Tue Apr 25 17:38:33 2000 @@ -109,8 +109,8 @@ struct camera_state { struct usb_device *dev; /* USB device handle */ - char inEP; /* read endpoint */ - char outEP; /* write endpoint */ + int inEP; /* read endpoint */ + int outEP; /* write endpoint */ const struct camera *info; /* DC-240, etc */ int subminor; /* which minor dev #? */ int isActive; /* I/O taking place? */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/devices.c linux/drivers/usb/devices.c --- v2.3.99-pre5/linux/drivers/usb/devices.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/devices.c Wed Apr 26 15:22:55 2000 @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -452,11 +453,13 @@ return ret; } +/* Kernel lock for "lastev" protection */ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait) { struct usb_device_status *st = (struct usb_device_status *)file->private_data; unsigned int mask = 0; - + + lock_kernel(); if (!st) { st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL); if (!st) @@ -475,6 +478,7 @@ if (st->lastev != conndiscevcnt) mask |= POLLIN; st->lastev = conndiscevcnt; + unlock_kernel(); return mask; } @@ -494,7 +498,7 @@ return 0; } -static long long usb_device_lseek(struct file * file, long long offset, int orig) +static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig) { switch (orig) { case 0: diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/devio.c linux/drivers/usb/devio.c --- v2.3.99-pre5/linux/drivers/usb/devio.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/devio.c Wed Apr 26 15:22:55 2000 @@ -162,7 +162,7 @@ return ret; } -static long long usbdev_lseek(struct file *file, long long offset, int orig) +static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) { switch (orig) { case 0: @@ -989,6 +989,7 @@ return ret; } +/* No kernel lock - fine */ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait) { struct dev_state *ps = (struct dev_state *)file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/drivers.c linux/drivers/usb/drivers.c --- v2.3.99-pre5/linux/drivers/usb/drivers.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/drivers.c Wed Apr 26 15:22:55 2000 @@ -94,7 +94,7 @@ return ret; } -static long long usb_driver_lseek(struct file * file, long long offset, int orig) +static loff_t usb_driver_lseek(struct file * file, loff_t offset, int orig) { switch (orig) { case 0: diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/dsbr100.c linux/drivers/usb/dsbr100.c --- v2.3.99-pre5/linux/drivers/usb/dsbr100.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/usb/dsbr100.c Mon Apr 24 16:20:52 2000 @@ -15,7 +15,7 @@ You might find some interesting stuff about this module at http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr - Copyright (c) 2000 Markus Demleitner + Copyright (c) 2000 Markus Demleitner 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 @@ -33,9 +33,12 @@ History: + Version 0.22: + Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, + thanks to Mike Cox for pointing the problem out. + Version 0.21: - Markus Demleitner : - Minor cleanup, warnings if something goes wrong, lame attempt + Markus: Minor cleanup, warnings if something goes wrong, lame attempt to adhere to Documentation/CodingStyle Version 0.2: @@ -212,13 +215,14 @@ return -EFAULT; if(v.tuner) /* Only 1 tuner */ return -EINVAL; - v.rangelow=(87*16000); - v.rangehigh=(108*16000); - /*v.flags=VIDEO_TUNER_LOW;*/ - v.mode=VIDEO_MODE_AUTO; - v.signal=radio->stereo; - v.flags|=VIDEO_TUNER_STEREO_ON; - strcpy(v.name, "FM"); + v.rangelow = 87*16; + v.rangehigh = 108*16; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = radio->stereo*0x7000; + /* Don't know how to get signal strength */ + v.flags |= VIDEO_TUNER_STEREO_ON*radio->stereo; + strcpy(v.name, "DSB R-100"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; return 0; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/evdev.c linux/drivers/usb/evdev.c --- v2.3.99-pre5/linux/drivers/usb/evdev.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/evdev.c Fri Apr 21 13:22:23 2000 @@ -192,6 +192,7 @@ return retval; } +/* No kernel lock - fine */ static unsigned int evdev_poll(struct file *file, poll_table *wait) { struct evdev_list *list = file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/joydev.c linux/drivers/usb/joydev.c --- v2.3.99-pre5/linux/drivers/usb/joydev.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/joydev.c Fri Apr 21 13:22:42 2000 @@ -308,6 +308,7 @@ return retval; } +/* No kernel lock - fine */ static unsigned int joydev_poll(struct file *file, poll_table *wait) { struct joydev_list *list = file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c --- v2.3.99-pre5/linux/drivers/usb/keybdev.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/keybdev.c Wed Apr 26 14:53:39 2000 @@ -36,7 +36,7 @@ #include #include -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) +#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) static int x86_sysrq_alt = 0; @@ -102,7 +102,7 @@ 76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117, 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 }; -static int emulate_raw(unsigned int code, unsigned char upflag) +static int emulate_raw(unsigned int keycode, int down) { if (keycode > 127 || !mac_keycodes[keycode]) return -1; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c --- v2.3.99-pre5/linux/drivers/usb/mdc800.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/mdc800.c Tue Apr 25 17:38:33 2000 @@ -30,6 +30,12 @@ * * The driver supports only one camera. * + * version 0.7.3 + * bugfix : The mdc800->state field gets set to READY after the + * the diconnect function sets it to NOT_CONNECTED. This makes the + * driver running like the camera is connected and causes some + * hang ups. + * * version 0.7.1 * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload * problems when compiled as Module. @@ -73,20 +79,20 @@ #include -#define VERSION "0.7.1" -#define RELEASE_DATE "(26/03/2000)" +#define VERSION "0.7.3" +#define RELEASE_DATE "(24/04/2000)" /* Vendor and Product Information */ #define MDC800_VENDOR_ID 0x055f #define MDC800_PRODUCT_ID 0xa800 /* Timeouts (msec) */ -#define TO_READ_FROM_IRQ 4000 -#define TO_GET_READY 2000 -#define TO_DOWNLOAD_GET_READY 1500 -#define TO_DOWNLOAD_GET_BUSY 1500 -#define TO_WRITE_GET_READY 3000 +#define TO_DOWNLOAD_GET_READY 1500 +#define TO_DOWNLOAD_GET_BUSY 1500 +#define TO_WRITE_GET_READY 1000 #define TO_DEFAULT_COMMAND 5000 +#define TO_READ_FROM_IRQ TO_DEFAULT_COMMAND +#define TO_GET_READY TO_DEFAULT_COMMAND /* Minor Number of the device (create with mknod /dev/mustek c 180 32) */ #define MDC800_DEVICE_MINOR_BASE 32 @@ -114,7 +120,7 @@ wait_queue_head_t irq_wait; char* irq_urb_buffer; - int camera_busy; // is camera busy ? + int camera_busy; // is camera busy ? int camera_request_ready; // Status to synchronize with irq char camera_response [8]; // last Bytes send after busy @@ -130,9 +136,9 @@ /* Device Data */ - char out [64]; // Answer Buffer + char out [64]; // Answer Buffer int out_ptr; // Index to the first not readen byte - int out_count; // Bytes in the buffer + int out_count; // Bytes in the buffer int open; // Camera device open ? int rw_lock; // Block read <-> write @@ -284,9 +290,17 @@ { mdc800->camera_request_ready=0; err ("timeout waiting for camera."); - return 0; + return -1; } - return 1; + + if (mdc800->state == NOT_CONNECTED) + { + warn ("Camera gets disconnected during waiting for irq."); + mdc800->camera_request_ready=0; + return -2; + } + + return 0; } @@ -301,7 +315,10 @@ { err ("writing command fails (status=%i)", urb->status); } - mdc800->state=READY; + else + { + mdc800->state=READY; + } wake_up_interruptible (&mdc800->write_wait); } @@ -328,7 +345,6 @@ else { err ("request bytes fails (status:%i)", urb->status); - mdc800->state=READY; } wake_up_interruptible (&mdc800->download_wait); } @@ -351,17 +367,18 @@ dbg ("(mdc800_usb_probe) called."); - if (mdc800->dev != 0) - { - warn ("only one Mustek MDC800 is supported."); - return 0; - } if (dev->descriptor.idVendor != MDC800_VENDOR_ID) return 0; if (dev->descriptor.idProduct != MDC800_PRODUCT_ID) return 0; + if (mdc800->dev != 0) + { + warn ("only one Mustek MDC800 is supported."); + return 0; + } + if (dev->descriptor.bNumConfigurations != 1) { err ("probe fails -> wrong Number of Configuration"); @@ -416,6 +433,8 @@ mdc800->dev=dev; mdc800->state=READY; + mdc800->open=0; + mdc800->rw_lock=0; /* Setup URB Structs */ FILL_INT_URB ( @@ -464,10 +483,8 @@ if (mdc800->state == NOT_CONNECTED) return; - + mdc800->state=NOT_CONNECTED; - mdc800->open=0; - mdc800->rw_lock=0; usb_unlink_urb (mdc800->irq_urb); usb_unlink_urb (mdc800->write_urb); @@ -599,6 +616,12 @@ if (mdc800->state == NOT_CONNECTED) return -EBUSY; + if (mdc800->state == WORKING) + { + warn ("Illegal State \"working\" reached during read ?!"); + return -EBUSY; + } + if (!mdc800->open || mdc800->rw_lock) return -EBUSY; mdc800->rw_lock=1; @@ -624,15 +647,13 @@ if (usb_submit_urb (mdc800->download_urb)) { err ("Can't submit download urb (status=%i)",mdc800->download_urb->status); - mdc800->state=READY; mdc800->rw_lock=0; return len-left; } interruptible_sleep_on_timeout (&mdc800->download_wait, TO_DOWNLOAD_GET_READY*HZ/1000); if (mdc800->download_urb->status != 0) { - err ("requesting bytes fails (status=%i)",mdc800->download_urb->status); - mdc800->state=READY; + err ("request download-bytes fails (status=%i)",mdc800->download_urb->status); mdc800->rw_lock=0; return len-left; } @@ -710,7 +731,12 @@ { int answersize; - mdc800_usb_waitForIRQ (0,TO_GET_READY); + if (mdc800_usb_waitForIRQ (0,TO_GET_READY)) + { + err ("Camera didn't get ready.\n"); + mdc800->rw_lock=0; + return -EIO; + } answersize=mdc800_getAnswerSize (mdc800->in[1]); @@ -720,14 +746,12 @@ { err ("submitting write urb fails (status=%i)", mdc800->write_urb->status); mdc800->rw_lock=0; - mdc800->state=READY; return -EIO; } - interruptible_sleep_on_timeout (&mdc800->write_wait, TO_DEFAULT_COMMAND*HZ/1000); + interruptible_sleep_on_timeout (&mdc800->write_wait, TO_WRITE_GET_READY*HZ/1000); if (mdc800->state == WORKING) { usb_unlink_urb (mdc800->write_urb); - mdc800->state=READY; mdc800->rw_lock=0; return -EIO; } @@ -756,10 +780,9 @@ if (answersize) { - if (!mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ)) + if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ)) { err ("requesting answer from irq fails"); - mdc800->state=READY; mdc800->rw_lock=0; return -EIO; } @@ -785,11 +808,10 @@ } else { - if (!mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND)) + if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND)) { err ("Command Timeout."); mdc800->rw_lock=0; - mdc800->state=READY; return -EIO; } } @@ -811,21 +833,10 @@ /* File Operations of this drivers */ static struct file_operations mdc800_device_ops = { - 0, /* llseek */ - mdc800_device_read, - mdc800_device_write, - 0, /* readdir */ - 0, /* poll */ - 0, /* ioctl, this can be used to detect USB ! */ - 0, /* mmap */ - mdc800_device_open, - 0, /* flush */ - mdc800_device_release, - 0, /* async */ - 0, /* fasync */ - 0, /* check_media_change */ -// 0, /* revalidate */ -// 0 /* lock */ + read: mdc800_device_read, + write: mdc800_device_write, + open: mdc800_device_open, + release: mdc800_device_release, }; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/mousedev.c linux/drivers/usb/mousedev.c --- v2.3.99-pre5/linux/drivers/usb/mousedev.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/mousedev.c Fri Apr 21 13:22:59 2000 @@ -39,11 +39,11 @@ #include #include -#ifndef CONFIG_MOUSEDEV_SCREEN_X -#define CONFIG_MOUSEDEV_SCREEN_X 1024 +#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X +#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 #endif -#ifndef CONFIG_MOUSEDEV_SCREEN_Y -#define CONFIG_MOUSEDEV_SCREEN_Y 768 +#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y +#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 #endif struct mousedev { @@ -93,12 +93,12 @@ switch (code) { case ABS_X: size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; - list->dx += (value * CONFIG_MOUSEDEV_SCREEN_X - list->oldx) / size; + list->dx += (value * CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size; list->oldx += list->dx * size; break; case ABS_Y: size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; - list->dy -= (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size; + list->dy -= (value * CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size; list->oldy -= list->dy * size; break; } @@ -365,6 +365,7 @@ return count; } +/* No kernel lock - fine */ static unsigned int mousedev_poll(struct file *file, poll_table *wait) { struct mousedev_list *list = file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.3.99-pre5/linux/drivers/usb/printer.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/printer.c Fri Apr 21 13:23:13 2000 @@ -198,6 +198,7 @@ return 0; } +/* No kernel lock - fine */ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait) { struct usblp *usblp = file->private_data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/rio500.c linux/drivers/usb/rio500.c --- v2.3.99-pre5/linux/drivers/usb/rio500.c Fri Mar 10 16:40:45 2000 +++ linux/drivers/usb/rio500.c Mon Apr 24 16:15:01 2000 @@ -44,7 +44,7 @@ /* stall/wait timeout for rio */ #define NAK_TIMEOUT (HZ) -#define IBUF_SIZE 128 +#define IBUF_SIZE 0x1000 /* Size of the rio buffer */ #define OBUF_SIZE 0x10000 @@ -317,7 +317,7 @@ result = usb_bulk_msg(rio->rio_dev, usb_rcvbulkpipe(rio->rio_dev, 1), ibuf, this_read, &partial, - (int) (HZ * .1)); + (int) (HZ * 8)); dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u", result, this_read, partial); @@ -405,18 +405,11 @@ static struct file_operations usb_rio_fops = { - NULL, /* seek */ - read_rio, - write_rio, - NULL, /* readdir */ - NULL, /* poll */ - ioctl_rio, /* ioctl */ - NULL, /* mmap */ - open_rio, - NULL, /* flush */ - close_rio, - NULL, - NULL, /* fasync */ + read: read_rio, + write: write_rio, + ioctl: ioctl_rio, + open: open_rio, + release: close_rio, }; static struct diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile --- v2.3.99-pre5/linux/drivers/usb/serial/Makefile Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/serial/Makefile Fri Apr 21 14:03:01 2000 @@ -4,7 +4,7 @@ O_TARGET := usb-serial.o M_OBJS := usb-serial.o -O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o +O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o omninet.o MOD_LIST_NAME := USB_SERIAL_MODULES include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c --- v2.3.99-pre5/linux/drivers/usb/serial/ftdi_sio.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/serial/ftdi_sio.c Thu Apr 13 08:59:54 2000 @@ -153,7 +153,7 @@ /* do some startup allocations not currently performed by usb_serial_probe() */ static int ftdi_sio_startup (struct usb_serial *serial) { - init_waitqueue_head(&serial->write_wait); + init_waitqueue_head(&serial->port[0].write_wait); return (0); } @@ -291,7 +291,7 @@ /* Was seeing a race here, got a read callback, then write callback before hitting interuptible_sleep_on - so wrapping in add_wait_queue stuff */ - add_wait_queue(&serial->write_wait, &wait); + add_wait_queue(&port->write_wait, &wait); set_current_state (TASK_INTERRUPTIBLE); while (port->write_urb->status == -EINPROGRESS) { dbg("ftdi_sio - write in progress - retrying"); @@ -301,13 +301,13 @@ } if (signal_pending(current)) { current->state = TASK_RUNNING; - remove_wait_queue(&serial->write_wait, &wait); + remove_wait_queue(&port->write_wait, &wait); rc = -ERESTARTSYS; goto err; } schedule(); } - remove_wait_queue(&serial->write_wait, &wait); + remove_wait_queue(&port->write_wait, &wait); set_current_state(TASK_RUNNING); count += data_offset; @@ -388,7 +388,7 @@ return; } - wake_up_interruptible(&serial->write_wait); + wake_up_interruptible(&port->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c --- v2.3.99-pre5/linux/drivers/usb/serial/keyspan_pda.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/serial/keyspan_pda.c Thu Apr 13 08:59:54 2000 @@ -52,78 +52,20 @@ #include "usb-serial.h" +struct keyspan_pda_private { + int tx_room; + int tx_throttled; +}; + #define KEYSPAN_VENDOR_ID 0x06cd #define KEYSPAN_PDA_FAKE_ID 0x0103 #define KEYSPAN_PDA_ID 0x0104 /* no clue */ -/* function prototypes for a Keyspan PDA serial converter */ -static int keyspan_pda_open (struct usb_serial_port *port, - struct file *filp); -static void keyspan_pda_close (struct usb_serial_port *port, - struct file *filp); -static int keyspan_pda_startup (struct usb_serial *serial); -static void keyspan_pda_rx_throttle (struct usb_serial_port *port); -static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port); -static int keyspan_pda_setbaud (struct usb_serial *serial, int baud); -static int keyspan_pda_write_room (struct usb_serial_port *port); -static int keyspan_pda_write (struct usb_serial_port *port, - int from_user, - const unsigned char *buf, - int count); -static void keyspan_pda_write_bulk_callback (struct urb *urb); -static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port); -static int keyspan_pda_ioctl (struct usb_serial_port *port, - struct file *file, - unsigned int cmd, - unsigned long arg); -static void keyspan_pda_set_termios (struct usb_serial_port *port, - struct termios *old); -static void keyspan_pda_break_ctl (struct usb_serial_port *port, - int break_state); -static int keyspan_pda_fake_startup (struct usb_serial *serial); - - /* All of the device info needed for the Keyspan PDA serial converter */ static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID; static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID; static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID; -struct usb_serial_device_type keyspan_pda_fake_device = { - name: "Keyspan PDA - (prerenumeration)", - idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */ - idProduct: &keyspan_pda_fake_product_id, /* the Keyspan PDA initial product id */ - needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ - needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ - needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 1, - startup: keyspan_pda_fake_startup -}; -struct usb_serial_device_type keyspan_pda_device = { - name: "Keyspan PDA", - idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */ - idProduct: &keyspan_pda_product_id, /* the Keyspan PDA product id */ - needs_interrupt_in: MUST_HAVE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: MUST_HAVE, - num_interrupt_in: 1, - num_bulk_in: 0, - num_bulk_out: 1, - num_ports: 1, - open: keyspan_pda_open, - close: keyspan_pda_close, - write: keyspan_pda_write, - write_room: keyspan_pda_write_room, - write_bulk_callback: keyspan_pda_write_bulk_callback, - chars_in_buffer: keyspan_pda_chars_in_buffer, - throttle: keyspan_pda_rx_throttle, - unthrottle: keyspan_pda_rx_unthrottle, - startup: keyspan_pda_startup, - ioctl: keyspan_pda_ioctl, - set_termios: keyspan_pda_set_termios, - break_ctl: keyspan_pda_break_ctl, -}; + static void keyspan_pda_rx_interrupt (struct urb *urb) @@ -133,6 +75,8 @@ struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int i; + struct keyspan_pda_private *priv; + priv = (struct keyspan_pda_private *)(port->private); /* the urb might have been killed. */ if (urb->status) @@ -167,8 +111,8 @@ break; case 2: /* tx unthrottle interrupt */ tty = serial->port[0].tty; - serial->tx_throttled = 0; - wake_up(&serial->write_wait); /* wake up writer */ + priv->tx_throttled = 0; + wake_up(&port->write_wait); /* wake up writer */ wake_up(&tty->write_wait); /* them too */ break; default: @@ -193,7 +137,7 @@ upon the device too. */ dbg("keyspan_pda_rx_throttle port %d", port->number); - usb_unlink_urb(port->read_urb); + usb_unlink_urb(port->interrupt_in_urb); } @@ -201,7 +145,7 @@ { /* just restart the receive interrupt URB */ dbg("keyspan_pda_rx_unthrottle port %d", port->number); - if (usb_submit_urb(port->read_urb)) + if (usb_submit_urb(port->interrupt_in_urb)) dbg(" usb_submit_urb(read urb) failed"); return; } @@ -409,8 +353,10 @@ struct usb_serial *serial = port->serial; int request_unthrottle = 0; int rc = 0; + struct keyspan_pda_private *priv; DECLARE_WAITQUEUE(wait, current); + priv = (struct keyspan_pda_private *)(port->private); /* guess how much room is left in the device's ring buffer, and if we want to send more than that, check first, updating our notion of what is left. If our write will result in no room left, ask the @@ -419,7 +365,7 @@ select() or poll() too) until we receive that unthrottle interrupt. Block if we can't write anything at all, otherwise write as much as we can. */ - + dbg("keyspan_pda_write(%d)",count); if (count == 0) { dbg(" write request of 0 bytes"); return (0); @@ -434,7 +380,7 @@ rc = -EAGAIN; goto err; } - interruptible_sleep_on(&serial->write_wait); + interruptible_sleep_on(&port->write_wait); if (signal_pending(current)) { rc = -ERESTARTSYS; goto err; @@ -451,16 +397,16 @@ have to be careful to avoid a race that would cause us to sleep forever. */ - add_wait_queue(&serial->write_wait, &wait); + add_wait_queue(&port->write_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); - while (serial->tx_throttled) { + while (priv->tx_throttled) { /* device can't accomodate any more characters. Sleep until it can. Woken up by an Rx interrupt message, which clears tx_throttled first. */ dbg(" tx_throttled, going to sleep"); if (signal_pending(current)) { current->state = TASK_RUNNING; - remove_wait_queue(&serial->write_wait, &wait); + remove_wait_queue(&port->write_wait, &wait); dbg(" woke up because of signal"); rc = -ERESTARTSYS; goto err; @@ -468,11 +414,11 @@ schedule(); dbg(" woke up"); } - remove_wait_queue(&serial->write_wait, &wait); + remove_wait_queue(&port->write_wait, &wait); set_current_state(TASK_RUNNING); count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - if (count > serial->tx_room) { + if (count > priv->tx_room) { unsigned char room; /* Looks like we might overrun the Tx buffer. Ask the device how much room it really has */ @@ -495,15 +441,15 @@ return -EIO; /* device didn't return any data */ } dbg(" roomquery says %d", room); - serial->tx_room = room; - if (count > serial->tx_room) { + priv->tx_room = room; + if (count > priv->tx_room) { /* we're about to completely fill the Tx buffer, so we'll be throttled afterwards. */ - count = serial->tx_room; + count = priv->tx_room; request_unthrottle = 1; } } - serial->tx_room -= count; + priv->tx_room -= count; if (count) { /* now transfer data */ @@ -529,7 +475,7 @@ dbg(" request_unthrottle"); /* ask the device to tell us when the tx buffer becomes sufficiently empty */ - serial->tx_throttled = 1; /* block writers */ + priv->tx_throttled = 1; /* block writers */ rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 7, /* request_unthrottle */ @@ -563,7 +509,7 @@ return; } - wake_up_interruptible(&serial->write_wait); + wake_up_interruptible(&port->write_wait); tty = port->tty; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && @@ -576,23 +522,25 @@ static int keyspan_pda_write_room (struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; + struct keyspan_pda_private *priv; + priv = (struct keyspan_pda_private *)(port->private); /* used by n_tty.c for processing of tabs and such. Giving it our conservative guess is probably good enough, but needs testing by running a console through the device. */ - return (serial->tx_room); + return (priv->tx_room); } static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; + struct keyspan_pda_private *priv; + priv = (struct keyspan_pda_private *)(port->private); /* when throttled, return at least WAKEUP_CHARS to tell select() (via n_tty.c:normal_poll() ) that we're not writeable. */ - if (serial->tx_throttled) + if (priv->tx_throttled) return 256; return 0; } @@ -603,6 +551,8 @@ struct usb_serial *serial = port->serial; unsigned char room; int rc; + struct keyspan_pda_private *priv; + priv = (struct keyspan_pda_private *)(port->private); if (port->active) { return -EINVAL; @@ -627,8 +577,8 @@ dbg(" roomquery returned 0 bytes"); return -EIO; /* device didn't return any data */ } - serial->tx_room = room; - serial->tx_throttled = room ? 0 : 1; + priv->tx_room = room; + priv->tx_throttled = room ? 0 : 1; /* the normal serial device seems to always turn on DTR and RTS here, so do the same */ @@ -638,7 +588,7 @@ keyspan_pda_set_modem_info(serial, 0); /*Start reading from the device*/ - if (usb_submit_urb(port->read_urb)) + if (usb_submit_urb(port->interrupt_in_urb)) dbg(" usb_submit_urb(read int) failed"); return (0); @@ -655,7 +605,7 @@ /* shutdown our bulk reads and writes */ usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); + usb_unlink_urb (port->interrupt_in_urb); port->active = 0; } @@ -691,27 +641,63 @@ return (1); } - -/* do some startup allocations not currently performed by usb_serial_probe() */ static int keyspan_pda_startup (struct usb_serial *serial) { - struct usb_endpoint_descriptor *intin; - intin = serial->port[0].interrupt_in_endpoint; + /* allocate the private data structures for all ports. Well, for all + one ports. */ - /* set up the receive interrupt urb */ - FILL_INT_URB(serial->port[0].read_urb, serial->dev, - usb_rcvintpipe(serial->dev, intin->bEndpointAddress), - serial->port[0].interrupt_in_buffer, - intin->wMaxPacketSize, - keyspan_pda_rx_interrupt, - serial, - intin->bInterval); - - init_waitqueue_head(&serial->write_wait); - + serial->port[0].private = kmalloc(sizeof(struct keyspan_pda_private), + GFP_KERNEL); + if (!serial->port[0].private) + return (1); /* error */ + init_waitqueue_head(&serial->port[0].write_wait); return (0); } -#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */ +static void keyspan_pda_shutdown (struct usb_serial *serial) +{ + kfree(serial->port[0].private); +} +struct usb_serial_device_type keyspan_pda_fake_device = { + name: "Keyspan PDA - (prerenumeration)", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_pda_fake_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 1, + startup: keyspan_pda_fake_startup, +}; +struct usb_serial_device_type keyspan_pda_device = { + name: "Keyspan PDA", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_pda_product_id, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 0, + num_bulk_out: 1, + num_ports: 1, + open: keyspan_pda_open, + close: keyspan_pda_close, + write: keyspan_pda_write, + write_room: keyspan_pda_write_room, + write_bulk_callback: keyspan_pda_write_bulk_callback, + read_int_callback: keyspan_pda_rx_interrupt, + chars_in_buffer: keyspan_pda_chars_in_buffer, + throttle: keyspan_pda_rx_throttle, + unthrottle: keyspan_pda_rx_unthrottle, + ioctl: keyspan_pda_ioctl, + set_termios: keyspan_pda_set_termios, + break_ctl: keyspan_pda_break_ctl, + startup: keyspan_pda_startup, + shutdown: keyspan_pda_shutdown, +}; + +#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c --- v2.3.99-pre5/linux/drivers/usb/serial/omninet.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/omninet.c Fri Apr 21 14:03:01 2000 @@ -0,0 +1,339 @@ +/* + * USB ZyXEL omni.net LCD PLUS driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * See Documentation/usb/usb-serial.txt for more information on using this driver + * + */ + +#include + +#ifdef CONFIG_USB_SERIAL_OMNINET + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CONFIG_USB_SERIAL_DEBUG + #define isalpha(x) ( ( x > 96 && x < 123) || ( x > 64 && x < 91) || (x > 47 && x < 58) ) + #define DEBUG +#else + #undef DEBUG +#endif + +#include + +#include "usb-serial.h" + + +#define ZYXEL_VENDOR_ID 0x0586 +#define ZYXEL_OMNINET_ID 0x1000 + +/* function prototypes */ +static int omninet_open (struct usb_serial_port *port, struct file *filp); +static void omninet_close (struct usb_serial_port *port, struct file *filp); +static void omninet_read_bulk_callback (struct urb *urb); +static void omninet_write_bulk_callback (struct urb *urb); +static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); +static int omninet_write_room (struct usb_serial_port *port); + +/* All of the device info needed for the omni.net */ +static __u16 zyxel_vendor_id = ZYXEL_VENDOR_ID; +static __u16 zyxel_omninet_product_id = ZYXEL_OMNINET_ID; + +struct usb_serial_device_type zyxel_omninet_device = { + name: "ZyXEL - omni.net lcd plus usb", + idVendor: &zyxel_vendor_id, + idProduct: &zyxel_omninet_product_id, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 2, + num_ports: 1, + open: omninet_open, + close: omninet_close, + write: omninet_write, + write_room: omninet_write_room, + read_bulk_callback: omninet_read_bulk_callback, + write_bulk_callback: omninet_write_bulk_callback, +}; + + +/* The protocol. + * + * The omni.net always exchange 64 bytes of data with the host. The first + * four bytes are the control header, you can see it in the above structure. + * + * oh_seq is a sequence number. Don't know if/how it's used. + * oh_len is the length of the data bytes in the packet. + * oh_xxx Bit-mapped, related to handshaking and status info. + * I normally set it to 0x03 in trasmitted frames. + * 7: Active when the TA is in a CONNECTed state. + * 6: unknown + * 5: handshaking, unknown + * 4: handshaking, unknown + * 3: unknown, usually 0 + * 2: unknown, usually 0 + * 1: handshaking, unknown, usually set to 1 in trasmitted frames + * 0: handshaking, unknown, usually set to 1 in trasmitted frames + * oh_pad Probably a pad byte. + * + * After the header you will find data bytes if oh_len was greater than zero. + * + */ + +struct omninet_header +{ + __u8 oh_seq; + __u8 oh_len; + __u8 oh_xxx; + __u8 oh_pad; +}; + +struct omninet_data +{ + __u8 od_outseq; // Sequence number for bulk_out URBs +}; + +static int omninet_open (struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + struct usb_serial_port *wport = &serial->port[1]; + struct omninet_data *od; + + dbg("omninet_open port %d", port->number); + + if (port->active) { + dbg ("device already open"); + return -EINVAL; + } + port->active = 1; + + od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); + + if( !od ) + { + err("omninet_open: kmalloc(%d) failed.", sizeof(struct omninet_data)); + return -ENOMEM; + } + + port->private = od; + + /* Start reading from the device */ + if (usb_submit_urb(port->read_urb)) + dbg("usb_submit_urb(read bulk, %p) failed", port->read_urb); + + wport->tty = port->tty; + + return (0); +} + +static void omninet_close (struct usb_serial_port *port, struct file * filp) +{ + struct usb_serial *serial = port->serial; + struct usb_serial_port *wport = &serial->port[1]; + struct omninet_data *od = (struct omninet_data *) port->private; + + port->active = 0; + + + dbg("zyxel_close port %d", port->number); + + usb_unlink_urb (wport->write_urb); + usb_unlink_urb (port->read_urb); + + if(od) kfree(od); +} + + +#define OMNINET_DATAOFFSET 0x04 +#define OMNINET_HEADERLEN sizeof(struct omninet_header) +#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN) + +static void omninet_read_bulk_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial = port->serial; + + unsigned char *data = urb->transfer_buffer; + struct omninet_header *header = (struct omninet_header *) &data[0]; + + int i; + +// dbg("omninet_read_bulk_callback"); + + if (port_paranoia_check (port, "omninet_read_bulk_callback")) { + return; + } + + if (serial_paranoia_check (serial, "omninet_read_bulk_callback")) { + return; + } + + if (urb->status) { + dbg("nonzero read bulk status received: %d", urb->status); + return; + } + +#ifdef DEBUG + if(header->oh_xxx != 0x30) + { + if (urb->actual_length) { + printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len); + for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) { + printk ("%.2x ", data[i]); + } + printk ("\n"); + } + } +#endif + + if (urb->actual_length && header->oh_len) + { + for (i = 0; i < header->oh_len; i++) { + tty_insert_flip_char(port->tty, data[OMNINET_DATAOFFSET + i], 0); + } + tty_flip_buffer_push(port->tty); + } + + /* Continue trying to always read */ + if (usb_submit_urb(urb)) + dbg("failed resubmitting read urb"); + + return; +} + +static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) +{ + struct usb_serial *serial = port->serial; + struct usb_serial_port *wport = &serial->port[1]; + + struct omninet_data *od = (struct omninet_data *) port->private; + struct omninet_header *header = (struct omninet_header *) wport->write_urb->transfer_buffer; +/* +#ifdef DEBUG + int i; +#endif +*/ + +// dbg("omninet_write port %d", port->number); + + if (count == 0) { + dbg("write request of 0 bytes"); + return (0); + } +/* +#ifdef DEBUG + printk (KERN_DEBUG __FILE__ ": omninet_write %d: ", count); + for (i = 0; i < count; i++) { + if( isalpha(buf[i]) ) + printk ("%c ", buf[i]); + else + printk ("%.2x ", buf[i]); + } + printk ("\n"); +#endif +*/ + if (wport->write_urb->status == -EINPROGRESS) { + dbg ("already writing"); + return (0); + } + + count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; + + if (from_user) { + copy_from_user(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count); + } + else { + memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count); + } + + + header->oh_seq = od->od_outseq++; + header->oh_len = count; + header->oh_xxx = 0x03; + header->oh_pad = 0x00; + + /* send the data out the bulk port, always 64 bytes */ + wport->write_urb->transfer_buffer_length = 64; + + if (usb_submit_urb(wport->write_urb)) + dbg("usb_submit_urb(write bulk) failed"); + +// dbg("omninet_write returns %d", count); + + return (count); +} + + +static int omninet_write_room (struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct usb_serial_port *wport = &serial->port[1]; + + int room = 0; // Default: no room + + if (wport->write_urb->status != -EINPROGRESS) + room = wport->bulk_out_size - OMNINET_HEADERLEN; + +// dbg("omninet_write_room returns %d", room); + + return (room); +} + +static void omninet_write_bulk_callback (struct urb *urb) +{ +/* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */ + struct usb_serial_port *port = (struct usb_serial_port *) urb->context; + struct usb_serial *serial; + struct tty_struct *tty; + +// dbg("omninet_write_bulk_callback, port %0x\n", port); + + + if (port_paranoia_check (port, "omninet_write_bulk_callback")) { + return; + } + + serial = port->serial; + if (serial_paranoia_check (serial, "omninet_write_bulk_callback")) { + return; + } + + if (urb->status) { + dbg("nonzero write bulk status received: %d", urb->status); + return; + } + + tty = port->tty; + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + wake_up_interruptible(&tty->write_wait); + +// dbg("omninet_write_bulk_callback, tty %0x\n", tty); + + return; +} + +#endif /* CONFIG_USB_SERIAL_OMNINET */ + + diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h --- v2.3.99-pre5/linux/drivers/usb/serial/usb-serial.h Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/serial/usb-serial.h Fri Apr 21 14:03:01 2000 @@ -39,10 +39,8 @@ unsigned char number; char active; /* someone has this device open */ - struct usb_endpoint_descriptor * interrupt_in_endpoint; - __u8 interrupt_in_interval; unsigned char * interrupt_in_buffer; - struct urb * control_urb; + struct urb * interrupt_in_urb; unsigned char * bulk_in_buffer; struct urb * read_urb; @@ -50,7 +48,10 @@ unsigned char * bulk_out_buffer; int bulk_out_size; struct urb * write_urb; - void * private; /* data private to the specific driver */ + + wait_queue_head_t write_wait; + + void * private; /* data private to the specific port */ }; struct usb_serial { @@ -65,11 +66,6 @@ char num_bulk_out; /* number of bulk out endpoints we have */ struct usb_serial_port port[MAX_NUM_PORTS]; - /* FIXME! These should move to the private area of the keyspan driver */ - int tx_room; - int tx_throttled; - wait_queue_head_t write_wait; - void * private; /* data private to the specific driver */ }; @@ -99,7 +95,8 @@ /* function call to make before accepting driver */ int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */ - + void (*shutdown) (struct usb_serial *serial); + /* serial function calls */ int (*open) (struct usb_serial_port *port, struct file * filp); void (*close) (struct usb_serial_port *port, struct file * filp); @@ -111,7 +108,8 @@ int (*chars_in_buffer) (struct usb_serial_port *port); void (*throttle) (struct usb_serial_port *port); void (*unthrottle) (struct usb_serial_port *port); - + + void (*read_int_callback)(struct urb *urb); void (*read_bulk_callback)(struct urb *urb); void (*write_bulk_callback)(struct urb *urb); }; @@ -124,6 +122,7 @@ extern struct usb_serial_device_type ftdi_sio_device; extern struct usb_serial_device_type keyspan_pda_fake_device; extern struct usb_serial_device_type keyspan_pda_device; +extern struct usb_serial_device_type zyxel_omninet_device; /* determine if we should include the EzUSB loader functions */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c --- v2.3.99-pre5/linux/drivers/usb/serial/usbserial.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/serial/usbserial.c Mon Apr 24 16:15:01 2000 @@ -14,6 +14,14 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (04/23/2000) gkh + * Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports. + * Moved when the startup code printed out the devices that are supported. + * + * (04/19/2000) gkh + * Added driver for ZyXEL omni.net lcd plus ISDN TA + * Made startup info message specify which drivers were compiled in. + * * (04/03/2000) gkh * Changed the probe process to remove the module unload races. * Changed where the tty layer gets initialized to have devfs work nicer. @@ -211,6 +219,7 @@ #include "usb-serial.h" +#define MAX(a,b) (((a)>(b))?(a):(b)) /* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ /* need to always compile these in, as some of the other devices use these functions as their own. */ @@ -270,6 +279,9 @@ &keyspan_pda_fake_device, &keyspan_pda_device, #endif +#ifdef CONFIG_USB_SERIAL_OMNINET + &zyxel_omninet_device, +#endif NULL }; @@ -424,14 +436,9 @@ return -ENODEV; } - /* set up our port structure */ + /* set up our port structure making the tty driver remember our port object, and us it */ portNumber = MINOR(tty->device) - serial->minor; port = &serial->port[portNumber]; - port->number = portNumber; - port->serial = serial; - port->magic = USB_SERIAL_PORT_MAGIC; - - /* make the tty driver remember our port object, and us it */ tty->driver_data = port; port->tty = tty; @@ -996,236 +1003,248 @@ int num_bulk_in = 0; int num_bulk_out = 0; int num_ports; + int max_endpoints; - /* loop through our list of known serial converters, and see if this device matches */ - device_num = 0; - while (usb_serial_devices[device_num] != NULL) { + /* loop through our list of known serial converters, and see if this + device matches. */ + for (device_num = 0; usb_serial_devices[device_num]; device_num++) { type = usb_serial_devices[device_num]; - dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct)); + dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", + type->name, *(type->idVendor), *(type->idProduct)); /* look at the device descriptor */ if ((dev->descriptor.idVendor == *(type->idVendor)) && (dev->descriptor.idProduct == *(type->idProduct))) { + dbg("descriptor matches"); + break; + } + } + if (!usb_serial_devices[device_num]) { + /* no match */ + dbg("none matched"); + return(NULL); + } - dbg("descriptor matches...looking at the endpoints"); - - /* descriptor matches, let's try to find the endpoints needed */ - interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT; + /* descriptor matches, let's find the endpoints needed */ + interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT; - /* check out the endpoints */ - interface = &dev->actconfig->interface[ifnum].altsetting[0]; - for (i = 0; i < interface->bNumEndpoints; ++i) { - endpoint = &interface->endpoint[i]; - - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk in endpoint */ - dbg("found bulk in"); - bulk_in_pipe = HAS; - bulk_in_endpoint[num_bulk_in] = endpoint; - ++num_bulk_in; - } - - if (((endpoint->bEndpointAddress & 0x80) == 0x00) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk out endpoint */ - dbg("found bulk out"); - bulk_out_pipe = HAS; - bulk_out_endpoint[num_bulk_out] = endpoint; - ++num_bulk_out; - } + /* check out the endpoints */ + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + for (i = 0; i < interface->bNumEndpoints; ++i) { + endpoint = &interface->endpoint[i]; - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x03)) { - /* we found a interrupt in endpoint */ - dbg("found interrupt in"); - interrupt_pipe = HAS; - interrupt_in_endpoint[num_interrupt_in] = endpoint; - ++num_interrupt_in; - } + if ((endpoint->bEndpointAddress & 0x80) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk in endpoint */ + dbg("found bulk in"); + bulk_in_pipe = HAS; + bulk_in_endpoint[num_bulk_in] = endpoint; + ++num_bulk_in; + } - } + if (((endpoint->bEndpointAddress & 0x80) == 0x00) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk out endpoint */ + dbg("found bulk out"); + bulk_out_pipe = HAS; + bulk_out_endpoint[num_bulk_out] = endpoint; + ++num_bulk_out; + } + + if ((endpoint->bEndpointAddress & 0x80) && + ((endpoint->bmAttributes & 3) == 0x03)) { + /* we found a interrupt in endpoint */ + dbg("found interrupt in"); + interrupt_pipe = HAS; + interrupt_in_endpoint[num_interrupt_in] = endpoint; + ++num_interrupt_in; + } + } - /* verify that we found all of the endpoints that we need */ - if ((interrupt_pipe & type->needs_interrupt_in) && - (bulk_in_pipe & type->needs_bulk_in) && - (bulk_out_pipe & type->needs_bulk_out)) { - /* found all that we need */ - MOD_INC_USE_COUNT; - info("%s converter detected", type->name); + /* verify that we found all of the endpoints that we need */ + if (!((interrupt_pipe & type->needs_interrupt_in) && + (bulk_in_pipe & type->needs_bulk_in) && + (bulk_out_pipe & type->needs_bulk_out))) { + /* nope, they don't match what we expected */ + info("descriptors matched, but endpoints did not"); + return NULL; + } -#ifdef CONFIG_USB_SERIAL_GENERIC - if (type == &generic_device) - num_ports = num_bulk_out; - else -#endif - num_ports = type->num_ports; + /* found all that we need */ + MOD_INC_USE_COUNT; + info("%s converter detected", type->name); - serial = get_free_serial (num_ports, &minor); - if (serial == NULL) { - err("No more free serial devices"); - MOD_DEC_USE_COUNT; - return NULL; - } - - serial->dev = dev; - serial->type = type; - serial->minor = minor; - serial->num_ports = num_ports; - serial->num_bulk_in = num_bulk_in; - serial->num_bulk_out = num_bulk_out; - serial->num_interrupt_in = num_interrupt_in; - - /* initialize a tty_driver for this device */ - serial->tty_driver = usb_serial_tty_driver_init (serial); - if (serial->tty_driver == NULL) { - err("Can't create a tty_serial_driver"); - goto probe_error; - } - - if (tty_register_driver (serial->tty_driver)) { - err("failed to register tty driver"); - goto probe_error; - } - - /* collect interrupt_in endpoints now, because - the keyspan_pda startup function needs - to know about them */ - for (i = 0; i < num_interrupt_in; ++i) { - port = &serial->port[i]; - buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize; - port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); - if (!port->interrupt_in_buffer) { - err("Couldn't allocate interrupt_in_buffer"); - goto probe_error; - } - port->interrupt_in_endpoint = interrupt_in_endpoint[i]; - } - - /* if this device type has a startup function, call it */ - if (type->startup) { - if (type->startup (serial)) { - goto probe_error; - } - } - - /* set up the endpoint information */ - for (i = 0; i < num_bulk_in; ++i) { - port = &serial->port[i]; - port->read_urb = usb_alloc_urb (0); - if (!port->read_urb) { - err("No free urbs available"); - goto probe_error; - } - buffer_size = bulk_in_endpoint[i]->wMaxPacketSize; - port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); - if (!port->bulk_in_buffer) { - err("Couldn't allocate bulk_in_buffer"); - goto probe_error; - } - if (serial->type->read_bulk_callback) { - FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), - port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port); - } else { - FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), - port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port); - } - } - - for (i = 0; i < num_bulk_out; ++i) { - port = &serial->port[i]; - port->write_urb = usb_alloc_urb(0); - if (!port->write_urb) { - err("No free urbs available"); - goto probe_error; - } - port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize; - port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL); - if (!port->bulk_out_buffer) { - err("Couldn't allocate bulk_out_buffer"); - goto probe_error; - } - if (serial->type->write_bulk_callback) { - FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), - port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port); - } else { - FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), - port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port); - } - } - -#if 0 /* use this code when WhiteHEAT is up and running */ - for (i = 0; i < num_interrupt_in; ++i) { - port = &serial->port[i]; - port->control_urb = usb_alloc_urb(0); - if (!port->control_urb) { - err("No free urbs available"); - goto probe_error; - } - buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize; - port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); - if (!port->interrupt_in_buffer) { - err("Couldn't allocate interrupt_in_buffer"); - goto probe_error; - } - FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress), - port->interrupt_in_buffer, buffer_size, serial_control_irq, - port, interrupt_in_endpoint[i]->bInterval); - } +#ifdef CONFIG_USB_SERIAL_GENERIC + if (type == &generic_device) { + num_ports = num_bulk_out; + if (num_ports == 0) { + err("Generic device with no bulk out, not allowed."); + MOD_DEC_USE_COUNT; + return NULL; + } + } else #endif + num_ports = type->num_ports; - for (i = 0; i < serial->num_ports; ++i) { - info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i); - } - - return serial; - } else { - info("descriptors matched, but endpoints did not"); - } + serial = get_free_serial (num_ports, &minor); + if (serial == NULL) { + err("No more free serial devices"); + MOD_DEC_USE_COUNT; + return NULL; + } + + serial->dev = dev; + serial->type = type; + serial->minor = minor; + serial->num_ports = num_ports; + serial->num_bulk_in = num_bulk_in; + serial->num_bulk_out = num_bulk_out; + serial->num_interrupt_in = num_interrupt_in; + + /* initialize a tty_driver for this device */ + serial->tty_driver = usb_serial_tty_driver_init (serial); + if (serial->tty_driver == NULL) { + err("Can't create a tty_serial_driver"); + goto probe_error; + } + + if (tty_register_driver (serial->tty_driver)) { + err("failed to register tty driver"); + goto probe_error; + } + + /* if this device type has a startup function, call it */ + if (type->startup) { + if (type->startup (serial)) { + goto probe_error; } - - /* look at the next type in our list */ - ++device_num; } -probe_error: - if (serial) { - for (i = 0; i < num_bulk_in; ++i) { - port = &serial->port[i]; - if (port->read_urb) - usb_free_urb (port->read_urb); - if (serial->port[i].bulk_in_buffer[i]) - kfree (serial->port[i].bulk_in_buffer); + /* set up the endpoint information */ + for (i = 0; i < num_bulk_in; ++i) { + endpoint = bulk_in_endpoint[i]; + port = &serial->port[i]; + port->read_urb = usb_alloc_urb (0); + if (!port->read_urb) { + err("No free urbs available"); + goto probe_error; } - for (i = 0; i < num_bulk_out; ++i) { - port = &serial->port[i]; - if (port->write_urb) - usb_free_urb (port->write_urb); - if (serial->port[i].bulk_out_buffer) - kfree (serial->port[i].bulk_out_buffer); + buffer_size = endpoint->wMaxPacketSize; + port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!port->bulk_in_buffer) { + err("Couldn't allocate bulk_in_buffer"); + goto probe_error; } - for (i = 0; i < num_interrupt_in; ++i) { - port = &serial->port[i]; - if (port->control_urb) - usb_free_urb (port->control_urb); - if (serial->port[i].interrupt_in_buffer) - kfree (serial->port[i].interrupt_in_buffer); + FILL_BULK_URB(port->read_urb, dev, + usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), + port->bulk_in_buffer, buffer_size, + ((serial->type->read_bulk_callback) ? + serial->type->read_bulk_callback : + generic_read_bulk_callback), + port); + } + + for (i = 0; i < num_bulk_out; ++i) { + endpoint = bulk_out_endpoint[i]; + port = &serial->port[i]; + port->write_urb = usb_alloc_urb(0); + if (!port->write_urb) { + err("No free urbs available"); + goto probe_error; } - - /* return the minor range that this device had */ - return_serial (serial); - - /* if this device has a tty_driver, then unregister it and free it */ - if (serial->tty_driver) { - tty_unregister_driver (serial->tty_driver); - kfree (serial->tty_driver); - serial->tty_driver = NULL; + buffer_size = endpoint->wMaxPacketSize; + port->bulk_out_size = buffer_size; + port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!port->bulk_out_buffer) { + err("Couldn't allocate bulk_out_buffer"); + goto probe_error; + } + FILL_BULK_URB(port->write_urb, dev, + usb_sndbulkpipe(dev, endpoint->bEndpointAddress), + port->bulk_out_buffer, buffer_size, + ((serial->type->write_bulk_callback) ? + serial->type->write_bulk_callback : + generic_write_bulk_callback), + port); + } + + for (i = 0; i < num_interrupt_in; ++i) { + endpoint = interrupt_in_endpoint[i]; + port = &serial->port[i]; + port->interrupt_in_urb = usb_alloc_urb(0); + if (!port->interrupt_in_urb) { + err("No free urbs available"); + goto probe_error; } + buffer_size = endpoint->wMaxPacketSize; + port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!port->interrupt_in_buffer) { + err("Couldn't allocate interrupt_in_buffer"); + goto probe_error; + } + FILL_INT_URB(port->interrupt_in_urb, dev, + usb_rcvintpipe(dev, endpoint->bEndpointAddress), + port->interrupt_in_buffer, buffer_size, + serial->type->read_int_callback, + port, + endpoint->bInterval); + } + + /* initialize some parts of the port structures */ + /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */ + max_endpoints = MAX(num_bulk_in, num_bulk_out); + max_endpoints = MAX(max_endpoints, num_interrupt_in); + for (i = 0; i < max_endpoints; ++i) { + port = &serial->port[i]; + port->number = i; + port->serial = serial; + port->magic = USB_SERIAL_PORT_MAGIC; + } + + for (i = 0; i < serial->num_ports; ++i) { + info("%s converter now attached to ttyUSB%d", + type->name, serial->minor + i); + } + + return serial; /* success */ - /* free up any memory that we allocated */ - kfree (serial); - MOD_DEC_USE_COUNT; + +probe_error: + for (i = 0; i < num_bulk_in; ++i) { + port = &serial->port[i]; + if (port->read_urb) + usb_free_urb (port->read_urb); + if (port->bulk_in_buffer) + kfree (port->bulk_in_buffer); + } + for (i = 0; i < num_bulk_out; ++i) { + port = &serial->port[i]; + if (port->write_urb) + usb_free_urb (port->write_urb); + if (port->bulk_out_buffer) + kfree (port->bulk_out_buffer); + } + for (i = 0; i < num_interrupt_in; ++i) { + port = &serial->port[i]; + if (port->interrupt_in_urb) + usb_free_urb (port->interrupt_in_urb); + if (port->interrupt_in_buffer) + kfree (port->interrupt_in_buffer); } + + /* return the minor range that this device had */ + return_serial (serial); + + /* if this device has a tty_driver, then unregister it and free it */ + if (serial->tty_driver) { + tty_unregister_driver (serial->tty_driver); + kfree (serial->tty_driver); + serial->tty_driver = NULL; + } + + /* free up any memory that we allocated */ + kfree (serial); + MOD_DEC_USE_COUNT; return NULL; } @@ -1237,6 +1256,9 @@ int i; if (serial) { + if (serial->type->shutdown) + serial->type->shutdown(serial); + for (i = 0; i < serial->num_ports; ++i) serial->port[i].active = 0; @@ -1260,9 +1282,9 @@ } for (i = 0; i < serial->num_interrupt_in; ++i) { port = &serial->port[i]; - if (port->control_urb) { - usb_unlink_urb (port->control_urb); - usb_free_urb (port->control_urb); + if (port->interrupt_in_urb) { + usb_unlink_urb (port->interrupt_in_urb); + usb_free_urb (port->interrupt_in_urb); } if (port->interrupt_in_buffer) kfree (port->interrupt_in_buffer); @@ -1295,18 +1317,32 @@ int usb_serial_init(void) { int i; + int something; + int result; /* Initalize our global data */ for (i = 0; i < SERIAL_TTY_MINORS; ++i) { serial_table[i] = NULL; } + /* tell the world what devices this driver currently supports */ + something = 0; + for (i = 0; usb_serial_devices[i]; ++i) { + if (!strstr (usb_serial_devices[i]->name, "prerenumeration")) { + info ("USB Serial support registered for %s", usb_serial_devices[i]->name); + something = 1; + } + } + if (!something) + info ("USB Serial driver is not configured for any devices!"); + /* register the USB driver */ - if (usb_register(&usb_serial_driver) < 0) { + result = usb_register(&usb_serial_driver); + if (result < 0) { + err("usb_register failed for the usb-serial driver. Error number %d", result); return -1; } - - info("support registered"); + return 0; } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/uhci-debug.h linux/drivers/usb/uhci-debug.h --- v2.3.99-pre5/linux/drivers/usb/uhci-debug.h Sun Feb 20 21:12:39 2000 +++ linux/drivers/usb/uhci-debug.h Mon Apr 24 16:15:01 2000 @@ -14,7 +14,7 @@ #include "uhci.h" -void uhci_show_td(struct uhci_td * td) +void uhci_show_td(struct uhci_td *td) { char *spid; @@ -127,6 +127,62 @@ return NULL; return bus_to_virt(link & ~UHCI_PTR_BITS); +} + +void uhci_show_urb_queue(struct urb *urb) +{ + struct urb_priv *urbp = urb->hcpriv; + struct list_head *head, *tmp; + int i, checked = 0, prevactive = 0; + + printk(" URB [%p] urbp [%p]\n", urb, urbp); + + if (urbp->qh) + printk(" QH [%p]\n", urbp->qh); + else + printk(" QH [%p] element (%08x) link (%08x)\n", urbp->qh, + urbp->qh->element, urbp->qh->link); + + i = 0; + + head = &urbp->list; + tmp = head->next; + while (tmp != head) { + struct uhci_td *td = list_entry(tmp, struct uhci_td, list); + + tmp = tmp->next; + + printk(" td %d: [%p]\n", i++, td); + printk(" "); + uhci_show_td(td); + + if (i > 10 && !checked && prevactive && tmp != head) { + struct list_head *ntmp = tmp; + struct uhci_td *ntd = td; + int active = 1, ni = i; + + checked = 1; + + while (ntmp != head && ntmp->next != head && active) { + ntd = list_entry(ntmp, struct uhci_td, list); + + ntmp = ntmp->next; + + active = ntd->status & TD_CTRL_ACTIVE; + + ni++; + } + + if (active && ni > i) { + printk(" [skipped %d active TD's]\n", ni - i); + tmp = ntmp; + td = ntd; + i = ni; + } + } + + prevactive = td->status & TD_CTRL_ACTIVE; + } } void uhci_show_queue(struct uhci_qh *qh) diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.99-pre5/linux/drivers/usb/uhci.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/uhci.c Mon Apr 24 16:15:01 2000 @@ -284,42 +284,6 @@ prevtd->link = UHCI_PTR_TERM; } -/* This function will append one URB's QH to another URB's QH. This is for */ -/* USB_QUEUE_BULK support */ -static void uhci_append_urb_qh(struct uhci *uhci, struct urb *eurb, struct urb *urb) -{ - struct urb *nurb; - struct urb_priv *eurbp, *urbp, *nurbp; - struct list_head *tmp; - struct uhci_td *td, *ntd; - unsigned long flags; - - eurbp = eurb->hcpriv; - urbp = urb->hcpriv; - - spin_lock_irqsave(&eurb->lock, flags); - - /* Grab the last URB in the queue */ - tmp = eurbp->urb_queue_list.prev; - - /* Add this one to the end */ - list_add_tail(&urbp->urb_queue_list, &eurbp->urb_queue_list); - - spin_unlock_irqrestore(&eurb->lock, flags); - - nurbp = list_entry(tmp, struct urb_priv, urb_queue_list); - nurb = nurbp->urb; - - tmp = nurbp->list.prev; - td = list_entry(tmp, struct uhci_td, list); - - tmp = urbp->list.next; - ntd = list_entry(tmp, struct uhci_td, list); - - /* No breadth since this will only be called for bulk transfers */ - td->link = virt_to_bus(ntd); -} - static void uhci_free_td(struct uhci_td *td) { if (!list_empty(&td->list)) @@ -395,6 +359,7 @@ if (qh->nextqh) qh->nextqh->prevqh = qh->prevqh; qh->prevqh = qh->nextqh = NULL; + qh->element = qh->link = UHCI_PTR_TERM; spin_unlock_irqrestore(&uhci->framelist_lock, flags); if (delayed) { @@ -413,6 +378,101 @@ uhci_free_qh(qh); } +static spinlock_t uhci_append_urb_lock = SPIN_LOCK_UNLOCKED; + +/* This function will append one URB's QH to another URB's QH. This is for */ +/* USB_QUEUE_BULK support */ +static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb) +{ + struct urb_priv *eurbp, *urbp, *furbp, *lurbp; + struct list_head *tmp; + struct uhci_td *td, *ltd; + unsigned long flags; + + eurbp = eurb->hcpriv; + urbp = urb->hcpriv; + + spin_lock_irqsave(&uhci_append_urb_lock, flags); + + /* Find the beginning URB in the queue */ + if (eurbp->queued) { + struct list_head *head = &eurbp->urb_queue_list; + + tmp = head->next; + while (tmp != head) { + struct urb_priv *turbp = + list_entry(tmp, struct urb_priv, urb_queue_list); + + tmp = tmp->next; + + if (!turbp->queued) + break; + } + } else + tmp = &eurbp->urb_queue_list; + + furbp = list_entry(tmp, struct urb_priv, urb_queue_list); + + tmp = furbp->urb_queue_list.prev; + lurbp = list_entry(tmp, struct urb_priv, urb_queue_list); + + /* Add this one to the end */ + list_add_tail(&urbp->urb_queue_list, &furbp->urb_queue_list); + + /* Grab the last TD from the last URB */ + ltd = list_entry(lurbp->list.prev, struct uhci_td, list); + + /* Grab the first TD from the first URB */ + td = list_entry(urbp->list.next, struct uhci_td, list); + + /* No breadth since this will only be called for bulk transfers */ + ltd->link = virt_to_bus(td); + + spin_unlock_irqrestore(&uhci_append_urb_lock, flags); +} + +static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb) +{ + struct urb_priv *urbp, *nurbp; + unsigned long flags; + + urbp = urb->hcpriv; + + spin_lock_irqsave(&uhci_append_urb_lock, flags); + + nurbp = list_entry(urbp->urb_queue_list.next, struct urb_priv, + urb_queue_list); + + if (!urbp->queued) { + /* We're the head, so just insert the QH for the next URB */ + uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh); + nurbp->queued = 0; + } else { + struct urb_priv *purbp; + struct uhci_td *ptd; + + /* We're somewhere in the middle (or end). A bit trickier */ + /* than the head scenario */ + purbp = list_entry(urbp->urb_queue_list.prev, struct urb_priv, + urb_queue_list); + + ptd = list_entry(purbp->list.prev, struct uhci_td, list); + if (nurbp->queued) + /* Close the gap between the two */ + ptd->link = virt_to_bus(list_entry(nurbp->list.next, + struct uhci_td, list)); + else + /* The next URB happens to be the beggining, so */ + /* we're the last, end the chain */ + ptd->link = UHCI_PTR_TERM; + + } + + list_del(&urbp->urb_queue_list); + + spin_unlock_irqrestore(&uhci_append_urb_lock, flags); +} + struct urb_priv *uhci_alloc_urb_priv(struct urb *urb) { struct urb_priv *urbp; @@ -491,11 +551,6 @@ uhci_free_td(td); } - if (!list_empty(&urbp->urb_queue_list)) { - list_del(&urbp->urb_queue_list); - INIT_LIST_HEAD(&urbp->urb_queue_list); - } - urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); @@ -672,12 +727,10 @@ if (urb->pipe & TD_CTRL_LS) { uhci_insert_tds_in_qh(qh, urb, 0); uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh); - urbp->queued = 0; } else { uhci_insert_tds_in_qh(qh, urb, 1); uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh); uhci_inc_fsbr(uhci, urb); - urbp->queued = 0; } urbp->qh = qh; @@ -697,18 +750,21 @@ struct urb_priv *urbp = urb->hcpriv; struct uhci_td *td; unsigned int status; + int ret = 0; if (!urbp) return -EINVAL; head = &urbp->list; - tmp = head->next; - if (head == tmp) + if (head->next == head) return -EINVAL; - if (urbp->short_control_packet) + if (urbp->short_control_packet) { + tmp = head->prev; goto status_phase; + } + tmp = head->next; td = list_entry(tmp, struct uhci_td, list); /* The first TD is the SETUP phase, check the status, but skip */ @@ -729,20 +785,34 @@ tmp = tmp->next; + if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) && + !(td->status & TD_CTRL_ACTIVE)) { + uhci_inc_fsbr(urb->dev->bus->hcpriv, urb); + urbp->fsbr_timeout = 0; + td->status &= ~TD_CTRL_IOC; + } + status = uhci_status_bits(td->status); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; urb->actual_length += uhci_actual_length(td->status); - /* If SPD is set then we received a short packet */ - /* There will be no status phase at the end */ - if ((td->status & TD_CTRL_SPD) && - (uhci_actual_length(td->status) < uhci_expected_length(td->info))) - return usb_control_retrigger_status(urb); - if (status) goto td_error; + + /* Check to see if we received a short packet */ + if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) { + if (urb->transfer_flags & USB_DISABLE_SPD) { + ret = -EREMOTEIO; + goto err; + } + + if (uhci_packetid(td->info) == USB_PID_IN) + return usb_control_retrigger_status(urb); + else + return 0; + } } status_phase: @@ -768,19 +838,22 @@ return 0; td_error: - if (status & TD_CTRL_STALLED) + ret = uhci_map_status(status, uhci_packetout(td->info)); + if (ret == -EPIPE) /* endpoint has stalled - mark it halted */ usb_endpoint_halt(urb->dev, uhci_endpoint(td->info), uhci_packetout(td->info)); - else if (debug) { + +err: + if (debug && ret != -EPIPE) { /* Some debugging code */ dbg("uhci_result_control() failed with status %x", status); /* Print the chain for debugging purposes */ - uhci_show_queue(urbp->qh); + uhci_show_urb_queue(urb); } - return uhci_map_status(status, uhci_packetout(td->info)); + return ret; } static int usb_control_retrigger_status(struct urb *urb) @@ -823,7 +896,6 @@ uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, urbp->qh); else uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, urbp->qh); - urbp->queued = 0; return -EINPROGRESS; } @@ -869,8 +941,9 @@ { struct list_head *tmp, *head; struct urb_priv *urbp = urb->hcpriv; - unsigned int status; struct uhci_td *td; + unsigned int status; + int ret = 0; if (!urbp) return -EINVAL; @@ -884,46 +957,58 @@ tmp = tmp->next; + if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) && + !(td->status & TD_CTRL_ACTIVE)) { + uhci_inc_fsbr(urb->dev->bus->hcpriv, urb); + urbp->fsbr_timeout = 0; + td->status &= ~TD_CTRL_IOC; + } + status = uhci_status_bits(td->status); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; urb->actual_length += uhci_actual_length(td->status); - /* If SPD is set then we received a short packet */ - if ((td->status & TD_CTRL_SPD) && - (uhci_actual_length(td->status) < uhci_expected_length(td->info))) { + if (status) + goto td_error; + + if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) { usb_settoggle(urb->dev, uhci_endpoint(td->info), uhci_packetout(td->info), uhci_toggle(td->info) ^ 1); - return 0; + if (urb->transfer_flags & USB_DISABLE_SPD) { + ret = -EREMOTEIO; + goto err; + } else + return 0; } - - if (status) - goto td_error; } return 0; td_error: - if (status & TD_CTRL_STALLED) + ret = uhci_map_status(status, uhci_packetout(td->info)); + if (ret == -EPIPE) /* endpoint has stalled - mark it halted */ usb_endpoint_halt(urb->dev, uhci_endpoint(td->info), uhci_packetout(td->info)); - else if (debug) { + +err: + if (debug && ret != -EPIPE) { /* Some debugging code */ dbg("uhci_result_interrupt/bulk() failed with status %x", status); /* Print the chain for debugging purposes */ if (urbp->qh) - uhci_show_queue(urbp->qh); + uhci_show_urb_queue(urb); else uhci_show_td(td); } - return uhci_map_status(status, uhci_packetout(td->info)); + return ret; } static void uhci_reset_interrupt(struct urb *urb) @@ -974,6 +1059,7 @@ /* 3 errors */ status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT); + if (!(urb->transfer_flags & USB_DISABLE_SPD)) status |= TD_CTRL_SPD; @@ -1016,12 +1102,10 @@ uhci_insert_tds_in_qh(qh, urb, 1); if (urb->transfer_flags & USB_QUEUE_BULK && eurb) { - uhci_append_urb_qh(uhci, eurb, urb); urbp->queued = 1; - } else { + uhci_append_queued_urb(uhci, eurb, urb); + } else uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh); - urbp->queued = 0; - } uhci_add_urb_list(uhci, urb); @@ -1049,6 +1133,8 @@ while (tmp != head) { struct urb *u = list_entry(tmp, struct urb, urb_list); + tmp = tmp->next; + /* look for pending URB's with identical pipe handle */ if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS) && (u != urb)) { @@ -1056,7 +1142,6 @@ *start = u->start_frame; last_urb = u; } - tmp = tmp->next; } if (last_urb) { @@ -1363,14 +1448,8 @@ /* The interrupt loop will reclaim the QH's */ uhci_remove_qh(uhci, urbp->qh); - if (!list_empty(&urbp->urb_queue_list)) { - struct list_head *tmp = urbp->urb_queue_list.next; - struct urb_priv *nurbp = list_entry(tmp, struct urb_priv, urb_queue_list); - if (nurbp->queued) { - uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh); - nurbp->queued = 0; - } - } + if (!list_empty(&urbp->urb_queue_list)) + uhci_delete_queued_urb(uhci, urb); uhci_destroy_urb_priv(urb); @@ -1430,6 +1509,35 @@ return ret; } +static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb) +{ + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct list_head *head, *tmp; + + uhci_dec_fsbr(uhci, urb); + + /* There is a race with updating IOC in here, but it's not worth */ + /* trying to fix since this is merely an optimization. The only */ + /* time we'd lose is if the status of the packet got updated */ + /* and we'd be turning on FSBR next frame anyway, so it's a wash */ + urbp->fsbr_timeout = 1; + + head = &urbp->list; + tmp = head->next; + while (tmp != head) { + struct uhci_td *td = list_entry(tmp, struct uhci_td, list); + + tmp = tmp->next; + + if (td->status & TD_CTRL_ACTIVE) { + td->status |= TD_CTRL_IOC; + break; + } + } + + return 0; +} + /* * uhci_get_current_frame_number() * @@ -1586,7 +1694,7 @@ if (urbp) { /* Check if the FSBR timed out */ if (urbp->fsbr && time_after(urbp->inserttime + IDLE_TIMEOUT, jiffies)) - uhci_dec_fsbr(uhci, u); + uhci_fsbr_timeout(uhci, u); /* Check if the URB timed out */ if (u->timeout && time_after(u->timeout, jiffies)) { @@ -1762,7 +1870,7 @@ case RH_PORT_POWER: OK(0); /* port power ** */ case RH_PORT_ENABLE: - SET_RH_PORTSTAT (USBPORTSC_PE); + SET_RH_PORTSTAT(USBPORTSC_PE); OK(0); } break; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h --- v2.3.99-pre5/linux/drivers/usb/uhci.h Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/uhci.h Mon Apr 24 16:15:01 2000 @@ -339,10 +339,10 @@ struct uhci_qh *qh; /* QH for this URB */ - int fsbr : 1; /* Did this URB turn on FSBR? */ - int queued : 1; /* 0 if QH was linked in */ - - char short_control_packet; /* If we get a short packet during */ + int fsbr : 1; /* URB turned on FSBR */ + int fsbr_timeout : 1; /* URB timed out on FSBR */ + int queued : 1; /* QH was queued (not linked in) */ + int short_control_packet : 1; /* If we get a short packet during */ /* a control transfer, retrigger */ /* the status phase */ @@ -414,6 +414,7 @@ /* Debugging code */ void uhci_show_td(struct uhci_td *td); void uhci_show_status(struct uhci *uhci); +void uhci_show_urb_queue(struct urb *urb); void uhci_show_queue(struct uhci_qh *qh); void uhci_show_queues(struct uhci *uhci); diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c --- v2.3.99-pre5/linux/drivers/usb/usb-core.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/usb-core.c Fri Apr 21 14:03:00 2000 @@ -28,6 +28,7 @@ * USB device drivers */ +int usb_cpia_init(void); int usb_audio_init(void); int usb_ibmcam_init(void); int dabusb_init(void); @@ -68,6 +69,9 @@ usb_hub_init(); #ifndef CONFIG_USB_MODULE +#ifdef CONFIG_VIDEO_CPIA_USB + usb_cpia_init(); +#endif #ifdef CONFIG_USB_AUDIO usb_audio_init(); #endif diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.3.99-pre5/linux/drivers/usb/usb-ohci.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/usb-ohci.c Wed Apr 26 15:22:55 2000 @@ -1555,7 +1555,7 @@ data_buf = root_hub_config_des; OK(len); case (0x03): /* string descriptors */ len = usb_root_hub_string (wValue & 0xff, - (int) ohci->regs, "OHCI", + (int)(long) ohci->regs, "OHCI", data, wLength); if (len > 0) { data_buf = data; diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c --- v2.3.99-pre5/linux/drivers/usb/usb-storage.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/usb-storage.c Fri Apr 21 14:03:00 2000 @@ -74,42 +74,50 @@ unsigned int flags; /* from filter initially */ - /* information about the device -- only good if device is attached */ - __u8 ifnum; /* interface number */ - __u8 ep_in; /* in endpoint */ - __u8 ep_out; /* out ....... */ - __u8 ep_int; /* interrupt . */ + /* information about the device -- always good */ + char vendor[32]; + char product[32]; + char serial[32]; + char *transport_name; + char *protocol_name; __u8 subclass; __u8 protocol; + /* information about the device -- only good if device is attached */ + __u8 ifnum; /* interface number */ + __u8 ep_in; /* bulk in endpoint */ + __u8 ep_out; /* bulk out endpoint */ + __u8 ep_int; /* interrupt endpoint */ + __u8 ep_interval; /* interrupt interval */ + /* function pointers for this device */ - trans_cmnd transport; /* transport function */ + trans_cmnd transport; /* transport function */ trans_reset transport_reset; /* transport device reset */ - proto_cmnd proto_handler; /* protocol handler */ + proto_cmnd proto_handler; /* protocol handler */ /* SCSI interfaces */ - GUID(guid); /* unique dev id */ + GUID(guid); /* unique dev id */ struct Scsi_Host *host; /* our dummy host data */ - Scsi_Host_Template htmplt; /* own host template */ - int host_number; /* to find us */ - int host_no; /* allocated by scsi */ - Scsi_Cmnd *srb; /* current srb */ + Scsi_Host_Template htmplt; /* own host template */ + int host_number; /* to find us */ + int host_no; /* allocated by scsi */ + Scsi_Cmnd *srb; /* current srb */ /* thread information */ Scsi_Cmnd *queue_srb; /* the single queue slot */ - int action; /* what to do */ - int pid; /* control thread */ + int action; /* what to do */ + int pid; /* control thread */ - /* interrupt info for CBI devices */ - struct semaphore ip_waitq; /* for CBI interrupts */ - __u16 ip_data; /* interrupt data */ - int ip_wanted; /* needed */ + /* interrupt info for CBI devices -- only good if attached */ + struct semaphore ip_waitq; /* for CBI interrupts */ + __u16 ip_data; /* interrupt data */ + int ip_wanted; /* is an IRQ expected? */ void *irq_handle; /* for USB int requests */ unsigned int irqpipe; /* pipe for release_irq */ /* mutual exclusion structures */ - struct semaphore notify; /* thread begin/end */ - struct semaphore sleeper; /* to sleep on */ + struct semaphore notify; /* thread begin/end */ + struct semaphore sleeper; /* to sleep the thread on */ struct semaphore queue_exclusion; /* to protect data structs */ }; @@ -118,11 +126,10 @@ */ #define US_ACT_COMMAND 1 -#define US_ACT_ABORT 2 -#define US_ACT_DEVICE_RESET 3 -#define US_ACT_BUS_RESET 4 -#define US_ACT_HOST_RESET 5 -#define US_ACT_EXIT 6 +#define US_ACT_DEVICE_RESET 2 +#define US_ACT_BUS_RESET 3 +#define US_ACT_HOST_RESET 4 +#define US_ACT_EXIT 5 /* The list of structures and the protective lock for them */ static struct us_data *us_list; @@ -131,18 +138,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum); static void storage_disconnect(struct usb_device *dev, void *ptr); static struct usb_driver storage_driver = { - "usb-storage", - storage_probe, - storage_disconnect, - { NULL, NULL } + name: "usb-storage", + probe: storage_probe, + disconnect: storage_disconnect, }; /*********************************************************************** * Data transfer routines ***********************************************************************/ -/* FIXME: the names of these functions are poorly choosen. */ - /* * Transfer one SCSI scatter-gather buffer via bulk transfer * @@ -154,15 +158,15 @@ * timeout limit. Thus we don't have to worry about it for individual * packets. */ -static int us_bulk_transfer(struct us_data *us, int pipe, - char *buf, int length) +static int us_transfer_partial(struct us_data *us, int pipe, + char *buf, int length) { int result; int partial; /* transfer the data */ US_DEBUGP("Bulk xfer 0x%x(%d)\n", (unsigned int)buf, length); - result = usb_bulk_msg(us->pusb_dev, pipe, buf, length, &partial, HZ*5); + result = usb_bulk_msg(us->pusb_dev, pipe, buf, length, &partial, HZ); US_DEBUGP("bulk_msg returned %d xferred %d/%d\n", result, partial, length); @@ -181,7 +185,7 @@ if (result) { /* NAK - that means we've retried a few times allready */ if (result == -ETIMEDOUT) { - US_DEBUGP("us_bulk_transfer: device NAKed\n"); + US_DEBUGP("us_transfer_partial(): device NAKed\n"); } return US_BULK_TRANSFER_FAILED; } @@ -195,7 +199,7 @@ * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * - * Note that this uses us_bulk_transfer to achive it's goals -- this + * Note that this uses us_transfer_partial to achieve it's goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately. For now, it also re-interprets the error codes. */ @@ -222,16 +226,16 @@ */ sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) { - result = us_bulk_transfer(us, pipe, sg[i].address, - sg[i].length); + result = us_transfer_partial(us, pipe, sg[i].address, + sg[i].length); if (result) break; } } else /* no scatter-gather, just make the request */ - result = us_bulk_transfer(us, pipe, srb->request_buffer, - srb->request_bufflen); + result = us_transfer_partial(us, pipe, srb->request_buffer, + srb->request_bufflen); /* return the result in the data structure itself */ srb->result = result; @@ -240,12 +244,27 @@ /* Calculate the length of the data transfer (not the command) for any * given SCSI command */ -static unsigned int us_transfer_length(Scsi_Cmnd *srb) +static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us) { int i; unsigned int total = 0; struct scatterlist *sg; + /* support those devices which need the length calculated + * differently + */ + if (us->flags & US_FL_ALT_LENGTH) { + if (srb->cmnd[0] == INQUIRY) { + srb->cmnd[4] = 36; + } + + if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE)) + return srb->cmnd[4]; + + if (srb->cmnd[0] == TEST_UNIT_READY) + return 0; + } + /* Are we going to scatter gather? */ if (srb->use_sg) { /* Add up the sizes of all the scatter-gather segments */ @@ -299,8 +318,10 @@ */ if (us->subclass == US_SC_UFI && ((srb->cmnd[0] == REQUEST_SENSE) || - (srb->cmnd[0] == INQUIRY))) + (srb->cmnd[0] == INQUIRY))) { + US_DEBUGP("** no auto-sense for a special command\n"); need_auto_sense = 0; + } } /* @@ -339,8 +360,13 @@ int temp_result; void* old_request_buffer; int old_sg; + int old_request_bufflen; + unsigned char old_cmnd[MAX_COMMAND_SIZE]; - US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n"); + US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); + + /* save the old command */ + memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE); srb->cmnd[0] = REQUEST_SENSE; srb->cmnd[1] = 0; @@ -351,14 +377,24 @@ /* set the buffer length for transfer */ old_request_buffer = srb->request_buffer; + old_request_bufflen = srb->request_bufflen; old_sg = srb->use_sg; + srb->use_sg = 0; srb->request_bufflen = 18; - srb->request_buffer = us->srb->sense_buffer; + srb->request_buffer = srb->sense_buffer; - /* FIXME: what if this command fails? */ + /* issue the auto-sense command */ temp_result = us->transport(us->srb, us); + if (temp_result == USB_STOR_TRANSPORT_ERROR) { + /* FIXME: we need to invoke a transport reset here */ + US_DEBUGP("-- auto-sense failure\n"); + srb->result = DID_ERROR << 16; + return; + } + US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); - US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", + US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", + srb->sense_buffer[0], srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]); @@ -366,16 +402,32 @@ /* set the result so the higher layers expect this data */ srb->result = CHECK_CONDITION; - /* we're done here */ + /* we're done here, let's clean up */ srb->request_buffer = old_request_buffer; + srb->request_bufflen = old_request_bufflen; srb->use_sg = old_sg; - } + memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); - /* Set return code, if necessary */ - if (need_auto_sense && (srb->sense_buffer[0] == 0x0)) - srb->result = GOOD; - if (!need_auto_sense) + /* If things are really okay, then let's show that */ + if ((srb->sense_buffer[2] & 0xf) == 0x0) + srb->result = GOOD; + } else /* if (need_auto_sense) */ srb->result = GOOD; + + /* Regardless of auto-sense, if we _know_ we have an error + * condition, show that in the result code + */ + if (result == USB_STOR_TRANSPORT_FAILED) + srb->result = CHECK_CONDITION; + + /* If we think we're good, then make sure the sense data shows it. + * This is necessary because the auto-sense for some devices always + * sets byte 0 == 0x70, even if there is no error + */ + if ((us->protocol == US_PR_CB) && + (result == USB_STOR_TRANSPORT_GOOD) && + ((srb->sense_buffer[2] & 0xf) == 0x0)) + srb->sense_buffer[0] = 0x0; } /* @@ -444,7 +496,7 @@ /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (us_transfer_length(srb)) { + if (us_transfer_length(srb, us)) { us_transfer(srb, US_DIRECTION(srb->cmnd[0])); US_DEBUGP("CBI data stage result is 0x%x\n", srb->result); } @@ -454,7 +506,7 @@ /* go to sleep until we get this interrupt */ down(&(us->ip_waitq)); - /* if we were woken up by a reset instead of the actual interrupt */ + /* if we were woken up by an abort instead of the actual interrupt */ if (us->ip_wanted) { US_DEBUGP("Did not get interrupt on CBI\n"); us->ip_wanted = 0; @@ -532,7 +584,7 @@ /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (us_transfer_length(srb)) { + if (us_transfer_length(srb, us)) { us_transfer(srb, US_DIRECTION(srb->cmnd[0])); US_DEBUGP("CB data stage result is 0x%x\n", srb->result); } @@ -558,7 +610,7 @@ /* set up the command wrapper */ bcb.Signature = US_BULK_CB_SIGN; - bcb.DataTransferLength = us_transfer_length(srb); + bcb.DataTransferLength = us_transfer_length(srb, us); bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7; bcb.Tag = srb->serial_number; bcb.Lun = srb->cmnd[1] >> 5; @@ -603,27 +655,31 @@ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); /* get CSW for device status */ + US_DEBUGP("Attempting to get CSW...\n"); result = usb_bulk_msg(us->pusb_dev, pipe, &bcs, - US_BULK_CS_WRAP_LEN, &partial, HZ*5); + US_BULK_CS_WRAP_LEN, &partial, HZ); /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_clear_halt(us->pusb_dev, pipe); - + /* get the status again */ + US_DEBUGP("Attempting to get CSW (2nd try)...\n"); result = usb_bulk_msg(us->pusb_dev, pipe, &bcs, - US_BULK_CS_WRAP_LEN, &partial, HZ*5); + US_BULK_CS_WRAP_LEN, &partial, HZ); /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { + US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); + usb_clear_halt(us->pusb_dev, pipe); return USB_STOR_TRANSPORT_ERROR; } } /* if we still have a failure at this point, we're in trouble */ + US_DEBUGP("Bulk status result = %d\n", result); if (result) { - US_DEBUGP("Bulk status result = %d\n", result); return USB_STOR_TRANSPORT_ERROR; } @@ -1120,14 +1176,14 @@ printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" ); US_DEBUGP("Bus reset requested\n"); // us->transport_reset(us); - return SUCCESS; + return FAILED; } /* FIXME: This doesn't actually reset anything */ static int us_host_reset( Scsi_Cmnd *srb ) { printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" ); - return 0; + return FAILED; } /*********************************************************************** @@ -1136,14 +1192,14 @@ /* we use this macro to help us write into the buffer */ #undef SPRINTF -#define SPRINTF(args...) do { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } while (0) +#define SPRINTF(args...) \ + do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) int usb_stor_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout) { struct us_data *us; char *pos = buffer; - char *tmp_ptr; /* if someone is sending us data, just throw it away */ if (inout) @@ -1167,80 +1223,19 @@ } /* print the controler name */ - SPRINTF ("Host scsi%d: usb-storage\n", hostno); + SPRINTF(" Host scsi%d: usb-storage\n", hostno); - /* print product and vendor strings */ - tmp_ptr = kmalloc(256, GFP_KERNEL); - if (!us->pusb_dev || !tmp_ptr) { - SPRINTF(" Vendor: Unknown Vendor\n"); - SPRINTF(" Product: Unknown Product\n"); - } else { - SPRINTF(" Vendor: "); - if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, tmp_ptr, 256) > 0) - SPRINTF("%s\n", tmp_ptr); - else - SPRINTF("Unknown Vendor\n"); - - SPRINTF(" Product: "); - if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, tmp_ptr, 256) > 0) - SPRINTF("%s\n", tmp_ptr); - else - SPRINTF("Unknown Product\n"); - kfree(tmp_ptr); - } - - SPRINTF(" Protocol: "); - switch (us->protocol) { - case US_PR_CB: - SPRINTF("Control/Bulk\n"); - break; - - case US_PR_CBI: - SPRINTF("Control/Bulk/Interrupt\n"); - break; - - case US_PR_BULK: - SPRINTF("Bulk only\n"); - break; - - default: - SPRINTF("Unknown Protocol\n"); - break; - } - - SPRINTF(" Transport: "); - switch (us->subclass) { - case US_SC_RBC: - SPRINTF("Reduced Block Commands\n"); - break; - - case US_SC_8020: - SPRINTF("8020i\n"); - break; - - case US_SC_QIC: - SPRINTF("QIC-157\n"); - break; - - case US_SC_8070: - SPRINTF("8070i\n"); - break; - - case US_SC_SCSI: - SPRINTF("Transparent SCSI\n"); - break; - - case US_SC_UFI: - SPRINTF("Uniform Floppy Interface\n"); - break; - - default: - SPRINTF("Unknown Transport\n"); - break; - } + /* print product, vendor, and serial number strings */ + SPRINTF(" Vendor: %s\n", us->vendor); + SPRINTF(" Product: %s\n", us->product); + SPRINTF("Serial Number: %s\n", us->serial); + + /* show the protocol and transport */ + SPRINTF(" Protocol: %s\n", us->protocol_name); + SPRINTF(" Transport: %s\n", us->transport_name); /* show the GUID of the device */ - SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); + SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); /* release our lock on the data structures */ up(&us_list_semaphore); @@ -1263,30 +1258,30 @@ */ static Scsi_Host_Template my_host_template = { - name: "usb-storage", - proc_info: usb_stor_proc_info, - info: us_info, - - detect: us_detect, - release: us_release, - command: us_command, - queuecommand: us_queuecommand, + name: "usb-storage", + proc_info: usb_stor_proc_info, + info: us_info, + + detect: us_detect, + release: us_release, + command: us_command, + queuecommand: us_queuecommand, eh_abort_handler: us_abort, eh_device_reset_handler:us_bus_reset, eh_bus_reset_handler: us_bus_reset, eh_host_reset_handler: us_host_reset, - can_queue: 1, - this_id: -1, + can_queue: 1, + this_id: -1, - sg_tablesize: SG_ALL, - cmd_per_lun: 1, - present: 0, - unchecked_isa_dma: FALSE, - use_clustering: TRUE, - use_new_eh_code: TRUE, - emulated: TRUE, + sg_tablesize: SG_ALL, + cmd_per_lun: 1, + present: 0, + unchecked_isa_dma: FALSE, + use_clustering: TRUE, + use_new_eh_code: TRUE, + emulated: TRUE }; static unsigned char sense_notready[] = { @@ -1321,6 +1316,7 @@ */ daemonize(); + /* set our name for identification purposes */ sprintf(current->comm, "usb-storage-%d", us->host_number); unlock_kernel(); @@ -1334,7 +1330,7 @@ down(&(us->queue_exclusion)); US_DEBUGP("*** thread awakened.\n"); - /* take the command off the queue */ + /* take the command off the queue */ action = us->action; us->action = 0; us->srb = us->queue_srb; @@ -1344,10 +1340,14 @@ switch (action) { case US_ACT_COMMAND: - /* bad device */ - if (us->srb->target) { - US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n", - us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev); + /* reject if target != 0 or if single-lun device + * and LUN != 0 + */ + if (us->srb->target || + ((us->flags & US_FL_SINGLE_LUN) && us->srb->lun)) { + US_DEBUGP("Bad device number (%d/%d)\n", + us->srb->target, us->srb->lun); + us->srb->result = DID_BAD_TARGET << 16; us->srb->scsi_done(us->srb); @@ -1355,59 +1355,51 @@ break; } + /* handle those devices which can't do a START_STOP */ + if ((us->srb->cmnd[0] == START_STOP) && + (us->flags & US_FL_START_STOP)) { + us->srb->result = GOOD; + us->srb->scsi_done(us->srb); + us->srb = NULL; + break; + } + /* lock the device pointers */ down(&(us->dev_semaphore)); /* our device has gone - pretend not ready */ - /* FIXME: we also need to handle INQUIRY here, - * probably */ - /* FIXME: fix return codes and sense buffer handling */ if (!us->pusb_dev) { US_DEBUGP("Request is for removed device\n"); + /* For REQUEST_SENSE, it's the data. But + * for anything else, it should look like + * we auto-sensed for it. + */ if (us->srb->cmnd[0] == REQUEST_SENSE) { memcpy(us->srb->request_buffer, sense_notready, sizeof(sense_notready)); - us->srb->result = DID_OK << 16; + us->srb->result = GOOD; } else { - us->srb->result = (DID_OK << 16) | 2; + memcpy(us->srb->sense_buffer, + sense_notready, + sizeof(sense_notready)); + us->srb->result = CHECK_CONDITION; } - - /* unlock the device pointers */ - up(&(us->dev_semaphore)); - - /* indicate that the command is done */ - us->srb->scsi_done(us->srb); - us->srb = NULL; - break; - } - - /* we've got a command, let's do it! */ - US_DEBUG(us_show_command(us->srb)); - - /* FIXME: this is to support Shuttle E-USB bridges, it - * appears */ - if (us->srb->cmnd[0] == START_STOP && - us->pusb_dev->descriptor.idProduct == 0x0001 && - us->pusb_dev->descriptor.idVendor == 0x04e6) - us->srb->result = DID_OK << 16; - else { + } else { /* !us->pusb_dev */ + /* we've got a command, let's do it! */ + US_DEBUG(us_show_command(us->srb)); us->proto_handler(us->srb, us); } - - US_DEBUGP("scsi cmd done, result=0x%x\n", - us->srb->result); /* unlock the device pointers */ up(&(us->dev_semaphore)); /* indicate that the command is done */ + US_DEBUGP("scsi cmd done, result=0x%x\n", + us->srb->result); us->srb->scsi_done(us->srb); us->srb = NULL; break; - - case US_ACT_ABORT: - break; case US_ACT_DEVICE_RESET: break; @@ -1426,22 +1418,71 @@ break; } } /* for (;;) */ - + /* notify the exit routine that we're actually exiting now */ up(&(us->notify)); return 0; } +static struct us_unusual_dev us_unusual_dev_list[] = { + { 0x057b, 0x0000, 0x0114, + "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN }, + { 0x0781, 0x0001, 0x0200, + "Sandisk ImageMate", US_SC_SCSI, US_PR_CB, + US_FL_SINGLE_LUN | US_FL_START_STOP }, + { 0x0781, 0x0002, 0x0009, + "** SECRET DEVICE **", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN }, + { 0x04e6, 0x0002, 0x0100, + "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, + { 0x07af, 0x0005, 0x0100, + "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, + { 0x0000, 0x0000, 0x0, + "", 0, 0, 0} +}; + +/* Search our ususual device list, based on vendor/product combinations + * to see if we can support this device. Returns a pointer to a structure + * defining how we should support this device, or NULL if it's not in the + * list + */ +static struct us_unusual_dev* us_find_dev(__u16 idVendor, __u16 idProduct, + __u16 bcdDevice) +{ + struct us_unusual_dev* ptr; + + US_DEBUGP("Searching unusual device list for (0x%x, 0x%x, 0x%x)...\n", + idVendor, idProduct, bcdDevice); + + ptr = us_unusual_dev_list; + while ((ptr->idVendor != 0x0000) && + !((ptr->idVendor == idVendor) && + (ptr->idProduct == idProduct) && + (ptr->bcdDevice == bcdDevice))) + ptr++; + + /* if the search ended because we hit the end record, we failed */ + if (ptr->idVendor == 0x0000) { + US_DEBUGP("-- did not find a matching device\n"); + return NULL; + } + + /* otherwise, we found one! */ + US_DEBUGP("-- found matching device: %s\n", ptr->name); + return ptr; +} + /* Probe to see if a new device is actually a SCSI device */ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) { int i; - char mf[32]; /* manufacturer */ - char prod[32]; /* product */ - char serial[32]; /* serial number */ + char mf[USB_STOR_STRING_LEN]; /* manufacturer */ + char prod[USB_STOR_STRING_LEN]; /* product */ + char serial[USB_STOR_STRING_LEN]; /* serial number */ + GUID(guid); /* Global Unique Identifier */ + unsigned int flags; + struct us_unusual_dev *unusual_dev; struct us_data *ss = NULL; - GUID(guid); /* Global Unique Identifier */ int result; /* these are temporary copies -- we test on these, then put them @@ -1450,6 +1491,7 @@ __u8 ep_in = 0; __u8 ep_out = 0; __u8 ep_int = 0; + __u8 ep_interval = 0; __u8 subclass = 0; __u8 protocol = 0; @@ -1457,10 +1499,22 @@ struct usb_interface_descriptor *altsetting = &(dev->actconfig->interface[ifnum].altsetting[0]); - /* FIXME: this isn't quite right... */ - /* We make an exception for the shuttle E-USB */ - if (!(dev->descriptor.idVendor == 0x04e6 && - dev->descriptor.idProduct == 0x0001) && + /* clear the temporary strings */ + memset(mf, 0, sizeof(mf)); + memset(prod, 0, sizeof(prod)); + memset(serial, 0, sizeof(serial)); + + /* search for this device in our unusual device list */ + unusual_dev = us_find_dev(dev->descriptor.idVendor, + dev->descriptor.idProduct, + dev->descriptor.bcdDevice); + + /* + * Can we support this device, either because we know about it + * from our unusual device list, or because it advertises that it's + * compliant to the specification? + */ + if (!unusual_dev && !(dev->descriptor.bDeviceClass == 0 && altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE && altsetting->bInterfaceSubClass >= US_SC_MIN && @@ -1473,37 +1527,16 @@ US_DEBUGP("USB Mass Storage device detected\n"); /* Determine subclass and protocol, or copy from the interface */ - /* FIXME: this isn't quite right */ - if (dev->descriptor.idVendor == 0x04e6 && - dev->descriptor.idProduct == 0x0001) { - protocol = US_PR_CB; - subclass = US_SC_8070; /* an assumption */ + if (unusual_dev) { + subclass = unusual_dev->useProtocol; + protocol = unusual_dev->useTransport; + flags = unusual_dev->flags; } else { subclass = altsetting->bInterfaceSubClass; protocol = altsetting->bInterfaceProtocol; + flags = 0; } - - /* shuttle E-USB */ - /* FIXME: all we should need to do here is determine the protocol */ - if (dev->descriptor.idVendor == 0x04e6 && - dev->descriptor.idProduct == 0x0001) { - __u8 qstat[2]; - - result = usb_control_msg(ss->pusb_dev, - usb_rcvctrlpipe(dev,0), - 1, 0xC0, - 0, ss->ifnum, - qstat, 2, HZ*5); - US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]); - init_MUTEX_LOCKED(&(ss->ip_waitq)); - ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); - result = usb_request_irq(ss->pusb_dev, ss->irqpipe, - CBI_irq, 255, (void *)ss, - &ss->irq_handle); - if (result < 0) - return NULL; - } - + /* * Find the endpoints we need * We are expecting a minimum of 2 endpoints - in and out (bulk). @@ -1529,10 +1562,11 @@ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { ep_int = altsetting->endpoint[i].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep_interval = altsetting->endpoint[i].bInterval; } } - US_DEBUGP("Endpoints In %d Out %d Int %d\n", - ep_in, ep_out, ep_int); + US_DEBUGP("Endpoints: In %d Out %d Int %d (Period %d)\n", + ep_in, ep_out, ep_int, ep_interval); /* set the interface -- STALL is an acceptable response here */ result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0); @@ -1542,13 +1576,13 @@ usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); } else if (result != 0) { /* it's not a stall, but another error -- time to bail */ - US_DEBUGP("-- unknown error. rejecting device\n"); + US_DEBUGP("-- Unknown error. Rejecting device\n"); return NULL; } /* Do some basic sanity checks, and bail if we find a problem */ if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) { - US_DEBUGP("Problems with device\n"); + US_DEBUGP("Sanity check failed. Rejecting device.\n"); return NULL; } @@ -1556,9 +1590,6 @@ /* clear the GUID and fetch the strings */ GUID_CLEAR(guid); - memset(mf, 0, sizeof(mf)); - memset(prod, 0, sizeof(prod)); - memset(serial, 0, sizeof(serial)); if (dev->descriptor.iManufacturer) usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf)); @@ -1608,13 +1639,13 @@ init_MUTEX_LOCKED(&(ss->ip_waitq)); /* set up the IRQ pipe and handler */ - /* FIXME: This needs to get period from the device */ US_DEBUGP("Allocating IRQ for CBI transport\n"); ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); result = usb_request_irq(ss->pusb_dev, ss->irqpipe, - CBI_irq, 255, (void *)ss, + CBI_irq, ss->ep_interval, + (void *)ss, &(ss->irq_handle)); - US_DEBUGP("usb_request_irq returned %d\n", result); + US_DEBUGP("-- usb_request_irq returned %d\n", result); } } else { /* New device -- Allocate memory and initialize */ @@ -1637,16 +1668,29 @@ /* copy over the subclass and protocol data */ ss->subclass = subclass; ss->protocol = protocol; + ss->flags = flags; /* copy over the endpoint data */ ss->ep_in = ep_in; ss->ep_out = ep_out; ss->ep_int = ep_int; + ss->ep_interval = ep_interval; /* establish the connection to the new device */ ss->ifnum = ifnum; ss->pusb_dev = dev; + /* copy over the identifiying strings */ + strncpy(ss->vendor, mf, USB_STOR_STRING_LEN); + strncpy(ss->product, prod, USB_STOR_STRING_LEN); + strncpy(ss->serial, serial, USB_STOR_STRING_LEN); + if (strlen(ss->vendor) == 0) + strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN); + if (strlen(ss->product) == 0) + strncpy(ss->product, "Unknown", USB_STOR_STRING_LEN); + if (strlen(ss->serial) == 0) + strncpy(ss->serial, "None", USB_STOR_STRING_LEN); + /* copy the GUID we created before */ memcpy(ss->guid, guid, sizeof(guid)); @@ -1654,81 +1698,91 @@ * Set the handler pointers based on the protocol * Again, this data is persistant across reattachments */ - US_DEBUGP("Transport: "); switch (ss->protocol) { case US_PR_CB: - US_DEBUGPX("Control/Bulk\n"); + ss->transport_name = "Control/Bulk"; ss->transport = CB_transport; ss->transport_reset = CB_reset; break; case US_PR_CBI: - US_DEBUGPX("Control/Bulk/Interrupt\n"); + ss->transport_name = "Control/Bulk/Interrupt"; ss->transport = CBI_transport; ss->transport_reset = CB_reset; break; case US_PR_BULK: - US_DEBUGPX("Bulk\n"); + ss->transport_name = "Bulk"; ss->transport = Bulk_transport; ss->transport_reset = Bulk_reset; break; default: - US_DEBUGPX("Unknown\n"); + ss->transport_name = "Unknown"; + up(&us_list_semaphore); kfree(ss); return NULL; break; } + US_DEBUGP("Transport: %s\n", ss->transport_name); - US_DEBUGP("Protocol: "); switch (ss->subclass) { case US_SC_RBC: - US_DEBUGPX("Reduced Block Commands (RBC)\n"); + ss->protocol_name = "Reduced Block Commands (RBC)"; ss->proto_handler = transparent_scsi_command; break; case US_SC_8020: - US_DEBUGPX("8020i\n"); + ss->protocol_name = "8020i"; ss->proto_handler = ATAPI_command; break; case US_SC_QIC: - US_DEBUGPX("QIC-157\n"); + ss->protocol_name = "QIC-157"; + US_DEBUGP("Sorry, device not supported. Please\n"); + US_DEBUGP("contact mdharm-usb@one-eyed-alien.net\n"); + US_DEBUGP("if you see this message.\n"); + up(&us_list_semaphore); + kfree(ss); + return NULL; break; case US_SC_8070: - US_DEBUGPX("8070i\n"); + ss->protocol_name = "8070i"; ss->proto_handler = ATAPI_command; break; case US_SC_SCSI: - US_DEBUGPX("Transparent SCSI\n"); + ss->protocol_name = "Transparent SCSI"; ss->proto_handler = transparent_scsi_command; break; case US_SC_UFI: - US_DEBUGPX("UFI\n"); + ss->protocol_name = "Uniform Floppy Interface (UFI)"; ss->proto_handler = ufi_command; break; default: - US_DEBUGPX("Unknown\n"); + ss->protocol_name = "Unknown"; + up(&us_list_semaphore); + kfree(ss); + return NULL; break; } + US_DEBUGP("Protocol: %s\n", ss->protocol_name); if (ss->protocol == US_PR_CBI) { /* set up so we'll wait for notification */ init_MUTEX_LOCKED(&(ss->ip_waitq)); /* set up the IRQ pipe and handler */ - /* FIXME: This needs to get period from the device */ US_DEBUGP("Allocating IRQ for CBI transport\n"); ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); result = usb_request_irq(ss->pusb_dev, ss->irqpipe, - CBI_irq, 255, (void *)ss, + CBI_irq, ss->ep_interval, + (void *)ss, &(ss->irq_handle)); - US_DEBUGP("usb_request_irq returned %d\n", result); + US_DEBUGP("-- usb_request_irq returned %d\n", result); } /* diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/usb-storage.h linux/drivers/usb/usb-storage.h --- v2.3.99-pre5/linux/drivers/usb/usb-storage.h Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/usb-storage.h Fri Apr 21 14:03:01 2000 @@ -7,7 +7,8 @@ #include -#define USB_STORAGE "usb-storage: " +#define USB_STORAGE "usb-storage.c: " +#define USB_STOR_STRING_LEN 32 #ifdef CONFIG_USB_STORAGE_DEBUG void us_show_command(Scsi_Cmnd *srb); @@ -128,9 +129,27 @@ } } +/* + * Unusual device list definitions + */ + +struct us_unusual_dev { + /* we search the list based on these parameters */ + __u16 idVendor; + __u16 idProduct; + __u16 bcdDevice; + + /* the list specifies these parameters */ + const char* name; + __u8 useProtocol; + __u8 useTransport; + unsigned int flags; +}; + /* Flag definitions */ -#define US_FL_IP_STATUS 0x00000001 /* status uses interrupt */ -#define US_FL_FIXED_COMMAND 0x00000002 /* expand commands to fixed size */ -#define US_FL_MODE_XLATE 0x00000004 /* translate _6 to _10 comands for +#define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */ +#define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 comands for Win/MacOS compatibility */ -#define US_FL_CBI_AS_CB 0x00000008 /* treat a CBI dev as a CB dev */ +#define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */ +#define US_FL_ALT_LENGTH 0x00000008 /* use the alternate algorithm for + us_transfer_length() */ diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.3.99-pre5/linux/drivers/video/Config.in Tue Apr 11 15:09:21 2000 +++ linux/drivers/video/Config.in Mon Apr 24 13:49:18 2000 @@ -118,7 +118,7 @@ bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD fi tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY - bool ' ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128 + tristate ' ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128 bool ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX fi fi diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c --- v2.3.99-pre5/linux/drivers/video/acornfb.c Thu Feb 10 17:11:15 2000 +++ linux/drivers/video/acornfb.c Tue Apr 25 17:38:33 2000 @@ -1599,7 +1599,7 @@ } current_par.currcon = -1; - current_par.screen_base = SCREEN2_BASE; + current_par.screen_base = SCREEN_BASE; current_par.screen_base_p = SCREEN_START; current_par.using_vram = 0; @@ -1696,7 +1696,8 @@ v_sync = h_sync / (init_var.yres + init_var.upper_margin + init_var.lower_margin + init_var.vsync_len); - printk("Acornfb: %ldkB %cRAM, %s, using %dx%d, %d.%03dkHz, %dHz\n", + printk(KERN_INFO "Acornfb: %ldkB %cRAM, %s, using %dx%d, " + "%d.%03dkHz, %dHz\n", current_par.screen_size / 1024, current_par.using_vram ? 'V' : 'D', VIDC_NAME, init_var.xres, init_var.yres, diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c --- v2.3.99-pre5/linux/drivers/video/aty128fb.c Tue Apr 11 15:09:21 2000 +++ linux/drivers/video/aty128fb.c Mon Apr 24 13:49:18 2000 @@ -180,7 +180,7 @@ #ifndef MODULE static const char *mode_option __initdata = NULL; #endif -#ifndef CONFIG_PPC +#if !defined(CONFIG_PPC) && !defined(__sparc__) static void *bios_seg = NULL; #endif @@ -244,12 +244,13 @@ struct fb_info fb_info; struct fb_info_aty128 *next; struct aty128_constants constants; /* PLL and others */ - unsigned long regbase_phys; /* physical mmio */ + u32 regbase_phys; /* physical mmio */ void *regbase; /* remapped mmio */ - unsigned long frame_buffer_phys; /* physical fb memory */ - unsigned long frame_buffer; /* remaped framebuffer */ - const struct aty128_meminfo *mem; /* onboard mem info */ + u32 frame_buffer_phys; /* physical fb memory */ + u32 frame_buffer; /* remaped framebuffer */ + u32 io_base; /* unmapped io */ u32 vram_size; /* onboard video ram */ + const struct aty128_meminfo *mem; /* onboard mem info */ struct aty128fb_par default_par, current_par; struct display disp; struct display_switch dispsw; /* for cursor and font */ @@ -301,6 +302,7 @@ struct fb_info *fb); static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info); +static int aty128fb_rasterimg(struct fb_info *info, int start); /* @@ -308,8 +310,8 @@ */ int aty128fb_init(void); -static int aty128fbcon_switch(int con, struct fb_info *info); -static void aty128fbcon_blank(int blank, struct fb_info *info); +static int aty128fbcon_switch(int con, struct fb_info *fb); +static void aty128fbcon_blank(int blank, struct fb_info *fb); /* * Internal routines @@ -335,9 +337,9 @@ const struct aty128_chip_info *aci); static struct fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128 *board_list, struct fb_info_aty128 *new_node); -static int aty128find_ROM(struct fb_info_aty128 *info); -#ifndef CONFIG_PPC +#if !defined(CONFIG_PPC) && !defined(__sparc__) static void aty128_get_pllinfo(struct fb_info_aty128 *info); +static int aty128find_ROM(struct fb_info_aty128 *info); #endif static void aty128_timings(struct fb_info_aty128 *info); static void aty128_init_engine(const struct aty128fb_par *par, @@ -385,29 +387,26 @@ static struct fb_ops aty128fb_ops = { aty128fb_open, aty128fb_release, aty128fb_get_fix, aty128fb_get_var, aty128fb_set_var, aty128fb_get_cmap, - aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl + aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl, + NULL, aty128fb_rasterimg }; /* * Functions to read from/write to the mmio registers - * - endian conversions may possibly be avoided by flipping CONFIG_CNTL - * or using the other register aperture? TODO. + * - endian conversions may possibly be avoided by + * using the other register aperture. TODO. */ static inline u32 _aty_ld_le32(volatile unsigned int regindex, const struct fb_info_aty128 *info) { - unsigned long *temp; u32 val; #if defined(__powerpc__) - eieio(); - temp = info->regbase; - asm("lwbrx %0,%1,%2" : "=b"(val) : "b" (regindex), "b" (temp)); + asm("lwbrx %0,%1,%2;eieio" : "=r"(val) : "b"(regindex), "r"(info->regbase)); #else - temp = info->regbase+regindex; - val = readl (temp); + val = readl (info->regbase + regindex); #endif return val; @@ -417,35 +416,23 @@ _aty_st_le32(volatile unsigned int regindex, u32 val, const struct fb_info_aty128 *info) { - unsigned long *temp; - #if defined(__powerpc__) - temp = info->regbase; - asm("stwbrx %0,%1,%2" : : "r" (val), "b" (regindex), "r" (temp) : - "memory"); -#elif defined(__mc68000__) - *((volatile u32 *)(info->regbase+regindex)) = cpu_to_le32(val); + asm("stwbrx %0,%1,%2;eieio" : : "r"(val), "b"(regindex), + "r"(info->regbase) : "memory"); #else - temp = info->regbase+regindex; - writel (val, temp); + writel (val, info->regbase + regindex); #endif } static inline u8 _aty_ld_8(unsigned int regindex, const struct fb_info_aty128 *info) { -#if defined(__powerpc__) - eieio(); -#endif return readb (info->regbase + regindex); } static inline void _aty_st_8(unsigned int regindex, u8 val, const struct fb_info_aty128 *info) { -#if defined(__powerpc__) - eieio(); -#endif writeb (val, info->regbase + regindex); } @@ -466,9 +453,6 @@ _aty_ld_pll(unsigned int pll_index, const struct fb_info_aty128 *info) { -#if defined(__powerpc__) - eieio(); -#endif aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F); return aty_ld_le32(CLOCK_CNTL_DATA); } @@ -478,9 +462,6 @@ _aty_st_pll(unsigned int pll_index, u32 val, const struct fb_info_aty128 *info) { -#if defined(__powerpc__) - eieio(); -#endif aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN); aty_st_le32(CLOCK_CNTL_DATA, val); } @@ -528,7 +509,8 @@ static int __init register_test(const struct fb_info_aty128 *info) { - u32 val, flag = 0; + u32 val; + int flag = 0; val = aty_ld_le32(BIOS_0_SCRATCH); @@ -648,35 +630,34 @@ u32 pitch_value; /* 3D scaler not spoken here */ + wait_for_fifo(1, info); aty_st_le32(SCALE_3D_CNTL, 0x00000000); aty128_reset_engine(info); - pitch_value = par->crtc.pitch; /* fix this up */ + pitch_value = par->crtc.pitch; if (par->crtc.bpp == 24) { pitch_value = pitch_value * 3; } + wait_for_fifo(4, info); /* setup engine offset registers */ - wait_for_fifo(1, info); aty_st_le32(DEFAULT_OFFSET, 0x00000000); /* setup engine pitch registers */ aty_st_le32(DEFAULT_PITCH, pitch_value); /* set the default scissor register to max dimensions */ - wait_for_fifo(1, info); aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF); /* set the drawing controls registers */ - wait_for_fifo(1, info); aty_st_le32(DP_GUI_MASTER_CNTL, GMC_SRC_PITCH_OFFSET_DEFAULT | GMC_DST_PITCH_OFFSET_DEFAULT | GMC_SRC_CLIP_DEFAULT | GMC_DST_CLIP_DEFAULT | GMC_BRUSH_SOLIDCOLOR | - (bpp_to_depth(par->crtc.bpp << 8)) | + (bpp_to_depth(par->crtc.bpp) << 8) | GMC_SRC_DSTCOLOR | GMC_BYTE_ORDER_MSB_TO_LSB | GMC_DP_CONVERSION_TEMP_6500 | @@ -688,7 +669,6 @@ GMC_WRITE_MASK_SET); wait_for_fifo(8, info); - /* clear the line drawing registers */ aty_st_le32(DST_BRES_ERR, 0); aty_st_le32(DST_BRES_INC, 0); @@ -766,23 +746,22 @@ /* input */ xres = var->xres; yres = var->yres; - vxres = var->xres_virtual; - vyres = var->yres_virtual; + vxres = var->xres_virtual; + vyres = var->yres_virtual; xoffset = var->xoffset; yoffset = var->yoffset; - bpp = var->bits_per_pixel; - left = var->left_margin; + bpp = var->bits_per_pixel; + left = var->left_margin; right = var->right_margin; upper = var->upper_margin; lower = var->lower_margin; hslen = var->hsync_len; vslen = var->vsync_len; - sync = var->sync; + sync = var->sync; vmode = var->vmode; - /* check for mode eligibility */ - - /* accept only non interlaced modes */ + /* check for mode eligibility + * accept only non interlaced modes */ if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) return -EINVAL; @@ -796,6 +775,7 @@ if (vyres < yres + yoffset) vyres = yres + yoffset; + /* convert bpp into ATI register depth */ depth = bpp_to_depth(bpp); /* make sure we didn't get an invalid depth */ @@ -804,7 +784,8 @@ return -EINVAL; } - bytpp = mode_bytpp[depth]; + /* convert depth to bpp */ + bytpp = mode_bytpp[depth]; /* make sure there is enough video ram for the mode */ if ((u32)(vxres * vyres * bytpp) > info->vram_size) { @@ -813,24 +794,24 @@ } h_disp = (xres >> 3) - 1; - h_total = (((xres + right + hslen + left) / 8) - 1) & 0xFFFFL; + h_total = (((xres + right + hslen + left) >> 3) - 1) & 0xFFFFL; v_disp = yres - 1; v_total = (yres + upper + vslen + lower - 1) & 0xFFFFL; /* check to make sure h_total and v_total are in range */ - if ((h_total/8 - 1) > 0x1ff || (v_total - 1) > 0x7FF) { + if (((h_total >> 3) - 1) > 0x1ff || (v_total - 1) > 0x7FF) { printk(KERN_ERR "aty128fb: invalid width ranges\n"); return -EINVAL; } - h_sync_wid = (hslen+7)/8; + h_sync_wid = (hslen + 7) >> 3; if (h_sync_wid == 0) h_sync_wid = 1; else if (h_sync_wid > 0x3f) /* 0x3f = max hwidth */ h_sync_wid = 0x3f; - h_sync_strt = h_disp + (right/8); + h_sync_strt = h_disp + (right >> 3); v_sync_wid = vslen; if (v_sync_wid == 0) @@ -855,7 +836,7 @@ crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) | (v_sync_pol << 23); - crtc->pitch = xres >> 3; + crtc->pitch = vxres >> 3; crtc->offset = 0; crtc->offset_cntl = 0; @@ -922,7 +903,7 @@ var->transp.length = 8; break; default: - printk(KERN_ERR "Invalid pixel width\n"); + printk(KERN_ERR "aty128fb: Invalid pixel width\n"); return -EINVAL; } @@ -941,26 +922,27 @@ /* fun with masking */ h_total = crtc->h_total & 0x1ff; - h_disp = (crtc->h_total>>16) & 0xff; - h_sync_strt = (crtc->h_sync_strt_wid>>3) & 0x1ff; + h_disp = (crtc->h_total >> 16) & 0xff; + h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff; h_sync_dly = crtc->h_sync_strt_wid & 0x7; - h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x3f; - h_sync_pol = (crtc->h_sync_strt_wid>>23) & 0x1; + h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x3f; + h_sync_pol = (crtc->h_sync_strt_wid >> 23) & 0x1; v_total = crtc->v_total & 0x7ff; - v_disp = (crtc->v_total>>16) & 0x7ff; + v_disp = (crtc->v_total >> 16) & 0x7ff; v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; - v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f; - v_sync_pol = (crtc->v_sync_strt_wid>>23) & 0x1; + v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f; + v_sync_pol = (crtc->v_sync_strt_wid >> 23) & 0x1; c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; - xres = (h_disp+1) << 3; - yres = v_disp+1; - left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly; - right = (h_sync_strt-h_disp)*8+h_sync_dly; - hslen = h_sync_wid*8; - upper = v_total-v_sync_strt-v_sync_wid; - lower = v_sync_strt-v_disp; + /* do conversions */ + xres = (h_disp + 1) << 3; + yres = v_disp + 1; + left = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly; + right = ((h_sync_strt - h_disp) << 3) + h_sync_dly; + hslen = h_sync_wid << 3; + upper = v_total - v_sync_strt - v_sync_wid; + lower = v_sync_strt - v_disp; vslen = v_sync_wid; sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | @@ -974,13 +956,13 @@ var->yres_virtual = crtc->vyres; var->xoffset = crtc->xoffset; var->yoffset = crtc->yoffset; - var->left_margin = left; + var->left_margin = left; var->right_margin = right; var->upper_margin = upper; var->lower_margin = lower; var->hsync_len = hslen; var->vsync_len = vslen; - var->sync = sync; + var->sync = sync; var->vmode = FB_VMODE_NONINTERLACED; return 0; @@ -990,7 +972,7 @@ static void aty128_set_pll(struct aty128_pll *pll, const struct fb_info_aty128 *info) { - int div3; + u32 div3; unsigned char post_conv[] = /* register values for post dividers */ { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 }; @@ -1003,25 +985,23 @@ aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN); /* write the reference divider */ + aty_pll_wait_readupdate(info); aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider & 0x3ff); aty_pll_writeupdate(info); - aty_pll_wait_readupdate(info); div3 = aty_ld_pll(PPLL_DIV_3); - div3 &= ~PPLL_FB3_DIV_MASK; div3 |= pll->feedback_divider; - div3 &= ~PPLL_POST3_DIV_MASK; div3 |= post_conv[pll->post_divider] << 16; /* write feedback and post dividers */ + aty_pll_wait_readupdate(info); aty_st_pll(PPLL_DIV_3, div3); aty_pll_writeupdate(info); - aty_pll_wait_readupdate(info); + aty_pll_wait_readupdate(info); aty_st_pll(HTOTAL_CNTL, 0); /* no horiz crtc adjustment */ - aty_pll_writeupdate(info); /* clear the reset, just in case */ @@ -1111,7 +1091,7 @@ bpp = 16; n = xclk * fifo_width; - d = pll->vclk*bpp; + d = pll->vclk * bpp; x = round_div(n, d); ron = 4 * m->MB + @@ -1162,13 +1142,6 @@ struct fb_info_aty128 *info) { u32 config; -#ifdef CONFIG_FB_COMPAT_XPMAC -#if 0 /* enable this when macmodes gets updated */ - struct vc_mode disp_info; -#endif - struct fb_var_screeninfo var; - int cmode, vmode; -#endif info->current_par = *par; @@ -1210,31 +1183,15 @@ if (par->accel_flags & FB_ACCELF_TEXT) aty128_init_engine(par, info); -#if 0/*def CONFIG_FB_COMPAT_XPMAC*/ -#if 0 /* use this when macmodes gets updated */ - if (!console_fb_info || console_fb_info == &info->fb_info) { - disp_info.width = ((par->crtc.v_total >> 16) & 0x7ff)+1; - disp_info.height = (((par->crtc.h_total >> 16) & 0xff)+1) << 3; - disp_info.depth = par->crtc.bpp; - disp_info.pitch = par->crtc.vxres*par->crtc.bpp >> 3; - aty128_encode_var(&var, par, info); - if (mac_var_to_vmode(&var, &vmode, &cmode)) - disp_info.mode = 0; - else - disp_info.mode = vmode; - strcpy(disp_info.name, aty128fb_name); - disp_info.fb_address = info->frame_buffer_phys; - disp_info.cmap_adr_address = 0; - disp_info.cmap_data_address = 0; - disp_info.disp_reg_address = info->regbase_phys; - register_compat_xpmac(disp_info); - } -#else +#ifdef CONFIG_FB_COMPAT_XPMAC if (!console_fb_info || console_fb_info == &info->fb_info) { - display_info.width = ((par->crtc.v_total >> 16) & 0x7ff)+1; - display_info.height = (((par->crtc.h_total >> 16) & 0xff)+1) << 3; + struct fb_var_screeninfo var; + int cmode, vmode; + + display_info.height = ((par->crtc.v_total >> 16) & 0x7ff) + 1; + display_info.width = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3; display_info.depth = par->crtc.bpp; - display_info.pitch = par->crtc.vxres*par->crtc.bpp >> 3; + display_info.pitch = (par->crtc.vxres * par->crtc.bpp) >> 3; aty128_encode_var(&var, par, info); if (mac_var_to_vmode(&var, &vmode, &cmode)) display_info.mode = 0; @@ -1245,9 +1202,7 @@ display_info.cmap_adr_address = 0; display_info.cmap_data_address = 0; display_info.disp_reg_address = info->regbase_phys; - register_compat_xpmac(display_info); } -#endif #endif /* CONFIG_FB_COMPAT_XPMAC */ } @@ -1491,15 +1446,15 @@ strcpy(fix->id, aty128fb_name); - fix->smem_start = (long)info->frame_buffer_phys; - fix->mmio_start = (long)info->regbase_phys; + fix->smem_start = (unsigned long)info->frame_buffer_phys; + fix->mmio_start = (unsigned long)info->regbase_phys; - fix->smem_len = (u32)info->vram_size; + fix->smem_len = info->vram_size; fix->mmio_len = 0x1fff; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; - fix->line_length = par->crtc.vxres*par->crtc.bpp >> 3; + fix->line_length = (par->crtc.vxres * par->crtc.bpp) >> 3; fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; fix->ywrapstep = 0; @@ -1547,7 +1502,7 @@ u32 offset; u32 xres, yres; - xres = (((par->crtc.h_total >> 16) & 0xff) + 1) * 8; + xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3; yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1; xoffset = (var->xoffset +7) & ~7; @@ -1617,7 +1572,6 @@ return 0; } - /* * Frame Buffer Specific ioctls */ @@ -1630,6 +1584,18 @@ } +static int +aty128fb_rasterimg(struct fb_info *info, int start) +{ + struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info; + + if (fb->blitter_may_be_busy) + wait_for_idle(fb); + + return 0; +} + + #ifndef MODULE int __init aty128fb_setup(char *options) @@ -1742,12 +1708,13 @@ /* fill in info */ strcpy(info->fb_info.modename, aty128fb_name); - info->fb_info.node = -1; + info->fb_info.node = -1; info->fb_info.fbops = &aty128fb_ops; - info->fb_info.disp = &info->disp; + info->fb_info.disp = &info->disp; strcpy(info->fb_info.fontname, fontname); - info->fb_info.changevar = NULL; + info->fb_info.changevar = NULL; info->fb_info.switch_con = &aty128fbcon_switch; + info->fb_info.updatevar = NULL; info->fb_info.blank = &aty128fbcon_blank; info->fb_info.flags = FBINFO_FLAG_DEFAULT; @@ -1755,7 +1722,7 @@ var = default_var; #else memset(&var, 0, sizeof(var)); -#ifdef CONFIG_FB_COMPAT_XPMAC /* CONFIG_PPC implied */ +#ifdef CONFIG_PPC if (_machine == _MACH_Pmac) { if (mode_option) { if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) @@ -1777,12 +1744,14 @@ if (mac_vmode_to_var(default_vmode, default_cmode, &var)) var = default_var; } + } else { +#endif /* CONFIG_PPC */ + if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, + &defaultmode, initdepth) == 0) + var = default_var; +#ifdef CONFIG_PPC } -#else - if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, - &defaultmode, initdepth) == 0) - var = default_var; -#endif /* CONFIG_FB_COMPAT_XPMAC */ +#endif #endif /* MODULE */ if (noaccel) @@ -1873,35 +1842,36 @@ const struct aty128_chip_info *aci) { struct fb_info_aty128 *info = NULL; - unsigned long fb_addr, reg_addr = 0; - u16 tmp; - - struct resource *rp; + u32 fb_addr, reg_addr, io_addr = 0; + int err; - rp = &pdev->resource[0]; - fb_addr = rp->start; - fb_addr &= PCI_BASE_ADDRESS_MEM_MASK; + /* Request resources we're going to use */ + io_addr = pci_resource_start(pdev, 1); + if (!request_region(io_addr, pci_resource_len(pdev, 1), + "aty128fb IO")) { + printk(KERN_ERR "aty128fb: cannot reserve I/O ports\n"); + goto err_out_none; + } - if (!request_mem_region(rp->start, rp->end - rp->start + 1, + fb_addr = pci_resource_start(pdev, 0); + if (!request_mem_region(fb_addr, pci_resource_len(pdev, 0), "aty128fb FB")) { - release_mem_region(pdev->resource[0].start, - pdev->resource[0].end - - pdev->resource[0].start + 1); - return -1; + printk(KERN_ERR "aty128fb: cannot reserve frame buffer memory\n"); + goto err_free_fb; } - rp = &pdev->resource[2]; - reg_addr = rp->start; - reg_addr &= PCI_BASE_ADDRESS_MEM_MASK; - - if (!request_mem_region(rp->start, rp->end - rp->start + 1, - "aty128fb MMIO")) - goto unmap_out; + reg_addr = pci_resource_start(pdev, 2); + if (!request_mem_region(reg_addr, pci_resource_len(pdev, 2), + "aty128fb MMIO")) { + printk(KERN_ERR "aty128fb: cannot reserve MMIO region\n"); + goto err_free_mmio; + } + /* We have the resources. Now virtualize them */ info = kmalloc(sizeof(struct fb_info_aty128), GFP_ATOMIC); if(!info) { printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n"); - goto unmap_out; + goto err_unmap_out; } memset(info, 0, sizeof(struct fb_info_aty128)); @@ -1913,22 +1883,29 @@ info->regbase = ioremap(reg_addr, 0x1FFF); if (!info->regbase) - goto err_out; + goto err_free_info; - info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF; + /* Store io_base */ + info->io_base = io_addr; - pci_read_config_word(pdev, PCI_COMMAND, &tmp); - if (!(tmp & PCI_COMMAND_MEMORY)) { - tmp |= PCI_COMMAND_MEMORY; - pci_write_config_word(pdev, PCI_COMMAND, tmp); - } + /* Grab memory size from the card */ + info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF; /* Virtualize the framebuffer */ info->frame_buffer_phys = fb_addr; - info->frame_buffer = (unsigned long)ioremap(fb_addr, info->vram_size); + info->frame_buffer = (u32)ioremap(fb_addr, info->vram_size); + + if (!info->frame_buffer) { + iounmap((void *)info->regbase); + goto err_free_info; + } - if (!info->frame_buffer) + /* Enable device in PCI config */ + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n", err); goto err_out; + } /* If we can't test scratch registers, something is seriously wrong */ if (!register_test(info)) { @@ -1936,21 +1913,17 @@ goto err_out; } - if (!aty128find_ROM(info)) { +#if !defined(CONFIG_PPC) && !defined(__sparc__) + if (!aty128find_ROM(info)) printk(KERN_INFO "aty128fb: Rage128 BIOS not located. Guessing...\n"); - aty128_timings(info); - } -#ifndef CONFIG_PPC - else + else aty128_get_pllinfo(info); - - /* free up to-be unused resources. bios_seg is mapped by - * aty128find_ROM() and used by aty128_get_pllinfo() - * - * TODO: make more elegant. doesn't need to be global */ - if (bios_seg) - iounmap(bios_seg); #endif + aty128_timings(info); + + if (!aty128_init(info, "PCI")) + goto err_out; + #ifdef CONFIG_MTRR if (mtrr) { info->mtrr.vram = mtrr_add(info->frame_buffer_phys, info->vram_size, @@ -1961,32 +1934,34 @@ } #endif /* CONFIG_MTRR */ - if (!aty128_init(info, "PCI")) - goto err_out; - return 0; err_out: + iounmap((void *)info->frame_buffer); + iounmap((void *)info->regbase); +err_free_info: kfree(info); -unmap_out: - release_mem_region(pdev->resource[0].start, - pdev->resource[0].end - - pdev->resource[0].start + 1); - release_mem_region(pdev->resource[2].start, - pdev->resource[2].end - - pdev->resource[2].start + 1); - - return -1; +err_unmap_out: + release_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); +err_free_mmio: + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); +err_free_fb: + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); +err_out_none: + return -ENODEV; } #endif /* CONFIG_PCI */ -/* PPC cannot read video ROM, so we fail by default */ +/* PPC and Sparc cannot read video ROM */ +#if !defined(CONFIG_PPC) && !defined(__sparc__) static int __init aty128find_ROM(struct fb_info_aty128 *info) { int flag = 0; -#ifndef CONFIG_PPC u32 segstart; char *rom_base; char *rom; @@ -2043,12 +2018,10 @@ flag = 1; break; } -#endif /* !CONFIG_PPC */ return (flag); } -#ifndef CONFIG_PPC static void __init aty128_get_pllinfo(struct fb_info_aty128 *info) { @@ -2076,11 +2049,12 @@ info->constants.ref_divider = (u32)pll.PCLK_ref_divider; info->constants.dotclock = (u32)pll.PCLK_ref_freq; - aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider); - aty_pll_writeupdate(info); - - info->constants.fifo_width = 128; - info->constants.fifo_depth = 32; + /* free up to be un-used resources. bios_seg is mapped by + * aty128find_ROM() and used by aty128_get_pllinfo() + * + * TODO: make more elegant. doesn't need to be global */ + if (bios_seg) + iounmap(bios_seg); #ifdef DEBUG printk(KERN_DEBUG "get_pllinfo: ppll_max %d ppll_min %d xclk %d " @@ -2089,56 +2063,59 @@ info->constants.xclk, info->constants.ref_divider, info->constants.dotclock); #endif - - switch(aty_ld_le32(MEM_CNTL) & 0x03) { - case 0: - info->mem = &sdr_128; - break; - case 1: - info->mem = &sdr_sgram; - break; - case 2: - info->mem = &ddr_sgram; - break; - default: - info->mem = &sdr_sgram; - } - return; } -#endif /* ! CONFIG_PPC */ +#endif /* !CONFIG_PPC */ /* fill in known card constants if pll_block is not available */ static void __init aty128_timings(struct fb_info_aty128 *info) { - /* TODO make an attempt at probing */ +#ifdef CONFIG_PPC + /* instead of a table lookup, assume OF has properly + * setup the PLL registers and use their values + * to set the XCLK values and reference divider values */ + + u32 x_mpll_ref_fb_div; + u32 xclk_cntl; + u32 Nx, M; + unsigned PostDivSet[] = + { 0, 1, 2, 4, 8, 3, 6, 12 }; +#endif + if (!info->constants.dotclock) info->constants.dotclock = 2950; - /* from documentation */ - if (!info->constants.ppll_min) - info->constants.ppll_min = 12500; - if (!info->constants.ppll_max) - info->constants.ppll_max = 25000; /* 23000 on some cards? */ +#ifdef CONFIG_PPC + x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); + xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; + Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; + M = x_mpll_ref_fb_div & 0x0000ff; + + info->constants.xclk = round_div((2 * Nx * + info->constants.dotclock), (M * PostDivSet[xclk_cntl])); + + info->constants.ref_divider = + aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; +#endif -#if 1 - /* XXX TODO. Calculuate properly. */ - if (!info->constants.ref_divider) + if (!info->constants.ref_divider) { info->constants.ref_divider = 0x3b; - aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider); - aty_pll_writeupdate(info); - aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e); + aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e); + aty_pll_writeupdate(info); + } + aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider); aty_pll_writeupdate(info); -#else - info->constants.ref_divider = aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; -#endif - /* TODO. Calculate */ + /* from documentation */ + if (!info->constants.ppll_min) + info->constants.ppll_min = 12500; + if (!info->constants.ppll_max) + info->constants.ppll_max = 25000; /* 23000 on some cards? */ if (!info->constants.xclk) - info->constants.xclk = 0x1d4d; /* same as mclk */ + info->constants.xclk = 0x1d4d; /* same as mclk */ info->constants.fifo_width = 128; info->constants.fifo_depth = 32; @@ -2225,7 +2202,6 @@ return 0; } - /* * Set a single color register. The values supplied are already * rounded down to the hardware's capabilities (according to the @@ -2314,22 +2290,36 @@ * Accelerated functions */ -static void +static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, u_int width, u_int height, struct fb_info_aty128 *info) { - u32 save_dp_datatype, save_dp_cntl; + u32 save_dp_datatype, save_dp_cntl, bppval; + + if (!width || !height) + return; + + bppval = bpp_to_depth(info->current_par.crtc.bpp); + if (bppval == DST_24BPP) { + srcx *= 3; + dstx *= 3; + width *= 3; + } else if (bppval == -EINVAL) { + printk("aty128fb: invalid depth\n"); + return; + } wait_for_fifo(2, info); save_dp_datatype = aty_ld_le32(DP_DATATYPE); save_dp_cntl = aty_ld_le32(DP_CNTL); wait_for_fifo(6, info); - aty_st_le32(DP_DATATYPE, (BRUSH_SOLIDCOLOR << 16) | SRC_DSTCOLOR); + aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT); aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); - aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); + aty_st_le32(DP_DATATYPE, save_dp_datatype | bppval | SRC_DSTCOLOR); + aty_st_le32(DST_Y_X, (dsty << 16) | dstx); aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); @@ -2338,8 +2328,6 @@ wait_for_fifo(2, info); aty_st_le32(DP_DATATYPE, save_dp_datatype); aty_st_le32(DP_CNTL, save_dp_cntl); - - wait_for_idle(info); } @@ -2569,12 +2557,12 @@ iounmap(info->regbase); iounmap(&info->frame_buffer); - release_mem_region(info->pdev->resource[0].start, - info->pdev->resource[0].end - - info->pdev->resource[0].start + 1); - release_mem_region(info->pdev->resource[2].start, - info->pdev->resource[2].end - - info->pdev->resource[2].start + 1); + release_mem_region(pci_resource_start(info->pdev, 0), + pci_resource_len(info->pdev, 0)); + release_mem_region(pci_resource_start(info->pdev, 1), + pci_resource_len(info->pdev, 1)); + release_mem_region(pci_resource_start(info->pdev, 2), + pci_resource_len(info->pdev, 2)); kfree(info); } diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c --- v2.3.99-pre5/linux/drivers/video/cyber2000fb.c Sun Mar 19 18:35:31 2000 +++ linux/drivers/video/cyber2000fb.c Tue Apr 25 17:38:33 2000 @@ -616,8 +616,8 @@ * mult = reg0xb0.7:0 * div1 = (reg0xb1.5:0 + 1) * div2 = 2^(reg0xb1.7:6) - * fpll should be between 115 and 257 MHz - * (8696ps and 3891ps) + * fpll should be between 115 and 260 MHz + * (8696ps and 3846ps) */ static int cyber2000fb_decode_clock(struct par_info *hw, struct fb_var_screeninfo *var) @@ -631,7 +631,7 @@ /* * Step 1: - * find div2 such that 115MHz < fpll < 257MHz + * find div2 such that 115MHz < fpll < 260MHz * and 0 <= div2 < 4 */ if (current_par.dev_id == PCI_DEVICE_ID_INTERG_2010) @@ -643,7 +643,7 @@ unsigned long new_pll; new_pll = pll_ps / divisors[div2]; - if (8696 > new_pll && new_pll > 3891) { + if (8696 > new_pll && new_pll > 3846) { pll_ps = new_pll; break; } @@ -655,8 +655,10 @@ #if 0 /* * Step 2: - * Find fpll - * fpll = fref * mult / div1 + * Given pll_ps and ref_ps, find: + * pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005 + * where { 0 < div1 < 32, 0 < mult < 256 } + * pll_ps_calc = div1 / (ref_ps * mult) * * Note! This just picks any old values at the moment, * and as such I don't trust it. It certainly doesn't @@ -1172,13 +1174,42 @@ cyber2000fb_ioctl }; +/* + * Enable access to the extended registers + * Bug: this should track the usage of these registers + */ +static void cyber2000fb_enable_extregs(void) +{ + int old; + + old = cyber2000_grphr(FUNC_CTL); + cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL); +} + +/* + * Disable access to the extended registers + * Bug: this should track the usage of these registers + */ +static void cyber2000fb_disable_extregs(void) +{ + int old; + + old = cyber2000_grphr(FUNC_CTL); + cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL); +} + +/* + * Attach a capture/tv driver to the core CyberX0X0 driver. + */ int cyber2000fb_attach(struct cyberpro_info *info) { if (current_par.initialised) { - info->dev = current_par.dev; - info->regs = CyberRegs; - info->fb = current_par.screen_base; - info->fb_size = current_par.screen_size; + info->dev = current_par.dev; + info->regs = CyberRegs; + info->fb = current_par.screen_base; + info->fb_size = current_par.screen_size; + info->enable_extregs = cyber2000fb_enable_extregs; + info->disable_extregs = cyber2000fb_disable_extregs; strncpy(info->dev_name, current_par.dev_name, sizeof(info->dev_name)); @@ -1188,6 +1219,9 @@ return current_par.initialised; } +/* + * Detach a capture/tv driver from the core CyberX0X0 driver. + */ void cyber2000fb_detach(void) { MOD_DEC_USE_COUNT; @@ -1496,7 +1530,7 @@ v_sync = h_sync / (init_var.yres + init_var.upper_margin + init_var.lower_margin + init_var.vsync_len); - printk("%s: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", + printk(KERN_INFO "%s: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", current_par.dev_name, current_par.screen_size >> 10, init_var.xres, init_var.yres, diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/cyber2000fb.h linux/drivers/video/cyber2000fb.h --- v2.3.99-pre5/linux/drivers/video/cyber2000fb.h Sun Mar 19 18:35:31 2000 +++ linux/drivers/video/cyber2000fb.h Tue Apr 25 17:38:33 2000 @@ -26,6 +26,12 @@ cyber2000_outb(val, 0x3cf); } +static inline unsigned int cyber2000_grphr(int reg) +{ + cyber2000_outb(reg, 0x3ce); + return cyber2000_inb(0x3cf); +} + static inline void cyber2000_attrw(int reg, int val) { cyber2000_inb(0x3da); @@ -145,6 +151,9 @@ #define CAP_NEW_CTL2 0x89 +#define BM_CTRL0 0x9c +#define BM_CTRL1 0x9d + #define CAP_MODE1 0xa4 #define CAP_MODE1_8BIT 0x01 /* enable 8bit capture mode */ #define CAP_MODE1_CCIR656 0x02 /* CCIR656 mode */ @@ -244,11 +253,14 @@ /* * Bus-master */ +#define BM_VID_ADDR_LOW 0xbc040 +#define BM_VID_ADDR_HIGH 0xbc044 #define BM_ADDRESS_LOW 0xbc080 #define BM_ADDRESS_HIGH 0xbc084 #define BM_LENGTH 0xbc088 #define BM_CONTROL 0xbc08c #define BM_CONTROL_ENABLE 0x01 /* enable transfer */ +#define BM_CONTROL_IRQEN 0x02 /* enable IRQ at end of transfer */ #define BM_CONTROL_INIT 0x04 /* initialise status & count */ #define BM_COUNT 0xbc090 /* read-only */ @@ -282,6 +294,12 @@ char *fb; char dev_name[32]; unsigned int fb_size; + + /* + * Use these to enable the BM or TV registers. + */ + void (*enable_extregs)(void); + void (*disable_extregs)(void); }; /* diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c --- v2.3.99-pre5/linux/drivers/video/fbcon-iplan2p2.c Mon Oct 11 15:38:15 1999 +++ linux/drivers/video/fbcon-iplan2p2.c Fri Apr 14 09:37:10 2000 @@ -17,7 +17,10 @@ #include #include + +#ifdef __mc68000__ #include +#endif #include