diff -u --recursive --new-file v2.3.16/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.16/linux/Documentation/Configure.help Tue Aug 31 17:29:12 1999 +++ linux/Documentation/Configure.help Tue Sep 7 11:23:40 1999 @@ -4835,8 +4835,8 @@ AMI MegaRAID support CONFIG_SCSI_MEGARAID - This driver supports the AMI MegaRAID 428 and 438 (and maybe 466) - SCSI host adapters. + This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490 + and 467 SCSI host adapters. If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -6043,19 +6043,50 @@ say M here and read Documentation/modules.txt. This is recommended. The module will be called yellowfin.o. +General Instruments Surfboard 1000 +CONFIG_NET_SB1000 + This is a driver for the General Instrument SURFboard 1000 internal cable + modem. This is an ISA card which is used by a number of cable TV companies + to provide cable modem access. It's a one-way downstream-only cable modem, + meaning that your upstream net link is provided by your regular phone modem. + + At present this driver only compiles as a module, so say M here if you + have this card. Then read Documentation/networking/README.sb1000 for + information on how to use this module, as it needs special ppp scripts for + establishing a connection. Further documentation and the necessary scripts + can be found at: + + http://www.jacksonville.net/~fventuri/ + http://home.adelphia.net/~siglercm/sb1000.html + http://linuxpower.cx/~cable/ + + If you don't have this card, of course say N. + Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support CONFIG_ACENIC - Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit - Ethernet adapter. The driver allows for using the Jumbo Frame - option (9000 bytes/frame) however it requires that your switches - can handle this as well. To enable Jumbo Frames, add `mtu 9000' to - your ifconfig line. + Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear + GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet + adapter. The driver allows for using the Jumbo Frame option (9000 + bytes/frame) however it requires that your switches can handle this + as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig + line. If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. This is recommended. The module will be called acenic.o. +Omit support for older Tigon I based AceNICs +CONFIG_ACENIC_OMIT_TIGON_I + Say Y here if you only have Tigon II based AceNICs and want to leave + out support for the older Tigon I based cards which are no longer + being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B + version)). This will reduce the size of the driver object by + app. 100KB. If you are not sure whether your card is a Tigon I or a + Tigon II, say N here. + + The safe and default value for this is N. + AMD LANCE and PCnet (AT1500 and NE2100) support CONFIG_LANCE If you have a network (Ethernet) card of this type, say Y and read @@ -7216,7 +7247,7 @@ You don't want to use the minix filesystem on your hard disk because of certain built-in restrictions, but it is sometimes found on older Linux floppy disks. This option will enlarge your kernel by about - 25 kB. If unsure, say N. + 28 kB. If unsure, say N. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -7242,7 +7273,7 @@ ext2fs is a diskless Linux box which mounts all files over the network using NFS (in this case it's sufficient to say Y to "NFS filesystem support" below). Saying Y here will enlarge your kernel - by about 41 kB. + by about 44 kB. The Ext2fs-Undeletion mini-HOWTO, available via FTP (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini, @@ -7299,6 +7330,25 @@ like lynx or netscape). Say Y here if you want to be able to read Joliet CDROMs under Linux. +UDF Filesystem support +CONFIG_UDF_FS + This is the new filesystem used by some CDROMS and DVD drivers. + Say Y if you intend to mount DVD discs or CDRWs written in packet mode, + or if written to by other UDF utilities, such as DirectCD. + + This filesystem support is also available as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). The module is called udf.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If unsure, say N. + +UDF read-write support (EXPERIMENTAL) +CONFIG_UDF_RW + Say Y if you want to test write support for UDF filesystems. + Due to lack of support for writing to CDR/CDRW's, this option + is only supported for Hard Discs, DVD-RAM, and loopback files. + fat fs support CONFIG_FAT_FS If you want to use one of the FAT-based filesystems (the MS-DOS, @@ -7430,7 +7480,7 @@ that has a program like lynx or netscape), and also on the proc(8) manpage ("man 8 proc"). - This option will enlarge your kernel by about 18 KB. Several + This option will enlarge your kernel by about 67 KB. Several programs depend on this, so everyone should say Y here. NFS filesystem support @@ -7723,6 +7773,18 @@ Say Y to this only if you plan on mounting disks with SGI disklabels. This is not required to mount EFS-format CDROMs. +EFS filesystem support (experimental) +CONFIG_EFS_FS + EFS is the filesystem used for CDROMs and filesystems by SGI's IRIX. + This implementation only offers read-only access. If you don't know + what all this is about, it's safe to say N. For more information + about EFS see it's homepage at http://aeschi.ch.eu.org/efs. + +SGI disklabel support +CONFIG_SGI_DISKLABEL + Say Y to this only if you plan on mounting disks with SGI disklabels. + This is not required to mount EFS-format CDROMs. + BSD disklabel (FreeBSD partition tables) support CONFIG_BSD_DISKLABEL FreeBSD uses its own hard disk partition scheme on your PC. It @@ -8244,6 +8306,16 @@ letters that were missing in Latin 4 to cover the entire Nordic area. +nls iso8859-14 +CONFIG_NLS_ISO8859_14 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 8 character + set, which adds the last accented vowels for Welsh (and Manx Gaelic) + that were missing in Latin 1. http://linux.speech.cymru.org/ + has further information. + nls iso8859-15 CONFIG_NLS_ISO8859_15 If you want to display filenames with native language characters @@ -10091,6 +10163,12 @@ you compiled aedsp16.o as a module you can specify this parameter as 'mpu_irq=NN'. +SGI Visual Workstation on-board audio +CONFIG_SOUND_VWSND + Say Y or M if you have an SGI Visual Workstation and you want to + be able to use its on-board audio. Read Documentation/sound/visws + for more info on this driver's capabilities. + Ensoniq ES1370 based PCI sound cards CONFIG_SOUND_ES1370 Say Y or M if you have a PCI sound card utilizing the Ensoniq @@ -10626,11 +10704,23 @@ If you plan to try to use the kernel on such a machine say Y here. Everybody else says N. +Sun 3 support +CONFIG_SUN3 + This option enables support for the Sun 3 series of workstations. + Be warned that this support is very experimental. You will also + want to say Y to 68020 support and N to the other processors below. + Currently, it is not possible to build a kernel with support for + the Sun 3 and and something else, so make sure you have said N to + all the other machines. This option does not support the sun3x series + of machines (the Sun 3/80 and 3/460). If you don't want to compile a + kernel for a Sun 3, say N. + 68020 support CONFIG_M68020 If you anticipate running this kernel on a computer with a MC68020 processor, say Y. Otherwise, say N. Note that the 68020 requires a - 68851 MMU (Memory Management Unit) to run Linux/m68k. + 68851 MMU (Memory Management Unit) to run Linux/m68k, except on the + Sun 3, which provides its own version. 68030 support CONFIG_M68030 @@ -11082,6 +11172,11 @@ If you want to use the builtin "LANCE" Ethernet controller on an HP300 machine, say Y here. +Sun 3 onboard LANCE support +CONFIG_SUN3LANCE + If you want to use the onboard AMD "LANCE" (le) Ethernet hardware + on a Sun 3, you will need to say Y here. + DIO bus support CONFIG_DIO Say Y here to enable support for the "DIO" expansion bus used in @@ -11751,31 +11846,6 @@ will create two modules called ircomm and ircomm_tty. For more information go to http://www.pluto.dti.ne.jp/~thiguchi/irda/ -IrLPT Protocol -CONFIG_IRLPT - Say Y here if you want to build support for the IrLPT protocol. If - you want to compile it as a module, say M here and read - Documentation/modules.txt. IrLPT makes it possible to print - documents to IrDA capable printers. - -IrLPT Client Protocol -CONFIG_IRLPT_CLIENT - Say Y here if you want to build support for the IrLPT client - protocol. If you want to compile it as a module, say M here and read - Documentation/modules.txt. The IrLPT client protocol can be used to - print documents to IrDA compatible printers like the HP-5MP, or - IrLPT printer adapters like the ACTiSYS IR-100M. - -IrLPT Server Protocol -CONFIG_IRLPT_SERVER - Say Y here if you want to build support for the IrLPT server - protocol. If you want to compile it as a module, say M here and read - Documentation/modules.txt. The IrLPT server protocol makes it - possible to use a Linux machine as an infrared printer server for - other laptops. So if your Linux machine has a cable connection to a - printer, then other laptops can use the Linux machine to print out - documents using infrared communication. - IrTTY IrDA Device Driver CONFIG_IRTTY_SIR Say Y here if you want to build support for the IrTTY line @@ -11869,6 +11939,15 @@ normal 9-pin serial port connector, and can currently only be used by IrTTY. To activate support for Greenwich dongles you will have to insert "irattach -d girbil" in the /etc/irda/drivers script. + +Adaptec Airport 1000 and 2000 dongle +CONFIG_AIRPORT_DONGLE + Say Y here if you want to build support for the Adaptec Airport 1000 + and 2000 dongles. If you want to compile it as a module, say M here + and read Documentation/modules.txt. The Airport dongle attaches to + the normal 9-pin serial port connector, and can currently only be + used by IrTTY. To activate support for Airport dongles you will have + to insert "irattach -d airport" in the /etc/irda/drivers script. Parallax Litelink dongle CONFIG_LITELINK_DONGLE diff -u --recursive --new-file v2.3.16/linux/Documentation/filesystems/00-INDEX linux/Documentation/filesystems/00-INDEX --- v2.3.16/linux/Documentation/filesystems/00-INDEX Sun May 2 09:51:16 1999 +++ linux/Documentation/filesystems/00-INDEX Sat Sep 4 12:42:30 1999 @@ -22,6 +22,8 @@ - info on using filesystems with the SMB protocol (Windows 3.11 and NT) sysv-fs.txt - info on the SystemV/Coherent filesystem. +udf.txt + - info and mount options for the UDF filesystem. ufs.txt - info on the ufs filesystem. umsdos.txt diff -u --recursive --new-file v2.3.16/linux/Documentation/filesystems/udf.txt linux/Documentation/filesystems/udf.txt --- v2.3.16/linux/Documentation/filesystems/udf.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/filesystems/udf.txt Sat Sep 4 12:42:30 1999 @@ -0,0 +1,57 @@ +* +* ./Documentation/filesystems/udf.txt +* +UDF Filesystem version 0.8.9 + +If you encounter problems with reading UDF discs using this driver, +please report them to linux_udf@hootie.lvld.hp.com, which is the +developer's list. + +Write support requires a block driver which supports writing. The current +scsi and ide cdrom drivers do not support writing. + +------------------------------------------------------------------------------- +The following mount options are supported: + + gid= Set the default group. + umask= Set the default umask. + uid= Set the default user. + unhide Show otherwise hidden files. + undelete Show deleted files in lists. + strict Set strict conformance (unused) + utf8 (unused) + iocharset (unused) + +The remaining are for debugging and disaster recovery: + + bs= Set the block size. (may not work unless 2048) + novrs Skip volume sequence recognition + +The following expect a offset from 0. + + session= Set the CDROM session (default= last session) + anchor= Override standard anchor location. (default= 256) + volume= Override the VolumeDesc location. (unused) + partition= Override the PartitionDesc location. (unused) + lastblock= Set the last block of the filesystem/ + +The following expect a offset from the partition root. + + fileset= Override the fileset block location. (unused) + rootdir= Override the root directory location. (unused) + WARNING: overriding the rootdir to a non-directory may + yield highly unpredictable results. +------------------------------------------------------------------------------- + + +For more information see: + http://www.trylinux.com/projects/udf/index.html + +For the latest version and toolset see: + http://www.csc.calpoly.edu/~bfennema/udf.html + +Documentation on UDF and ECMA 167 is available FREE from: + http://www.osta.org/ + http://www.ecma.ch/ + +Ben Fennema diff -u --recursive --new-file v2.3.16/linux/Documentation/networking/PLIP.txt linux/Documentation/networking/PLIP.txt --- v2.3.16/linux/Documentation/networking/PLIP.txt Wed May 20 18:54:34 1998 +++ linux/Documentation/networking/PLIP.txt Tue Sep 7 10:14:36 1999 @@ -49,17 +49,69 @@ SLIP). Performance -========== +=========== PLIP easily outperforms Ethernet cards....(ups, I was dreaming, but it *is* getting late. EOB) +PLIP driver details +------------------- + +The Linux PLIP driver is an implementation of the original Crynwr protocol, +that uses the parallel port subsystem of the kernel in order to properly +share parallel ports between PLIP and other services. + +IRQs and trigger timeouts +========================= + +When a parallel port used for a PLIP driver has an IRQ configured to it, the +PLIP driver is signaled whenever data is sent to it via the cable, such that +when no data is available, the driver isn't being used. + +However, on some machines it is hard, if not impossible, to configure an IRQ +to a certain parallel port, mainly because it is used by some other device. +On these machines, the PLIP driver can be used in IRQ-less mode, where +the PLIP driver would constantly poll the parallel port for data waiting, +and if such data is available, process it. This mode is less efficient than +the IRQ mode, because the driver has to check the parallel port many times +per second, even when no data at all is sent. Some rough measurements +indicate that there isn't a noticeable performance drop when using IRQ-less +mode as compared to IRQ mode as far as the data transfer speed is involved. +There is a performance drop on the machine hosting the driver. + +When the PLIP driver is used in IRQ mode, the timeout used for triggering a +data transfer (the maximal time the PLIP driver would allow the other side +before announcing a timeout, when trying to handshake a transfer of some +data) is, by default, 500usec. As IRQ delivery is more or less immediate, +this timeout is quite sufficient. + +When in IRQ-less mode, the PLIP driver polls the parallel port HZ times +per second (where HZ is typically 100 on most platforms, and 1024 on an +Alpha, as of this writing). Between two such polls, there are 10^6/HZ usecs. +On an i386, for example, 10^6/100 = 10000usec. It is easy to see that it is +quite possible for the trigger timeout to expire between two such polls, as +the timeout is only 500usec long. As a result, it is required to change the +trigger timeout on the *other* side of a PLIP connection, to about +10^6/HZ usecs. If both sides of a PLIP connection are used in IRQ-less mode, +this timeout is required on both sides. + +It appears that in practice, the trigger timeout can be shorter than in the +above calculation. It isn't an important issue, unless the wire is faulty, +in which case a long timeout would stall the machine when, for whatever +reason, bits are dropped. + +A utility that can perform this change in Linux is plipconfig, which is part +of the net-tools package (its location can be found in the +Documentation/Changes file). An example command would be +'plipconfig plipX trigger 10000', where plipX is the appropriate +PLIP device. + PLIP hardware interconnection ----------------------------- PLIP uses several different data transfer methods. The first (and the only one implemented in the early version of the code) uses a standard -printer "null" cable to transfers data four bits at a time using +printer "null" cable to transfer data four bits at a time using data bit outputs connected to status bit inputs. The second data transfer method relies on both machines having @@ -138,18 +190,18 @@ The PLIP driver is compatible with the "Crynwr" parallel port transfer standard in Mode 0. That standard specifies the following protocol: - send header nibble '8' + send header nibble '0x8' count-low octet count-high octet ... data octets checksum octet Each octet is sent as - - >4)&0x0F)> + + >4)&0x0F)> To start a transfer the transmitting machine outputs a nibble 0x08. -The raises the ACK line, triggering an interrupt in the receiving +That raises the ACK line, triggering an interrupt in the receiving machine. The receiving machine disables interrupts and raises its own ACK line. diff -u --recursive --new-file v2.3.16/linux/Documentation/networking/irda.txt linux/Documentation/networking/irda.txt --- v2.3.16/linux/Documentation/networking/irda.txt Thu Dec 17 09:01:03 1998 +++ linux/Documentation/networking/irda.txt Tue Sep 7 10:14:36 1999 @@ -1,13 +1,14 @@ To use the IrDA protocols within Linux you will need to get a suitable copy of the IrDA Utilities. More detailed information about these and associated -programs can be found on http://www.cs.uit.no/~dagb/irda/. +programs can be found on http://www.cs.uit.no/linux-irda/ -For more information about the IrDA protocol stack, see the IR-HOWTO -written by Werner Heuser +For more information about how to use the IrDA protocol stack, see the +IR-HOWTO (http://www.snafu.de/~wehe/IR-HOWTO.html) written by Werner Heuser + -There is an active mailing list for discussing Linux IrDA matters called -linux-irda. To subscribe to it, send a message to Majordomo@list.uit.no -with the words "subscribe linux-irda" in the body of the message, the -subject field is ignored. +There is an active mailing list for discussing Linux-IrDA matters called +linux-irda. To subscribe to it, visit: + + http://www.pasta.cs.uit.no/mailman/listinfo/linux-irda Dag Brattli diff -u --recursive --new-file v2.3.16/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.16/linux/MAINTAINERS Tue Aug 31 17:29:12 1999 +++ linux/MAINTAINERS Tue Sep 7 10:14:36 1999 @@ -104,7 +104,8 @@ ADVANSYS SCSI DRIVER P: Bob Frey M: Bob Frey -W: http://www.advansys.com/linux +W: http://www.advansys.com/linux.html +L: linux-scsi@vger.rutgers.edu S: Maintained AEDSP16 DRIVER @@ -441,7 +442,7 @@ IRDA SUBSYSTEM P: Dag Brattli M: Dag Brattli -L: linux-irda@list.uit.no +L: linux-irda@pasta.cs.uit.no W: http://www.cs.uit.no/linux-irda/ S: Maintained @@ -808,9 +809,7 @@ S: Supported STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS -P: Greg Ungerer M: support@stallion.oz.au -M: gerg@stallion.com W: http://www.stallion.com S: Supported @@ -846,6 +845,13 @@ P: Dario Ballabio M: dario@milano.europe.dg.com L: linux-scsi@vger.rutgers.edu +S: Maintained + +UDF FILESYSTEM +P: Ben Fennema +M: bfennema@falcon.csc.calpoly.edu +L: linux_udf@hootie.lvld.hp.com +W: http://www.trylinux.com/projects/udf/index.html S: Maintained UMSDOS FILESYSTEM diff -u --recursive --new-file v2.3.16/linux/Makefile linux/Makefile --- v2.3.16/linux/Makefile Tue Aug 31 17:29:12 1999 +++ linux/Makefile Fri Sep 3 12:35:08 1999 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 16 +SUBLEVEL = 17 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -144,6 +144,10 @@ ifdef CONFIG_PCI DRIVERS := $(DRIVERS) drivers/pci/pci.a +endif + +ifdef CONFIG_PCMCIA +DRIVERS := $(DRIVERS) drivers/pcmcia/pcmcia.o endif ifdef CONFIG_DIO diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.3.16/linux/arch/alpha/kernel/Makefile Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/Makefile Wed Sep 1 14:37:25 1999 @@ -16,7 +16,7 @@ O_TARGET := kernel.o O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ - ptrace.o time.o fpreg.o semaphore.o pci_syscall.o + ptrace.o time.o fpreg.o semaphore.o OX_OBJS := alpha_ksyms.o @@ -28,12 +28,11 @@ sys_jensen.o sys_miata.o sys_mikasa.o sys_noritake.o \ sys_rawhide.o sys_ruffian.o sys_sable.o sys_sio.o \ sys_sx164.o sys_takara.o sys_rx164.o \ - es1888.o smc37c669.o smc37c93x.o ns87312.o \ - pci.o pci_setup.o + es1888.o smc37c669.o smc37c93x.o ns87312.o pci.o else ifdef CONFIG_PCI -O_OBJS += pci.o pci_setup.o +O_OBJS += pci.o endif # Core logic support diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_apecs.c linux/arch/alpha/kernel/core_apecs.c --- v2.3.16/linux/arch/alpha/kernel/core_apecs.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/core_apecs.c Wed Sep 1 15:34:01 1999 @@ -11,7 +11,6 @@ */ #include -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c --- v2.3.16/linux/arch/alpha/kernel/core_cia.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/core_cia.c Wed Sep 1 15:34:01 1999 @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_lca.c linux/arch/alpha/kernel/core_lca.c --- v2.3.16/linux/arch/alpha/kernel/core_lca.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/core_lca.c Wed Sep 1 15:34:01 1999 @@ -9,7 +9,6 @@ */ #include -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c --- v2.3.16/linux/arch/alpha/kernel/core_mcpcia.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/core_mcpcia.c Wed Sep 1 15:34:01 1999 @@ -6,7 +6,6 @@ * Code common to all MCbus-PCI Adaptor core logic chipsets */ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c --- v2.3.16/linux/arch/alpha/kernel/core_pyxis.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/core_pyxis.c Wed Sep 1 15:34:01 1999 @@ -6,7 +6,6 @@ * Code common to all PYXIS core logic chips. */ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_t2.c linux/arch/alpha/kernel/core_t2.c --- v2.3.16/linux/arch/alpha/kernel/core_t2.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/core_t2.c Wed Sep 1 15:34:01 1999 @@ -9,7 +9,6 @@ * Code common to all T2 core logic chips. */ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.3.16/linux/arch/alpha/kernel/core_tsunami.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/core_tsunami.c Wed Sep 1 15:34:01 1999 @@ -6,7 +6,6 @@ * Code common to all TSUNAMI core logic chips. */ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c --- v2.3.16/linux/arch/alpha/kernel/pci.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/pci.c Wed Sep 1 15:34:01 1999 @@ -6,7 +6,6 @@ * David Mosberger (davidm@cs.arizona.edu) */ -#include #include #include #include @@ -70,19 +69,21 @@ */ static void __init -pci_assign_special(void) +pcibios_assign_special(void) { struct pci_dev *dev; + int i; - /* The first three resources of the Cypress IDE controler need - to remain unchanged. So allocate them as-is. */ - dev = NULL; - while ((dev = pci_find_device(PCI_VENDOR_ID_CONTAQ, - PCI_DEVICE_ID_CONTAQ_82C693, dev))) { - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - pci_record_assignment(dev, 0); - pci_record_assignment(dev, 1); - pci_record_assignment(dev, 2); + /* The first three resources of an IDE controler are often magic, + so leave them unchanged. This is true, for instance, of the + Contaq 82C693 as seen on SX164 and DP264. */ + + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE) + continue; + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (dev->resource[i].flags) + pci_claim_resource(dev, i); } } } @@ -107,40 +108,35 @@ { /* Propogate hose info into the subordinate devices. */ + struct pci_controler *hose = probing_hose; struct pci_dev *dev; - void *sysdata; - sysdata = (bus->parent ? bus->parent->sysdata : bus->sysdata); + bus->resource[0] = hose->io_space; + bus->resource[1] = hose->mem_space; for (dev = bus->devices; dev; dev = dev->sibling) - dev->sysdata = sysdata; + dev->sysdata = hose; } void __init -pcibios_base_address_update(struct pci_dev *dev, int resource) +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) { - struct pci_controler *hose = dev->sysdata; - struct resource *res = &dev->resource[resource]; - unsigned long base, where, size; + unsigned long where, size; u32 reg; - if (res->flags & IORESOURCE_IO) - base = hose->io_space->start; - else - base = hose->mem_space->start; - where = PCI_BASE_ADDRESS_0 + (resource * 4); size = res->end - res->start; pci_read_config_dword(dev, where, ®); - reg = (reg & size) | (((u32)(res->start - base)) & ~size); + reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); pci_write_config_dword(dev, where, reg); /* ??? FIXME -- record old value for shutdown. */ } void __init -pcibios_irq_update(struct pci_dev *dev, u8 irq) +pcibios_update_irq(struct pci_dev *dev, int irq) { - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); /* ??? FIXME -- record old value for shutdown. */ } @@ -186,10 +182,10 @@ } probing_hose = NULL; - pci_assign_special(); - pci_assign_unassigned(alpha_mv.min_io_address, - alpha_mv.min_mem_address); - pci_fixup_irq(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq); + pcibios_assign_special(); + pci_assign_unassigned_resources(alpha_mv.min_io_address, + alpha_mv.min_mem_address); + pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq); pci_set_bus_ranges(); } diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/pci_impl.h linux/arch/alpha/kernel/pci_impl.h --- v2.3.16/linux/arch/alpha/kernel/pci_impl.h Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/pci_impl.h Wed Sep 1 14:37:25 1999 @@ -127,7 +127,6 @@ extern struct pci_controler *hose_head, **hose_tail; extern struct pci_controler *probing_hose; -/* pci_common.c */ extern void common_init_pci(void); extern u8 common_swizzle(struct pci_dev *, u8 *); extern struct pci_controler *alloc_pci_controler(unsigned long *); @@ -136,11 +135,3 @@ extern const char *const pci_io_names[]; extern const char *const pci_mem_names[]; extern const char pci_hae0_name[]; - -/* pci_setup.c */ -void pci_record_assignment(struct pci_dev *dev, int resource); -void pci_assign_unassigned(int, int); -void pci_fixup_irq(u8 (*swizzle)(struct pci_dev *, u8 *), - int (*map_irq)(struct pci_dev *, u8, u8)); -void pci_set_bus_ranges(void); - diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/pci_setup.c linux/arch/alpha/kernel/pci_setup.c --- v2.3.16/linux/arch/alpha/kernel/pci_setup.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/pci_setup.c Wed Dec 31 16:00:00 1969 @@ -1,328 +0,0 @@ -/* - * linux/arch/alpha/kernel/pci_setup.c - * - * Extruded from code written by - * Dave Rusling (david.rusling@reo.mts.dec.com) - * David Mosberger (davidm@cs.arizona.edu) - * David Miller (davem@redhat.com) - */ - -#include -#include -#include -#include -#include - - -#define DEBUG_CONFIG 0 -#if DEBUG_CONFIG -# define DBGC(args) printk args -#else -# define DBGC(args) -#endif - - -void __init -pci_record_assignment(struct pci_dev *dev, int resource) -{ - struct pci_controler *hose = dev->sysdata; - struct resource *res = &dev->resource[resource]; - struct resource *base; - int ok; - - if (res->flags == 0) - return; - if (res->flags & IORESOURCE_IO) - base = hose->io_space; - else - base = hose->mem_space; - - res->start += base->start; - res->end += base->start; - - ok = request_resource(base, res); - - DBGC(("PCI record assignment: (%s) resource %d %s\n", - dev->name, resource, (ok < 0 ? "failed" : "ok"))); -} - -static void inline -pdev_assign_unassigned(struct pci_dev *dev, int min_io, int min_mem) -{ - u32 reg; - u16 cmd; - int i; - - DBGC(("PCI assign resources : (%s)\n", dev->name)); - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct pci_controler *hose; - struct resource *root, *res; - unsigned long size, min, max; - - res = &dev->resource[i]; - - if (res->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - else if (res->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - - /* If it is already assigned or the resource does - not exist, there is nothing to do. */ - if (res->parent != NULL || res->flags == 0UL) - continue; - - hose = dev->sysdata; - - /* Determine the root we allocate from. */ - if (res->flags & IORESOURCE_IO) { - root = hose->io_space; - min = root->start + min_io; - max = root->end; - } else { - root = hose->mem_space; - min = root->start + min_mem; - max = root->end; - } - - size = res->end - res->start + 1; - - DBGC((" for root[%016lx:%016lx]\n" - " res[%016lx:%016lx]\n" - " span[%016lx:%016lx] size[%lx]\n", - root->start, root->end, res->start, res->end, - min, max, size)); - - if (allocate_resource(root, res, size, min, max, size) < 0) { - printk(KERN_ERR - "PCI: Failed to allocate resource %d for %s\n", - i, dev->name); - } - - DBGC((" got res[%016lx:%016lx] for resource %d\n", - res->start, res->end, i)); - - /* Update PCI config space. */ - pcibios_base_address_update(dev, i); - } - - /* Special case, disable the ROM. Several devices act funny - (ie. do not respond to memory space writes) when it is left - enabled. A good example are QlogicISP adapters. */ - - pci_read_config_dword(dev, PCI_ROM_ADDRESS, ®); - reg &= ~PCI_ROM_ADDRESS_ENABLE; - pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg); - - /* All of these (may) have I/O scattered all around and may not - use IO-base address registers at all. So we just have to - always enable IO to these devices. */ - if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED - || (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA - || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE - || (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { - cmd |= PCI_COMMAND_IO; - } - - /* ??? Always turn on bus mastering. */ - cmd |= PCI_COMMAND_MASTER; - - /* Enable the appropriate bits in the PCI command register. */ - pci_write_config_word(dev, PCI_COMMAND, cmd); - - DBGC((" cmd reg 0x%x\n", cmd)); - - /* If this is a PCI bridge, set the cache line correctly. */ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - /* ??? EV4/EV5 cache line is 32 bytes. */ - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, - (64 / sizeof(u32))); - } -} - -void __init -pci_assign_unassigned(int min_io, int min_mem) -{ - struct pci_dev *dev; - - for (dev = pci_devices; dev; dev = dev->next) - pdev_assign_unassigned(dev, min_io, min_mem); -} - -struct pbus_set_ranges_data -{ - int found_vga; - unsigned int io_start, io_end; - unsigned int mem_start, mem_end; -}; - -static void __init -pbus_set_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *outer) -{ - struct pbus_set_ranges_data inner; - struct pci_bus *child; - struct pci_dev *dev; - - inner.found_vga = 0; - inner.mem_start = inner.io_start = ~0; - inner.mem_end = inner.io_end = 0; - - /* Collect information about how our direct children are layed out. */ - for (dev = bus->devices; dev; dev = dev->sibling) { - int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; - if (res->flags & IORESOURCE_IO) { - if (res->start < inner.io_start) - inner.io_start = res->start; - if (res->end > inner.io_end) - inner.io_end = res->end; - } else if (res->flags & IORESOURCE_MEM) { - if (res->start < inner.mem_start) - inner.mem_start = res->start; - if (res->end > inner.mem_end) - inner.mem_end = res->end; - } - } - if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) - inner.found_vga = 1; - } - - /* And for all of the sub-busses. */ - for (child = bus->children; child; child = child->next) - pbus_set_ranges(child, &inner); - - /* Align the values. */ - inner.io_start &= ~(4*1024 - 1); - inner.mem_start &= ~(1*1024*1024 - 1); - if (inner.io_end & (4*1024-1)) - inner.io_end = (inner.io_end | (4*1024 - 1)) + 1; - if (inner.mem_end & (1*1024*1024-1)) - inner.mem_end = (inner.mem_end | (1*1024*1024 - 1)) + 1; - - /* Configure the bridge, if possible. */ - if (bus->self) { - struct pci_dev *bridge = bus->self; - u32 l; - - /* Set up the top and bottom of the PCI I/O segment - for this bus. */ - pci_read_config_dword(bridge, PCI_IO_BASE, &l); - l &= 0xffff0000; - l |= (inner.io_start >> 8) & 0x00f0; - l |= (inner.io_end - 1) & 0xf000; - pci_write_config_dword(bridge, PCI_IO_BASE, l); - - /* - * Clear out the upper 16 bits of IO base/limit. - * Clear out the upper 32 bits of PREF base/limit. - */ - pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0); - pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0); - pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); - - /* Set up the top and bottom of the PCI Memory segment - for this bus. */ - l = (inner.mem_start & 0xfff00000) >> 16; - l |= (inner.mem_end - 1) & 0xfff00000; - pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); - - /* - * Turn off downstream PF memory address range, unless - * there is a VGA behind this bridge, in which case, we - * enable the PREFETCH range to include BIOS ROM at C0000. - * - * NOTE: this is a bit of a hack, done with PREFETCH for - * simplicity, rather than having to add it into the above - * non-PREFETCH range, which could then be bigger than we want. - * We might assume that we could relocate the BIOS ROM, but - * that would depend on having it found by those who need it - * (the DEC BIOS emulator would find it, but I do not know - * about the Xservers). So, we do it this way for now... ;-) - */ - l = (inner.found_vga) ? 0 : 0x0000ffff; - pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); - - /* - * Tell bridge that there is an ISA bus in the system, - * and (possibly) a VGA as well. - */ - l = (inner.found_vga) ? 0x0c : 0x04; - pci_write_config_byte(bridge, PCI_BRIDGE_CONTROL, l); - - /* - * Clear status bits, - * turn on I/O enable (for downstream I/O), - * turn on memory enable (for downstream memory), - * turn on master enable (for upstream memory and I/O). - */ - pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007); - } - - if (outer) { - outer->found_vga |= inner.found_vga; - if (inner.io_start < outer->io_start) - outer->io_start = inner.io_start; - if (inner.io_end > outer->io_end) - outer->io_end = inner.io_end; - if (inner.mem_start < outer->mem_start) - outer->mem_start = inner.mem_start; - if (inner.mem_end > outer->mem_end) - outer->mem_end = inner.mem_end; - } -} - -void __init -pci_set_bus_ranges(void) -{ - struct pci_bus *bus; - - for (bus = pci_root; bus; bus = bus->next) - pbus_set_ranges(bus, NULL); -} - -static void inline -pdev_fixup_irq(struct pci_dev *dev, - u8 (*swizzle)(struct pci_dev *, u8 *), - int (*map_irq)(struct pci_dev *, u8, u8)) -{ - u8 pin, slot; - int irq; - - /* If this device is not on the primary bus, we need to figure out - which interrupt pin it will come in on. We know which slot it - will come in on 'cos that slot is where the bridge is. Each - time the interrupt line passes through a PCI-PCI bridge we must - apply the swizzle function. */ - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - /* Cope with 0 and illegal. */ - if (pin == 0 || pin > 4) - pin = 1; - - /* Follow the chain of bridges, swizzling as we go. */ - slot = (*swizzle)(dev, &pin); - - irq = (*map_irq)(dev, slot, pin); - if (irq == -1) - irq = 0; - dev->irq = irq; - - DBGC(("PCI fixup irq : (%s) got %d\n", dev->name, dev->irq)); - - /* Always tell the device, so the driver knows what is - the real IRQ to use; the device does not use it. */ - pcibios_irq_update(dev, irq); -} - -void __init -pci_fixup_irq(u8 (*swizzle)(struct pci_dev *, u8 *), - int (*map_irq)(struct pci_dev *, u8, u8)) -{ - struct pci_dev *dev; - - for (dev = pci_devices; dev; dev = dev->next) - pdev_fixup_irq(dev, swizzle, map_irq); -} diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/pci_syscall.c linux/arch/alpha/kernel/pci_syscall.c --- v2.3.16/linux/arch/alpha/kernel/pci_syscall.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/pci_syscall.c Wed Dec 31 16:00:00 1969 @@ -1,148 +0,0 @@ -/* - * pci_syscall.c - */ - -#include -#include -#include -#include -#include - - -#ifndef CONFIG_PCI - -asmlinkage int sys_pciconfig_read() { return -ENOSYS; } -asmlinkage int sys_pciconfig_write() { return -ENOSYS; } - -#else - -asmlinkage long -sys_pciconfig_read(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, void *buf) -{ - struct pci_dev *dev; - u8 byte; - u16 word; - u32 dword; - long err, cfg_ret; - - err = -EPERM; - if (!capable(CAP_SYS_ADMIN)) - goto error; - - err = -ENODEV; - dev = pci_find_slot(bus, dfn); - if (!dev) - goto error; - - lock_kernel(); - switch (len) { - case 1: - cfg_ret = pci_read_config_byte(dev, off, &byte); - break; - case 2: - cfg_ret = pci_read_config_word(dev, off, &word); - break; - case 4: - cfg_ret = pci_read_config_dword(dev, off, &dword); - break; - default: - err = -EINVAL; - unlock_kernel(); - goto error; - }; - unlock_kernel(); - - err = -EIO; - if (cfg_ret != PCIBIOS_SUCCESSFUL) - goto error; - - switch (len) { - case 1: - err = put_user(byte, (unsigned char *)buf); - break; - case 2: - err = put_user(word, (unsigned short *)buf); - break; - case 4: - err = put_user(dword, (unsigned int *)buf); - break; - }; - return err; - -error: - /* ??? XFree86 doesn't even check the return value. They - just look for 0xffffffff in the output, since that's what - they get instead of a machine check on x86. */ - switch (len) { - case 1: - put_user(-1, (unsigned char *)buf); - break; - case 2: - put_user(-1, (unsigned short *)buf); - break; - case 4: - put_user(-1, (unsigned int *)buf); - break; - }; - return err; -} - -asmlinkage long -sys_pciconfig_write(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, void *buf) -{ - struct pci_dev *dev; - u8 byte; - u16 word; - u32 dword; - int err = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!pcibios_present()) - return -ENOSYS; - - dev = pci_find_slot(bus, dfn); - if (!dev) - return -ENODEV; - - lock_kernel(); - switch(len) { - case 1: - err = get_user(byte, (u8 *)buf); - if (err) - break; - err = pci_write_config_byte(dev, off, byte); - if (err != PCIBIOS_SUCCESSFUL) - err = -EIO; - break; - - case 2: - err = get_user(word, (u16 *)buf); - if (err) - break; - err = pci_write_config_byte(dev, off, word); - if (err != PCIBIOS_SUCCESSFUL) - err = -EIO; - break; - - case 4: - err = get_user(dword, (u32 *)buf); - if (err) - break; - pci_write_config_byte(dev, off, dword); - if (err != PCIBIOS_SUCCESSFUL) - err = -EIO; - break; - - default: - err = -EINVAL; - break; - }; - unlock_kernel(); - - return err; -} - -#endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c --- v2.3.16/linux/arch/alpha/kernel/sys_rawhide.c Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/kernel/sys_rawhide.c Wed Sep 1 15:34:01 1999 @@ -24,7 +24,6 @@ #include #include #include -#include #include "proto.h" #include "irq_impl.h" diff -u --recursive --new-file v2.3.16/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.3.16/linux/arch/arm/kernel/bios32.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/bios32.c Wed Sep 1 15:34:01 1999 @@ -5,7 +5,6 @@ * * Bits taken from various places. */ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.3.16/linux/arch/arm/mm/proc-sa110.S Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/mm/proc-sa110.S Wed Sep 1 15:34:01 1999 @@ -6,7 +6,6 @@ * These are the low level assembler for performing cache and TLB * functions on the sa110. */ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.16/linux/arch/i386/config.in Tue Aug 31 17:29:12 1999 +++ linux/arch/i386/config.in Fri Sep 3 13:19:52 1999 @@ -5,6 +5,7 @@ mainmenu_name "Linux Kernel Configuration" define_bool CONFIG_X86 y +define_bool CONFIG_ISA y mainmenu_option next_comment comment 'Code maturity level options' @@ -82,6 +83,8 @@ define_bool CONFIG_X86_LOCAL_APIC y fi fi + +source drivers/pcmcia/Config.in bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT diff -u --recursive --new-file v2.3.16/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.16/linux/arch/i386/defconfig Tue Aug 31 17:29:12 1999 +++ linux/arch/i386/defconfig Tue Sep 7 10:49:32 1999 @@ -2,6 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_X86=y +CONFIG_ISA=y # # Code maturity level options @@ -50,6 +51,12 @@ # CONFIG_VISWS is not set CONFIG_X86_IO_APIC=y CONFIG_X86_LOCAL_APIC=y + +# +# PCMCIA/Cardbus support +# +CONFIG_PCMCIA=y +CONFIG_CARDBUS=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -358,6 +365,7 @@ # CONFIG_VFAT_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_UDF_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set @@ -373,6 +381,8 @@ # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +CONFIG_NFSD=y +# CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set diff -u --recursive --new-file v2.3.16/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.3.16/linux/arch/i386/kernel/apm.c Tue Aug 31 17:29:12 1999 +++ linux/arch/i386/kernel/apm.c Wed Sep 1 14:19:08 1999 @@ -1391,7 +1391,7 @@ } } #endif - if (((apm_bios_info.flags & APM_BIOS_DISABLED) == 0) + if (((apm_bios_info.flags & APM_BIOS_DISENGAGED) == 0) && (apm_bios_info.version > 0x0100)) { if (apm_engage_power_management(0x0001) == APM_SUCCESS) apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; diff -u --recursive --new-file v2.3.16/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.3.16/linux/arch/i386/kernel/entry.S Thu Jul 29 15:18:50 1999 +++ linux/arch/i386/kernel/entry.S Sat Sep 4 13:06:08 1999 @@ -145,7 +145,30 @@ andl $-8192,%ebx # GET_CURRENT movl exec_domain(%ebx),%edx # Get the execution domain movl 4(%edx),%edx # Get the lcall7 handler for the domain + pushl $0x7 call *%edx + addl $4, %esp + popl %eax + jmp ret_from_sys_call + +ENTRY(lcall27) + pushfl # We get a different stack layout with call gates, + pushl %eax # which has to be cleaned up later.. + SAVE_ALL + movl EIP(%esp),%eax # due to call gates, this is eflags, not eip.. + movl CS(%esp),%edx # this is eip.. + movl EFLAGS(%esp),%ecx # and this is cs.. + movl %eax,EFLAGS(%esp) # + movl %edx,EIP(%esp) # Now we move them to their "normal" places + movl %ecx,CS(%esp) # + movl %esp,%ebx + pushl %ebx + andl $-8192,%ebx # GET_CURRENT + movl exec_domain(%ebx),%edx # Get the execution domain + movl 4(%edx),%edx # Get the lcall7 handler for the domain + pushl $0x27 + call *%edx + addl $4, %esp popl %eax jmp ret_from_sys_call diff -u --recursive --new-file v2.3.16/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.16/linux/arch/i386/kernel/setup.c Tue Aug 31 17:29:12 1999 +++ linux/arch/i386/kernel/setup.c Sat Sep 4 12:00:42 1999 @@ -266,14 +266,14 @@ char saved_command_line[COMMAND_LINE_SIZE]; struct resource standard_io_resources[] = { - { "dma1", 0x00, 0x1f }, - { "pic1", 0x20, 0x3f }, - { "timer", 0x40, 0x5f }, - { "keyboard", 0x60, 0x6f }, - { "dma page reg", 0x80, 0x8f }, - { "pic2", 0xa0, 0xbf }, - { "dma2", 0xc0, 0xdf }, - { "fpu", 0xf0, 0xff } + { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, + { "pic1", 0x20, 0x3f, IORESOURCE_BUSY }, + { "timer", 0x40, 0x5f, IORESOURCE_BUSY }, + { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY }, + { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, + { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY }, + { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, + { "fpu", 0xf0, 0xff, IORESOURCE_BUSY } }; #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) @@ -284,7 +284,7 @@ static struct resource ram_resources[] = { { "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY }, { "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY }, - { "Video RAM area", 0x0a0000, 0x0bffff }, + { "Video RAM area", 0x0a0000, 0x0bffff, IORESOURCE_BUSY }, { "Kernel code", 0x100000, 0 }, { "Kernel data", 0, 0 } }; @@ -293,7 +293,7 @@ #define MAXROMS 6 static struct resource rom_resources[MAXROMS] = { { "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY }, - { "Video ROM", 0xc0000, 0xc7fff } + { "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_BUSY } }; #define romsignature(x) (*(unsigned short *)(x) == 0xaa55) @@ -337,6 +337,7 @@ rom_resources[roms].start = base; rom_resources[roms].end = base + length - 1; rom_resources[roms].name = "Extension ROM"; + rom_resources[roms].flags = IORESOURCE_BUSY; request_resource(&iomem_resource, rom_resources + roms); roms++; @@ -354,6 +355,7 @@ rom_resources[roms].start = base; rom_resources[roms].end = base + 65535; rom_resources[roms].name = "Extension ROM"; + rom_resources[roms].flags = IORESOURCE_BUSY; request_resource(&iomem_resource, rom_resources + roms); } diff -u --recursive --new-file v2.3.16/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.3.16/linux/arch/i386/kernel/smp.c Wed Aug 18 11:34:50 1999 +++ linux/arch/i386/kernel/smp.c Tue Sep 7 10:03:07 1999 @@ -731,7 +731,11 @@ value = apic_read(APIC_SPIV); value |= (1<<8); /* Enable APIC (bit==1) */ +#if 0 value &= ~(1<<9); /* Enable focus processor (bit==0) */ +#else + value |= (1<<9); /* Disable focus processor (bit==1) */ +#endif value |= 0xff; /* Set spurious IRQ vector to 0xff */ apic_write(APIC_SPIV,value); diff -u --recursive --new-file v2.3.16/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.3.16/linux/arch/i386/kernel/traps.c Wed Aug 18 11:27:34 1999 +++ linux/arch/i386/kernel/traps.c Sat Sep 4 13:06:08 1999 @@ -46,8 +46,10 @@ asmlinkage int system_call(void); asmlinkage void lcall7(void); +asmlinkage void lcall27(void); -struct desc_struct default_ldt = { 0, 0 }; +struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 } }; /* * The IDT has to be page-aligned to simplify the Pentium @@ -67,8 +69,8 @@ { \ tsk->thread.error_code = error_code; \ tsk->thread.trap_no = trapnr; \ - force_sig(signr, tsk); \ die_if_no_fixup(str,regs,error_code); \ + force_sig(signr, tsk); \ } #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \ @@ -696,9 +698,11 @@ set_system_gate(SYSCALL_VECTOR,&system_call); /* - * default LDT is a single-entry callgate to lcall7 + * default LDT is a single-entry callgate to lcall7 for iBCS + * and a callgate to lcall27 for Solaris/x86 binaries */ - set_call_gate(&default_ldt,lcall7); + set_call_gate(&default_ldt[0],lcall7); + set_call_gate(&default_ldt[4],lcall27); /* * on SMP we do not yet know which CPU is on which TSS, diff -u --recursive --new-file v2.3.16/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.3.16/linux/arch/i386/mm/init.c Tue Aug 31 17:29:12 1999 +++ linux/arch/i386/mm/init.c Tue Sep 7 10:38:21 1999 @@ -375,7 +375,6 @@ int datapages = 0; int initpages = 0; unsigned long tmp; - unsigned long addr; int i, avail; end_mem &= PAGE_MASK; @@ -413,17 +412,27 @@ /* walk the whitelist, unreserving good memory */ for (avail = i = 0; i < e820.nr_map; i++) { + unsigned long addr, end, size; + if (e820.map[i].type != 1) /* not usable memory */ continue; - printk("memory region: %luk @ %08lx\n", - ((long)(e820.map[i].size)) / 1024, - (long)(e820.map[i].addr) ); - for (addr=PAGE_ALIGN(((long)(e820.map[i].addr)))+PAGE_OFFSET, - tmp = 0; - tmp < (unsigned long)(e820.map[i].size); - tmp += PAGE_SIZE, - addr += PAGE_SIZE) { + addr = e820.map[i].addr; + size = e820.map[i].size; + + /* Overflow large memory reasonably gracefully */ + if (addr != e820.map[i].addr) + continue; + + printk("memory region: %luk @ %08lx\n", size >> 10, addr ); + + /* Make sure we don't get fractional pages */ + end = (addr + size) & PAGE_MASK; + addr = PAGE_ALIGN(addr); + if (end <= addr) + continue; + size = end - addr; + for (addr = addr + PAGE_OFFSET ; size ; addr += PAGE_SIZE, size -= PAGE_SIZE) { /* this little bit of grossness is for dealing * with memory borrowing for system bookkeeping * (smp stacks, zero page, kernel code, etc) @@ -437,9 +446,11 @@ * in any case, we don't want to hack mem_map * entries above end_mem. */ - if ( (addr < start_low_mem) - || (addr >= HIGH_MEMORY && addr <= start_mem) - || (addr > end_mem) ) + if ( addr < start_low_mem ) + continue; + if ( addr > end_mem ) + continue; + if ( addr >= HIGH_MEMORY && addr <= start_mem ) continue; avail++; diff -u --recursive --new-file v2.3.16/linux/arch/m68k/Makefile linux/arch/m68k/Makefile --- v2.3.16/linux/arch/m68k/Makefile Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/Makefile Sat Sep 4 13:06:41 1999 @@ -24,7 +24,11 @@ CROSS_COMPILE = m68k-linux- endif +ifndef CONFIG_SUN3 LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds +else +LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux-sun3.lds -N +endif # without -fno-strength-reduce the 53c7xx.c driver fails ;-( CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 @@ -50,7 +54,11 @@ CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g endif +ifndef CONFIG_SUN3 HEAD := arch/m68k/kernel/head.o +else +HEAD := arch/m68k/kernel/sun3-head.o +endif SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES) @@ -106,6 +114,11 @@ SUBDIRS := $(SUBDIRS) arch/m68k/sun3x endif +ifdef CONFIG_SUN3 +CORE_FILES := $(CORE_FILES) arch/m68k/sun3/sun3.o arch/m68k/sun3/prom/promlib.a +SUBDIRS := $(SUBDIRS) arch/m68k/sun3 arch/m68k/sun3/prom +endif + ifdef CONFIG_M68040 CORE_FILES := $(CORE_FILES) arch/m68k/fpsp040/fpsp.o SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040 @@ -132,7 +145,7 @@ vmlinux.gz: vmlinux -ifdef CONFIG_KGDB +ifndef CONFIG_KGDB cp vmlinux vmlinux.tmp $(STRIP) vmlinux.tmp gzip -9c vmlinux.tmp >vmlinux.gz @@ -141,8 +154,21 @@ gzip -9c vmlinux >vmlinux.gz endif +bzImage: vmlinux.bz2 + +vmlinux.bz2: vmlinux + +ifndef CONFIG_KGDB + cp vmlinux vmlinux.tmp + $(STRIP) vmlinux.tmp + bzip2 -1c vmlinux.tmp >vmlinux.bz2 + rm vmlinux.tmp +else + bzip2 -1c vmlinux >vmlinux.bz2 +endif + archclean: - rm -f vmlinux.gz + rm -f vmlinux.gz vmlinux.bz2 rm -f arch/m68k/kernel/m68k_defs.h arch/m68k/kernel/m68k_defs.d archmrproper: diff -u --recursive --new-file v2.3.16/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c --- v2.3.16/linux/arch/m68k/amiga/amiints.c Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/amiga/amiints.c Sat Sep 4 13:06:41 1999 @@ -117,7 +117,7 @@ cia_init_IRQ(&ciab_base); } -static inline void amiga_insert_irq(irq_node_t **list, irq_node_t *node) +static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node) { unsigned long flags; irq_node_t *cur; @@ -133,7 +133,7 @@ if (node->flags & SA_INTERRUPT) { if (node->flags & SA_SHIRQ) - return; + return -EBUSY; /* * There should never be more than one */ @@ -152,6 +152,7 @@ *list = node; restore_flags(flags); + return 0; } static inline void amiga_delete_irq(irq_node_t **list, void *dev_id) @@ -186,6 +187,7 @@ unsigned long flags, const char *devname, void *dev_id) { irq_node_t *node; + int error = 0; if (irq >= AMI_IRQS) { printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, @@ -218,7 +220,7 @@ node->dev_id = dev_id; node->devname = devname; node->next = NULL; - amiga_insert_irq(&ami_irq_list[irq], node); + error = amiga_insert_irq(&ami_irq_list[irq], node); } else { ami_irq_list[irq]->handler = handler; ami_irq_list[irq]->flags = flags; @@ -230,7 +232,7 @@ if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq]) custom.intena = IF_SETCLR | ami_intena_vals[irq]; - return 0; + return error; } void amiga_free_irq(unsigned int irq, void *dev_id) diff -u --recursive --new-file v2.3.16/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c --- v2.3.16/linux/arch/m68k/atari/stdma.c Tue Aug 31 17:29:12 1999 +++ linux/arch/m68k/atari/stdma.c Sat Sep 4 13:06:41 1999 @@ -29,6 +29,7 @@ #include +#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v2.3.16/linux/arch/m68k/config.in Thu Aug 26 13:05:34 1999 +++ linux/arch/m68k/config.in Sat Sep 4 13:06:41 1999 @@ -198,8 +198,8 @@ fi fi if [ "$CONFIG_MAC" = "y" ]; then - bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI - dep_tristate 'MAC NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI + bool 'Macintosh NCR5380 SCSI' CONFIG_MAC_SCSI + dep_tristate 'Macintosh NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI fi #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI @@ -329,19 +329,19 @@ if [ "$CONFIG_AMIGA" = "y" ]; then tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE if [ "$CONFIG_AMIGAMOUSE" != "n" ]; then - define_bool CONFIG_MOUSE y + define_bool CONFIG_BUSMOUSE y fi fi if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari mouse support' CONFIG_ATARIMOUSE if [ "$CONFIG_ATARIMOUSE" != "n" ]; then - define_bool CONFIG_MOUSE y + define_bool CONFIG_BUSMOUSE y fi fi if [ "$CONFIG_MAC" = "y" ]; then bool 'Mac ADB mouse support' CONFIG_ADBMOUSE if [ "$CONFIG_ADBMOUSE" != "n" ]; then - define_bool CONFIG_MOUSE y + define_bool CONFIG_BUSMOUSE y fi fi if [ "$CONFIG_ATARI" = "y" ]; then @@ -381,7 +381,7 @@ bool 'Sun keyboard support' CONFIG_SUN_KEYBOARD bool 'Sun mouse support' CONFIG_SUN_MOUSE if [ "$CONFIG_SUN_MOUSE" != "n" ]; then - define_bool CONFIG_MOUSE y + define_bool CONFIG_BUSMOUSE y fi define_bool CONFIG_SBUS y define_bool CONFIG_SBUSCHAR y diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile --- v2.3.16/linux/arch/m68k/kernel/Makefile Thu Dec 17 09:06:29 1998 +++ linux/arch/m68k/kernel/Makefile Sat Sep 4 13:06:41 1999 @@ -10,11 +10,16 @@ .S.o: $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o +ifndef CONFIG_SUN3 all: head.o kernel.o +else +all: sun3-head.o kernel.o +endif + O_TARGET := kernel.o O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \ - setup.o sys_m68k.o time.o -OX_OBJS := m68k_ksyms.o + sys_m68k.o time.o semaphore.o +OX_OBJS := setup.o m68k_ksyms.o ifdef CONFIG_KGDB O_OBJS += kgdb.o @@ -25,6 +30,8 @@ endif head.o: head.S m68k_defs.h + +sun3-head.o: sun3-head.S m68k_defs.h m68k_defs.h: m68k_defs.c m68k_defs.head rm -f m68k_defs.d diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S --- v2.3.16/linux/arch/m68k/kernel/entry.S Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/kernel/entry.S Sat Sep 4 13:06:41 1999 @@ -72,6 +72,16 @@ pea SYMBOL_NAME(ret_from_exception) jmp SYMBOL_NAME(schedule) + | After a fork we jump here directly from resume, + | so that %d1 contains the previous task + | Theoretically only needed on SMP, but let's watch + | what happens in schedule_tail() in future... +ENTRY(ret_from_fork) + movel %d1,%sp@- + jsr SYMBOL_NAME(schedule_tail) + addql #4,%sp + jra SYMBOL_NAME(ret_from_exception) + badsys: movel #-ENOSYS,PT_D0(%sp) jra SYMBOL_NAME(ret_from_exception) @@ -88,16 +98,6 @@ subql #4,%sp | dummy return address SAVE_SWITCH_STACK jbsr SYMBOL_NAME(syscall_trace) - - | After a fork we jump here directly from resume, - | so that %d1 contains the previous task - | Theoretically only needed on SMP, but let's watch - | what happens in schedule_tail() in future... -ENTRY(ret_from_fork) - movel %d1,%sp@- - jsr SYMBOL_NAME(schedule_tail) - addql #4,%sp - jra SYMBOL_NAME(ret_from_exception) SYMBOL_NAME_LABEL(ret_from_signal) RESTORE_SWITCH_STACK diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/kgdb.c linux/arch/m68k/kernel/kgdb.c --- v2.3.16/linux/arch/m68k/kernel/kgdb.c Thu Jul 30 11:08:19 1998 +++ linux/arch/m68k/kernel/kgdb.c Sat Sep 4 13:06:41 1999 @@ -189,6 +189,11 @@ #include #include #endif +#ifdef CONFIG_MAC +#include +#include +#include +#endif #undef DEBUG @@ -239,6 +244,15 @@ extern int amiga_ser_out( unsigned char c ); extern unsigned char amiga_ser_in( void ); #endif +#ifdef CONFIG_MAC +static unsigned char mac_scca_in( void ); +static unsigned char mac_scca_out( unsigned char c ); +static unsigned char mac_scca_intr( void ); +static unsigned char mac_sccb_in( void ); +static unsigned char mac_sccb_out( unsigned char c); +static unsigned char mac_sccb_intr( void ); +extern void mac_init_scc_port( int cflag, int port ); +#endif /************************* End of Prototypes **************************/ @@ -668,6 +682,31 @@ } #endif +#ifdef CONFIG_MAC + if (MACH_IS_MAC) { + if (!strcmp( m68k_debug_device, "ser" ) || + !strcmp( m68k_debug_device, "ser1" )) { + mac_init_scc_port( B9600|CS8, 0 ); + serial_in = mac_scca_in; + serial_out = mac_scca_out; + serial_intr = mac_scca_intr; + } else if (!strcmp( m68k_debug_device, "ser2" )) { + mac_init_scc_port( B9600|CS8, 1 ); + serial_in = mac_sccb_in; + serial_out = mac_sccb_out; + serial_intr = mac_sccb_intr; + } + } + if (!serial_in || !serial_out) { + if (*m68k_debug_device) + printk( "kgdb_init failed: no valid serial device!\n" ); + else + printk( "kgdb not enabled\n" ); + return; + } + request_irq(4, kgdb_intr, IRQ_TYPE_FAST, "kgdb", NULL); +#endif + #ifdef CONFIG_ATARI if (!serial_in || !serial_out) { if (*m68k_debug_device) @@ -781,8 +820,15 @@ /* copy format/vector word */ " movew %a0@("FRAMEOFF_VECTOR"),%a1@("GDBOFF_VECTOR")\n" /* save FPU regs */ +#ifndef CONFIG_M68KFPU_EMU_ONLY +#ifdef CONFIG_M68KFPU_EMU + " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n" + " jeq 1f\n" +#endif " fmovemx %fp0-%fp7,%a1@("GDBOFF_FP0")\n" " fmoveml %fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n" + "1:\n" +#endif /* CONFIG_M68KFPU_EMU_ONLY */ /* set stack to CPU frame */ " addl #"FRAMEOFF_SR",%a0\n" @@ -801,8 +847,15 @@ /* after return, first restore FPU registers */ " movel #"SYMBOL_NAME_STR(kgdb_registers)",%a0\n" /* source */ +#ifndef CONFIG_M68KFPU_EMU_ONLY +#ifdef CONFIG_M68KFPU_EMU + " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n" + " jeq 1f\n" +#endif " fmovemx %a0@("GDBOFF_FP0"),%fp0-%fp7\n" " fmoveml %a0@("GDBOFF_FPCTL"),%fpcr/%fpsr/%fpiar\n" + "1:\n" +#endif /* CONFIG_M68KFPU_EMU_ONLY */ /* set new stack pointer */ " movel %a0@("GDBOFF_A7"),%sp\n" " clrw %sp@-\n" /* fake format $0 frame */ @@ -849,8 +902,15 @@ /* fake format 0 and vector 1 (translated to SIGINT) */ " movew #4,%a1@("GDBOFF_VECTOR")\n" /* save FPU regs */ +#ifndef CONFIG_M68KFPU_EMU_ONLY +#ifdef CONFIG_M68KFPU_EMU + " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n" + " jeq 1f\n" +#endif " fmovemx %fp0-%fp7,%a1@("GDBOFF_FP0")\n" " fmoveml %fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n" + "1:\n" +#endif /* CONFIG_M68KFPU_EMU_ONLY */ /* pop off the CPU stack frame */ " addql #8,%sp\n" " movel %sp,%a1@("GDBOFF_A7")\n" /* save a7 now */ @@ -1188,6 +1248,114 @@ } scc.cha_b_ctrl = 0x38; /* reset highest IUS */ MFPDELAY(); + return( c ); +} + +#endif + +/* -------------------- Macintosh serial I/O -------------------- */ + +#ifdef CONFIG_MAC + +struct SCC + { + u_char cha_b_ctrl; + u_char char_dummy1; + u_char cha_a_ctrl; + u_char char_dummy2; + u_char cha_b_data; + u_char char_dummy3; + u_char cha_a_data; + }; + +#define scc (*((volatile struct SCC*)mac_bi_data.sccbase)) + +#define uSEC 1 +#define LONG_DELAY() \ + do { \ + int i; \ + for( i = 60*uSEC; i > 0; --i ) \ + barrier(); \ + } while(0) + +static unsigned char mac_sccb_out (unsigned char c) +{ + int i; + do { + LONG_DELAY(); + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + for( i = uSEC; i > 0; --i ) + barrier(); + scc.cha_b_data = c; +} + +static unsigned char mac_scca_out (unsigned char c) +{ + int i; + do { + LONG_DELAY(); + } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */ + for( i = uSEC; i > 0; --i ) + barrier(); + scc.cha_a_data = c; +} + +static unsigned char mac_sccb_in( void ) +{ + do { + LONG_DELAY(); + } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ + LONG_DELAY(); + return( scc.cha_b_data ); +} + +static unsigned char mac_scca_in( void ) + +{ + do { + LONG_DELAY(); + } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */ + LONG_DELAY(); + return( scc.cha_a_data ); +} + +static unsigned char mac_sccb_intr( void ) + +{ unsigned char c, stat; + + LONG_DELAY(); + scc.cha_b_ctrl = 1; /* RR1 */ + LONG_DELAY(); + stat = scc.cha_b_ctrl; + LONG_DELAY(); + c = scc.cha_b_data; + LONG_DELAY(); + if (stat & 0x30) { + scc.cha_b_ctrl = 0x30; /* error reset for overrun and parity */ + LONG_DELAY(); + } + scc.cha_b_ctrl = 0x38; /* reset highest IUS */ + LONG_DELAY(); + return( c ); +} + +static unsigned char mac_scca_intr( void ) + +{ unsigned char c, stat; + + LONG_DELAY(); + scc.cha_a_ctrl = 1; /* RR1 */ + LONG_DELAY(); + stat = scc.cha_a_ctrl; + LONG_DELAY(); + c = scc.cha_a_data; + LONG_DELAY(); + if (stat & 0x30) { + scc.cha_a_ctrl = 0x30; /* error reset for overrun and parity */ + LONG_DELAY(); + } + scc.cha_a_ctrl = 0x38; /* reset highest IUS */ + LONG_DELAY(); return( c ); } diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c --- v2.3.16/linux/arch/m68k/kernel/m68k_ksyms.c Mon Aug 9 12:27:30 1999 +++ linux/arch/m68k/kernel/m68k_ksyms.c Sat Sep 4 13:06:41 1999 @@ -38,11 +38,14 @@ EXPORT_SYMBOL(mm_ptov); EXPORT_SYMBOL(mm_end_of_chunk); #endif -EXPORT_SYMBOL(mm_vtop_fallback); EXPORT_SYMBOL(m68k_realnum_memory); EXPORT_SYMBOL(m68k_memory); +#ifndef CONFIG_SUN3 +EXPORT_SYMBOL(mm_vtop_fallback); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(kernel_set_cachemode); +#endif EXPORT_SYMBOL(m68k_debug_device); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_thread); @@ -53,7 +56,6 @@ EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); -EXPORT_SYMBOL(kernel_set_cachemode); EXPORT_SYMBOL(kernel_thread); /* Networking helper routines. */ @@ -67,6 +69,7 @@ EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL_NOVERS(memscan); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c --- v2.3.16/linux/arch/m68k/kernel/process.c Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/kernel/process.c Sat Sep 4 13:06:41 1999 @@ -45,7 +45,7 @@ struct mm_struct init_mm = INIT_MM(init_mm); union task_union init_task_union -__attribute__((section("init_task"), aligned(THREAD_SIZE))) +__attribute__((section("init_task"), aligned(KTHREAD_SIZE))) = { task: INIT_TASK(init_task_union.task) }; asmlinkage void ret_from_fork(void); @@ -90,10 +90,14 @@ { if (mach_reset) mach_reset(); + for (;;); } void machine_halt(void) { + if (mach_halt) + mach_halt(); + for (;;); } void machine_power_off(void) @@ -101,6 +105,10 @@ #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) apm_set_power_state(APM_STATE_OFF); #endif + + if (mach_power_off) + mach_power_off(); + for (;;); } void show_regs(struct pt_regs * regs) @@ -138,7 +146,7 @@ "trap #0\n\t" /* Linux/m68k system call */ "tstl %0\n\t" /* child or parent */ "jne 1f\n\t" /* parent - jump */ - "lea %%sp@(-8192),%6\n\t" /* reload current */ + "lea %%sp@(%c7),%6\n\t" /* reload current */ "movel %3,%%sp@-\n\t" /* push argument */ "jsr %4@\n\t" /* call fn */ "movel %0,%%d1\n\t" /* pass exit value */ @@ -147,7 +155,8 @@ "1:" : "=d" (retval) : "0" (__NR_clone), "i" (__NR_exit), - "r" (arg), "a" (fn), "d" (clone_arg), "r" (current) + "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), + "i" (-KTHREAD_SIZE) : "d0", "d2"); pid = retval; } @@ -204,7 +213,7 @@ struct switch_stack * childstack, *stack; unsigned long stack_offset, *retp; - stack_offset = THREAD_SIZE - sizeof(struct pt_regs); + stack_offset = KTHREAD_SIZE - sizeof(struct pt_regs); childregs = (struct pt_regs *) ((unsigned long) p + stack_offset); *childregs = *regs; diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/semaphore.c linux/arch/m68k/kernel/semaphore.c --- v2.3.16/linux/arch/m68k/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/kernel/semaphore.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,129 @@ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v2.3.16/linux/arch/m68k/kernel/setup.c Tue Aug 31 17:29:12 1999 +++ linux/arch/m68k/kernel/setup.c Sat Sep 4 13:06:41 1999 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -76,6 +77,8 @@ int (*mach_hwclk) (int, struct hwclk_time*) = NULL; int (*mach_set_clock_mmss) (unsigned long) = NULL; void (*mach_reset)( void ); +void (*mach_halt)( void ) = NULL; +void (*mach_power_off)( void ) = NULL; long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ #if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD) void (*mach_floppy_setup) (char *, int *) __initdata = NULL; @@ -100,6 +103,9 @@ #ifdef CONFIG_HEARTBEAT void (*mach_heartbeat) (int) = NULL; #endif +#ifdef CONFIG_M68K_L2_CACHE +void (*mach_l2_flush) (int) = NULL; +#endif extern void base_trap_init(void); @@ -118,7 +124,7 @@ extern void config_amiga(void); extern void config_atari(void); extern void config_mac(void); -extern void config_sun3(void); +extern void config_sun3(unsigned long *, unsigned long *); extern void config_apollo(void); extern void config_mvme147(void); extern void config_mvme16x(void); @@ -127,8 +133,10 @@ extern void config_q40(void); extern void config_sun3x(void); -#define MASK_256K 0xfffc0000 +extern void mac_debugging_short (int, short); +extern void mac_debugging_long (int, long); +#define MASK_256K 0xfffc0000 static void __init m68k_parse_bootinfo(const struct bi_record *record) { @@ -205,13 +213,22 @@ else if (CPU_IS_060) m68k_is040or060 = 6; +#ifndef CONFIG_SUN3 base_trap_init(); +#endif + /* FIXME: m68k_fputype is passed in by Penguin booter, which can + * be confused by software FPU emulation. BEWARE. + * We should really do our own FPU check at startup. + * [what do we do with buggy 68LC040s? if we have problems + * with them, we should add a test to check_bugs() below] */ +#ifndef CONFIG_M68KFPU_EMU_ONLY /* clear the fpu if we have one */ if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { volatile int zero = 0; asm __volatile__ ("frestore %0" : : "m" (zero)); } +#endif init_mm.start_code = PAGE_OFFSET; init_mm.end_code = (unsigned long) &_etext; @@ -272,7 +289,7 @@ #endif #ifdef CONFIG_SUN3 case MACH_SUN3: - config_sun3(); + config_sun3(memory_start_p, memory_end_p); break; #endif #ifdef CONFIG_APOLLO @@ -321,10 +338,12 @@ } #endif +#ifndef CONFIG_SUN3 *memory_start_p = availmem; *memory_end_p = 0; for (i = 0; i < m68k_num_memory; i++) *memory_end_p += m68k_memory[i].size & MASK_256K; +#endif } int get_cpuinfo(char * buffer) @@ -354,6 +373,9 @@ clockfactor = 0; } +#ifdef CONFIG_M68KFPU_EMU_ONLY + fpu="none(soft float)"; +#else if (m68k_fputype & FPU_68881) fpu = "68881"; else if (m68k_fputype & FPU_68882) @@ -366,6 +388,7 @@ fpu = "Sun FPA"; else fpu = "none"; +#endif if (m68k_mmutype & MMU_68851) mmu = "68851"; @@ -452,6 +475,9 @@ m68k_unregister_serial(i); #endif } +EXPORT_SYMBOL(register_serial); +EXPORT_SYMBOL(unregister_serial); + #ifdef CONFIG_SERIAL_CONSOLE long serial_console_init(long kmem_start, long kmem_end) { @@ -461,6 +487,8 @@ #endif #if defined(M68K_SERIAL) && defined(CONFIG_SERIAL_CONSOLE) return m68k_serial_console_init(kmem_start, kmem_end); +#else + return kmem_start; #endif } #endif @@ -496,7 +524,7 @@ void check_bugs(void) { -#ifndef CONFIG_FPU_EMU +#ifndef CONFIG_M68KFPU_EMU if (m68k_fputype == 0) { printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " "WHICH IS REQUIRED BY LINUX/M68K ***\n" ); diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/sun3-head.S linux/arch/m68k/kernel/sun3-head.S --- v2.3.16/linux/arch/m68k/kernel/sun3-head.S Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/kernel/sun3-head.S Sat Sep 4 13:06:41 1999 @@ -0,0 +1,102 @@ +#include +#include + +#include +#include +#include + +PSL_HIGHIPL = 0x2700 +NBSG = 0x20000 +ICACHE_ONLY = 0x00000009 +CACHES_OFF = 0x00000008 | actually a clear and disable --m +#define MAS_STACK INT_STACK +ROOT_TABLE_SIZE = 128 +PAGESIZE = 8192 + +.globl SYMBOL_NAME(bootup_user_stack) +.globl SYMBOL_NAME(bootup_kernel_stack) +.globl SYMBOL_NAME(pg0) +.globl SYMBOL_NAME(empty_bad_page) +.globl SYMBOL_NAME(empty_bad_page_table) +.globl SYMBOL_NAME(empty_zero_page) +.globl SYMBOL_NAME(swapper_pg_dir) +.globl SYMBOL_NAME(kernel_pmd_table) +.global SYMBOL_NAME(m68k_pgtable_cachemode) +.global SYMBOL_NAME(kpt) +| todo: all these should be in bss! +SYMBOL_NAME(swapper_pg_dir): .skip 0x2000 +SYMBOL_NAME(pg0): .skip 0x2000 +SYMBOL_NAME(empty_bad_page): .skip 0x2000 +SYMBOL_NAME(empty_bad_page_table): .skip 0x2000 +SYMBOL_NAME(kernel_pmd_table): .skip 0x2000 +SYMBOL_NAME(empty_zero_page): .skip 0x2000 + +.globl SYMBOL_NAME(kernel_pg_dir) +.equ SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(kernel_pmd_table) + + .section .head +ENTRY(_stext) +ENTRY(_start) + +/* Firstly, disable interrupts and set up function codes. */ + movew #PSL_HIGHIPL, %sr + moveq #FC_CONTROL, %d0 + movec %d0, %sfc + movec %d0, %dfc + +/* Make sure we're in context zero. */ + moveq #0, %d0 + movsb %d0, AC_CONTEXT + +/* Copy mappings for first megabyte of RAM to address 0xE000000. */ + lea (AC_SEGMAP+0),%a0 + lea (AC_SEGMAP+KERNBASE),%a1 + moveq #(0x140000/NBSG-1),%d0 +1: movsb %a0@,%d1 + movsb %d1,%a1@ + addl #NBSG,%a0 + addl #NBSG,%a1 + dbf %d0,1b + +/* Disable caches and jump to high code. */ + moveq #ICACHE_ONLY,%d0 | Cache disabled until we're ready to enable it + movc %d0, %cacr | is this the right value? (yes --m) + jmp 1f:l + +/* Following code executes at high addresses (0xE000xxx). */ +1: lea SYMBOL_NAME(init_task_union),%a2 | get initial thread... + lea %a2@(KTHREAD_SIZE),%sp | ...and its stack. + +/* copy bootinfo records from the loader to _end */ + lea SYMBOL_NAME(_end), %a1 + lea BI_START, %a0 + /* number of longs to copy */ + movel %a0@, %d0 +1: addl #4, %a0 + movel %a0@, %a1@ + addl #4, %a1 + dbf %d0, 1b + +/* Point MSP at an invalid page to trap if it's used. --m */ + movl #(PAGESIZE),%d0 + movc %d0,%msp + moveq #-1,%d0 + movsb %d0,(AC_SEGMAP+0x0) + + jbsr SYMBOL_NAME(sun3_init) + + jbsr SYMBOL_NAME(start_kernel) + trap #15 + + .data + .even +SYMBOL_NAME_LABEL(kpt) + .long 0 +SYMBOL_NAME_LABEL(availmem) + .long 0 +| todo: remove next two. --m +SYMBOL_NAME_LABEL(is_medusa) + .long 0 +SYMBOL_NAME_LABEL(m68k_pgtable_cachemode) + .long 0 + diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c --- v2.3.16/linux/arch/m68k/kernel/traps.c Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/kernel/traps.c Sat Sep 4 13:06:41 1999 @@ -47,7 +47,9 @@ asmlinkage void trap(void); asmlinkage void inthandler(void); asmlinkage void nmihandler(void); +#ifdef CONFIG_M68KFPU_EMU asmlinkage void fpu_emu(void); +#endif e_vector vectors[256] = { 0, 0, buserr, trap, trap, trap, trap, trap, @@ -68,8 +70,17 @@ void __init base_trap_init(void) { +#ifdef CONFIG_SUN3 + /* Keep the keyboard interrupt working with PROM for debugging. --m */ + e_vector *old_vbr; + __asm__ volatile ("movec %%vbr,%1\n\t" + "movec %0,%%vbr" + : "=&r" (old_vbr) : "r" ((void*)vectors)); + vectors[0x1E] = old_vbr[0x1E]; /* Copy int6 vector. */ +#else /* setup the exception vector table */ __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); +#endif if (CPU_IS_040 && !FPU_IS_EMU) { /* set up FPSP entry points */ @@ -143,6 +154,10 @@ if (MACH_IS_AMIGA) { vectors[VEC_INT7] = nmihandler; } +#ifdef CONFIG_SUN3 + /* Moved from setup_arch() */ + base_trap_init(); +#endif } @@ -175,11 +190,17 @@ "MMU CONFIGURATION ERROR" }; +#ifndef CONFIG_SUN3 static char *space_names[] = { "Space 0", "User Data", "User Program", "Space 3", "Space 4", "Super Data", "Super Program", "CPU" }; - +#else +static char *space_names[] = { + "Space 0", "User Data", "User Program", "Control", + "Space 4", "Super Data", "Super Program", "CPU" + }; +#endif void die_if_kernel(char *,struct pt_regs *,int); asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, @@ -330,6 +351,17 @@ #endif errorcode = ((mmusr & MMU_R_040) ? 1 : 0) | ((ssw & RW_040) ? 0 : 2); +#ifdef CONFIG_FTRACE + { + unsigned long flags; + + save_flags(flags); + cli(); + do_ftrace(0xfa000000 | errorcode); + do_ftrace(mmusr); + restore_flags(flags); + } +#endif do_page_fault (&fp->ptregs, addr, errorcode); } else { printk ("68040 access error, ssw=%x\n", ssw); @@ -363,6 +395,132 @@ } #endif /* CONFIG_M68040 */ +#if defined(CONFIG_SUN3) +#include + +extern int mmu_emu_handle_fault (unsigned long, int, int); + +/* sun3 version of bus_error030 */ + +extern inline void bus_error030 (struct frame *fp) +{ + unsigned char buserr_type = sun3_get_buserr (); + unsigned long addr, errorcode; + unsigned short ssw = fp->un.fmtb.ssw; + +#if DEBUG + if (ssw & (FC | FB)) + printk ("Instruction fault at %#010lx\n", + ssw & FC ? + fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 + : + fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); + if (ssw & DF) + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); +#endif + + /* + * Check if this page should be demand-mapped. This needs to go before + * the testing for a bad kernel-space access (demand-mapping applies + * to kernel accesses too). + */ + + if ((ssw & DF) + && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) { + if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0)) + return; + } + + /* Check for kernel-space pagefault (BAD). */ + if (fp->ptregs.sr & PS_S) { + /* kernel fault must be a data fault to user space */ + if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { + // try checking the kernel mappings before surrender + if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1)) + return; + /* instruction fault or kernel data fault! */ + if (ssw & (FC | FB)) + printk ("Instruction fault at %#010lx\n", + fp->ptregs.pc); + if (ssw & DF) { + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); + } + printk ("BAD KERNEL BUSERR\n"); + + die_if_kernel("Oops", &fp->ptregs,0); + force_sig(SIGKILL, current); + return; + } + } else { + /* user fault */ + if (!(ssw & (FC | FB)) && !(ssw & DF)) + /* not an instruction fault or data fault! BAD */ + panic ("USER BUSERR w/o instruction or data fault"); + } + + + /* First handle the data fault, if any. */ + if (ssw & DF) { + addr = fp->un.fmtb.daddr; + +// errorcode bit 0: 0 -> no page 1 -> protection fault +// errorcode bit 1: 0 -> read fault 1 -> write fault + +// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault +// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault + + if (buserr_type & SUN3_BUSERR_PROTERR) + errorcode = 0x01; + else if (buserr_type & SUN3_BUSERR_INVALID) + errorcode = 0x00; + else { + printk ("*** unexpected busfault type=%#04x\n", buserr_type); + printk ("invalid %s access at %#lx from pc %#lx\n", + !(ssw & RW) ? "write" : "read", addr, + fp->ptregs.pc); + die_if_kernel ("Oops", &fp->ptregs, buserr_type); + force_sig (SIGSEGV, current); + return; + } + +//todo: wtf is RM bit? --m + if (!(ssw & RW) || ssw & RM) + errorcode |= 0x02; + + /* Handle page fault. */ + do_page_fault (&fp->ptregs, addr, errorcode); + + /* Retry the data fault now. */ + return; + } + + /* Now handle the instruction fault. */ + + /* Get the fault address. */ + if (fp->ptregs.format == 0xA) + addr = fp->ptregs.pc + 4; + else + addr = fp->un.fmtb.baddr; + if (ssw & FC) + addr -= 2; + + if (buserr_type & SUN3_BUSERR_INVALID) { + if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0)) + do_page_fault (&fp->ptregs, addr, 0); + } else { +#ifdef DEBUG + printk ("protection fault on insn access (segv).\n"); +#endif + force_sig (SIGSEGV, current); + } +} +#else #if defined(CPU_M68020_OR_M68030) static inline void bus_error030 (struct frame *fp) { @@ -568,6 +726,7 @@ : "a" (addr)); } #endif /* CPU_M68020_OR_M68030 */ +#endif /* !CONFIG_SUN3 */ asmlinkage void buserr_c(struct frame *fp) { diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/Makefile linux/arch/m68k/mac/Makefile --- v2.3.16/linux/arch/m68k/mac/Makefile Sat Jun 13 13:14:32 1998 +++ linux/arch/m68k/mac/Makefile Sat Sep 4 13:06:41 1999 @@ -7,11 +7,9 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -EXTRA_CFLAGS := -Wa,-m68020 - O_TARGET := mac.o -O_OBJS := config.o bootparse.o macints.o via6522.o \ - mackeyb.o adb-bus.o macboing.o debug.o OX_OBJS := mac_ksyms.o +O_OBJS := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \ + macboing.o debug.o misc.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/bootparse.c linux/arch/m68k/mac/bootparse.c --- v2.3.16/linux/arch/m68k/mac/bootparse.c Thu Feb 12 16:30:13 1998 +++ linux/arch/m68k/mac/bootparse.c Sat Sep 4 13:06:41 1999 @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c --- v2.3.16/linux/arch/m68k/mac/config.c Tue Aug 31 17:29:12 1999 +++ linux/arch/m68k/mac/config.c Sat Sep 4 13:06:41 1999 @@ -37,7 +37,20 @@ #include #include -#include "via6522.h" +#include +#include +#include +#include + +/* Offset between Unix time (1970-based) and Mac time (1904-based) */ + +#define MAC_TIME_OFFSET 2082844800 + +/* + * hardware reset vector + */ + +static void (*rom_reset)(void); /* Mac bootinfo struct */ @@ -59,30 +72,21 @@ unsigned long mac_orig_videoaddr; /* Mac specific keyboard functions */ -extern int mac_keyb_init(void); -extern int mac_kbdrate(struct kbd_repeat *k); -extern void mac_kbd_leds(unsigned int leds); - -/* Mac specific irq functions */ -extern void mac_init_IRQ (void); -extern void (*mac_handlers[]) (int, void *, struct pt_regs *); -extern int mac_request_irq (unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, - void *dev_id); -extern void mac_free_irq (unsigned int irq, void *dev_id); -extern void mac_enable_irq (unsigned int); -extern void mac_disable_irq (unsigned int); -static void mac_get_model(char *model); -/*static int mac_get_hardware_list(char *buffer);*/ -extern int mac_get_irq_list (char *); +extern int mackbd_init_hw(void); +extern void mackbd_leds(unsigned int leds); /* Mac specific timer functions */ extern unsigned long mac_gettimeoffset (void); static void mac_gettod (int *, int *, int *, int *, int *, int *); static int mac_hwclk (int, struct hwclk_time *); static int mac_set_clock_mmss (unsigned long); +extern void iop_preinit(void); +extern void iop_init(void); +extern void via_init(void); extern void via_init_clock(void (*func)(int, void *, struct pt_regs *)); +extern void via_flush_cache(void); +extern void oss_init(void); +extern void psc_init(void); extern void (*kd_mksound)(unsigned int, unsigned int); extern void mac_mksound(unsigned int, unsigned int); @@ -95,6 +99,18 @@ extern void mac_debug_init(void); extern void mac_debugging_long(int, long); +/* poweroff functions */ +extern void via_poweroff(void); +extern void oss_poweroff(void); +extern void adb_poweroff(void); +extern void adb_hwreset(void); + +/* pram functions */ +extern __u32 via_read_time(void); +extern void via_write_time(__u32); +extern __u32 adb_read_time(void); +extern void adb_write_time(__u32); + #ifdef CONFIG_MAGIC_SYSRQ static char mac_sysrq_xlate[128] = "\000sdfghzxcv\000bqwer" /* 0x00 - 0x0f */ @@ -124,104 +140,195 @@ extern int console_loglevel; -/* - * This function translates the boot timeval into a proper date, to initialize - * the system time. +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) */ +static unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} -static void mac_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) +/* + * This function translates seconds since 1970 into a proper date. + * + * Algorithm cribbed from glibc2.1, __offtime(). + */ +#define SECS_PER_MINUTE (60) +#define SECS_PER_HOUR (SECS_PER_MINUTE * 60) +#define SECS_PER_DAY (SECS_PER_HOUR * 24) + +static void unmktime(unsigned long time, long offset, + int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) { - unsigned long time; - int leap, oldleap, isleap; - int mon_days[14] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 }; - - time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */ - - *minp = time / 60; - *secp = time - (*minp * 60); - time = *minp; /* minutes now */ - - *hourp = time / 60; - *minp = time - (*hourp * 60); - time = *hourp; /* hours now */ - - *dayp = time / 24; - *hourp = time - (*dayp * 24); - time = *dayp; /* days now ... */ - - /* for leap day calculation */ - *yearp = (time / 365) + 1970; /* approx. year */ - - /* leap year calculation - there's an easier way, I bet. And it's broken :-( */ - /* calculate leap days up to previous year */ - oldleap = (*yearp-1)/4 - (*yearp-1)/100 + (*yearp-1)/400; - /* calculate leap days incl. this year */ - leap = *yearp/4 - *yearp/100 + *yearp/400; - /* this year a leap year ?? */ - isleap = (leap != oldleap); - - /* adjust days: days, excluding past leap days since epoch */ - time -= oldleap - (1970/4 - 1970/100 + 1970/400); - - /* precise year, and day in year */ - *yearp = (time / 365); /* #years since epoch */ - *dayp = time - (*yearp * 365) + 1; /* #days this year (0: Jan 1) */ - *yearp += 70; /* add epoch :-) */ - time = *dayp; - - if (isleap) /* add leap day ?? */ - mon_days[2] += 1; - - /* count the months */ - for (*monp = 1; time > mon_days[*monp]; (*monp)++) - time -= mon_days[*monp]; + /* How many days come before each month (0-12). */ + static const unsigned short int __mon_yday[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + long int days, rem, y, wday, yday; + const unsigned short int *ip; + + days = time / SECS_PER_DAY; + rem = time % SECS_PER_DAY; + rem += offset; + while (rem < 0) { + rem += SECS_PER_DAY; + --days; + } + while (rem >= SECS_PER_DAY) { + rem -= SECS_PER_DAY; + ++days; + } + *hourp = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + *minp = rem / SECS_PER_MINUTE; + *secp = rem % SECS_PER_MINUTE; + /* January 1, 1970 was a Thursday. */ + wday = (4 + days) % 7; /* Day in the week. Not currently used */ + if (wday < 0) wday += 7; + y = 1970; + +#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) +#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) +#define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) - *dayp = time; + while (days < 0 || days >= (__isleap (y) ? 366 : 365)) + { + /* Guess a corrected year, assuming 365 days per year. */ + long int yg = y + days / 365 - (days % 365 < 0); + /* Adjust DAYS and Y to match the guessed year. */ + days -= ((yg - y) * 365 + + LEAPS_THRU_END_OF (yg - 1) + - LEAPS_THRU_END_OF (y - 1)); + y = yg; + } + *yearp = y - 1900; + yday = days; /* day in the year. Not currently used. */ + ip = __mon_yday[__isleap(y)]; + for (y = 11; days < (long int) ip[y]; --y) + continue; + days -= ip[y]; + *monp = y; + *dayp = days + 1; /* day in the month */ return; } +/* + * Return the boot time for use in initializing the kernel clock. + * + * I'd like to read the hardware clock here but many machines read + * the PRAM through ADB, and interrupts aren't initialized when this + * is called so ADB obviously won't work. + */ + +static void mac_gettod(int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + /* Yes the GMT bias is backwards. It looks like Penguin is + screwing up the boottime it gives us... This works for me + in Canada/Eastern but it might be wrong everywhere else. */ + unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60, + yearp, monp, dayp, hourp, minp, secp); + /* For some reason this is off by one */ + *monp = *monp + 1; +} + /* - * TBI: read and write hwclock + * Read/write the hardware clock. */ -static int mac_hwclk( int op, struct hwclk_time *t ) +static int mac_hwclk(int op, struct hwclk_time *t) { - return 0; + unsigned long now; + + if (!op) { /* read */ + if (macintosh_config->adb_type == MAC_ADB_II) { + now = via_read_time(); + } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || + (macintosh_config->adb_type == MAC_ADB_CUDA)) { + now = adb_read_time(); + } else if (macintosh_config->adb_type == MAC_ADB_IOP) { + now = via_read_time(); + } else { + now = MAC_TIME_OFFSET; + } + + now -= MAC_TIME_OFFSET; + + t->wday = 0; + unmktime(now, 0, + &t->year, &t->mon, &t->day, + &t->hour, &t->min, &t->sec); + } else { /* write */ + now = mktime(t->year + 1900, t->mon + 1, t->day, + t->hour, t->min, t->sec) + MAC_TIME_OFFSET; + + if (macintosh_config->adb_type == MAC_ADB_II) { + via_write_time(now); + } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || + (macintosh_config->adb_type == MAC_ADB_CUDA)) { + adb_write_time(now); + } else if (macintosh_config->adb_type == MAC_ADB_IOP) { + via_write_time(now); + } + } + return 0; } /* - * TBI: set minutes/seconds in hwclock + * Set minutes/seconds in the hardware clock */ static int mac_set_clock_mmss (unsigned long nowtime) { - short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + struct hwclk_time now; + + mac_hwclk(0, &now); + now.sec = nowtime % 60; + now.min = (nowtime / 60) % 60; + mac_hwclk(1, &now); - return 0; + return 0; } +#if 0 void mac_waitbut (void) { ; } +#endif extern struct consw fb_con; extern struct fb_info *mac_fb_init(long *); -extern void mac_video_setup(char *, int *); - -void (*mac_handlers[8])(int, void *, struct pt_regs *)= -{ - mac_default_handler, - mac_default_handler, - mac_default_handler, - mac_default_handler, - mac_default_handler, - mac_default_handler, - mac_default_handler, - mac_default_handler -}; /* * Parse a Macintosh-specific record in the bootinfo @@ -237,7 +344,7 @@ mac_bi_data.id = *data; break; case BI_MAC_VADDR: - mac_bi_data.videoaddr = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); + mac_bi_data.videoaddr = *data; break; case BI_MAC_VDEPTH: mac_bi_data.videodepth = *data; @@ -249,7 +356,8 @@ mac_bi_data.dimensions = *data; break; case BI_MAC_VLOGICAL: - mac_bi_data.videological = *data; + mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); + mac_orig_videoaddr = *data; break; case BI_MAC_SCCBASE: mac_bi_data.sccbase = *data; @@ -266,6 +374,9 @@ case BI_MAC_CPUID: mac_bi_data.cpuid = *data; break; + case BI_MAC_ROMBASE: + mac_bi_data.rombase = *data; + break; default: unknown = 1; } @@ -280,12 +391,11 @@ static void mac_cache_card_flush(int writeback) { - unsigned long flags; - save_flags(flags); + unsigned long cpu_flags; + save_flags(cpu_flags); cli(); - via_write(via2, vBufB, via_read(via2,vBufB)&~VIA2B_vMode32); - via_write(via2, vBufB, via_read(via2,vBufB)|VIA2B_vMode32); - restore_flags(flags); + via_flush_cache(); + restore_flags(cpu_flags); } void __init config_mac(void) @@ -295,22 +405,15 @@ printk("ERROR: no Mac, but config_mac() called!! \n"); } - mac_debug_init(); - mach_sched_init = mac_sched_init; - mach_keyb_init = mac_keyb_init; - mach_kbdrate = mac_kbdrate; - mach_kbd_leds = mac_kbd_leds; + mach_keyb_init = mackbd_init_hw; + mach_kbd_leds = mackbd_leds; mach_init_IRQ = mac_init_IRQ; mach_request_irq = mac_request_irq; mach_free_irq = mac_free_irq; enable_irq = mac_enable_irq; disable_irq = mac_disable_irq; -#if 1 - mach_default_handler = &mac_handlers; -#endif mach_get_model = mac_get_model; - mach_get_irq_list = mac_get_irq_list; mach_gettimeoffset = mac_gettimeoffset; mach_gettod = mac_gettod; mach_hwclk = mac_hwclk; @@ -319,11 +422,12 @@ mach_mksound = mac_mksound; #endif mach_reset = mac_reset; + mach_halt = mac_poweroff; + mach_power_off = mac_poweroff; conswitchp = &dummy_con; mach_max_dma_address = 0xffffffff; #if 0 mach_debug_init = mac_debug_init; - mach_video_setup = mac_video_setup; #endif kd_mksound = mac_mksound; #ifdef CONFIG_MAGIC_SYSRQ @@ -346,18 +450,15 @@ mac_identify(); mac_report_hardware(); - if( - /* Cache cards */ - macintosh_config->ident == MAC_MODEL_IICI|| - macintosh_config->ident == MAC_MODEL_IISI|| - macintosh_config->ident == MAC_MODEL_IICX|| - /* On board L2 cache */ - macintosh_config->ident == MAC_MODEL_IIFX) - { + /* AFAIK only the IIci takes a cache card. The IIfx has onboard + cache ... someone needs to figure out how to tell if it's on or + not. */ + if (macintosh_config->ident == MAC_MODEL_IICI + || macintosh_config->ident == MAC_MODEL_IIFX) { mach_l2_flush = mac_cache_card_flush; } - /* goes on forever if timers broken */ #ifdef MAC_DEBUG_SOUND + /* goes on forever if timers broken */ mac_mksound(1000,10); #endif @@ -365,7 +466,9 @@ * Check for machine specific fixups. */ +#ifdef OLD_NUBUS_CODE nubus_sweep_video(); +#endif } @@ -386,6 +489,13 @@ static struct mac_model mac_data_table[]= { /* + * The default machine, in case we get an unsupported one + * We'll pretend to be a Macintosh II, that's pretty safe. + */ + + { MAC_MODEL_II, "Unknown", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + + /* * Original MacII hardware * */ @@ -403,10 +513,11 @@ * The IIfx apparently has different ADB hardware, and stuff * so zany nobody knows how to drive it. * Even so, with Marten's help we'll try to deal with it :-) + * CSA: see http://developer.apple.com/technotes/hw/hw_09.html */ { MAC_MODEL_IICI, "IIci", MAC_ADB_II, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_IIFX, "IIfx", MAC_ADB_II, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_IIFX, "IIfx", MAC_ADB_IOP, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_IISI, "IIsi", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_IIVI, "IIvi", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_IIVX, "IIvx", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, @@ -435,70 +546,72 @@ * confuse us. The 840AV has a SCSI location of its own (same as * the 660AV). */ - + { MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, /* The Q700 does have a NS Sonic */ - { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_MACE, MAC_NUBUS}, - /* These might have IOP problems */ - { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, - { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, /* * Performa - more LC type machines */ - { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P600, "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, -#if 0 /* other sources seem to suggest the P630/Q630/LC630 is more like LCIII */ - { MAC_MODEL_P630, "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, -#endif + { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + + { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + /* These have the comm slot, and therefore the possibility of SONIC ethernet */ + { MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_II, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P600, "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + /* * Centris - just guessing again; maybe like Quadra */ - { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, - { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, - { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + /* The C610 may or may not have SONIC. We probe to make sure */ + { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_MACE, MAC_NUBUS}, /* * Power books - seem similar to early Quadras ? (most have 030 though) */ - { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, /* The PB150 has IDE, and IIci style VIA */ - { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB190, "PowerBook 190", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_NONE, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB190, "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + /* These have onboard SONIC */ + { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, /* * Power book Duos - similar to Power books, I hope */ - { MAC_MODEL_PB210, "PowerBook Duo 210", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB230, "PowerBook Duo 230", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB250, "PowerBook Duo 250", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB280, "PowerBook Duo 280", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB280C, "PowerBook Duo 280c", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + /* All of these might have onboard SONIC in the Dock but I'm not quite sure */ + { MAC_MODEL_PB210, "PowerBook Duo 210", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB230, "PowerBook Duo 230", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB250, "PowerBook Duo 250", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB280, "PowerBook Duo 280", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB280C, "PowerBook Duo 280c", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, /* * Other stuff ?? @@ -508,7 +621,7 @@ void mac_identify(void) { - struct mac_model *m=&mac_data_table[0]; + struct mac_model *m; /* Penguin data useful? */ int model = mac_bi_data.id; @@ -519,32 +632,23 @@ printk ("No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n"); } - printk ("Detected Macintosh model: %d \n", model); - - while(m->ident != -1) - { - if(m->ident == model) + macintosh_config = mac_data_table; + for (m = macintosh_config ; m->ident != -1 ; m++) { + if (m->ident == model) { + macintosh_config = m; break; - m++; - } - if(m->ident==-1) - { - printk("\nUnknown macintosh model %d, probably unsupported.\n", - model); - model = MAC_MODEL_Q800; - printk("Defaulting to: Quadra800, model id %d\n", model); - printk("Please report this case to linux-mac68k@wave.lm.com\n"); - m=&mac_data_table[0]; - while(m->ident != -1) - { - if(m->ident == model) - break; - m++; } - if(m->ident==-1) - panic("mac model config data corrupt!\n"); } + /* We need to pre-init the IOPs, if any. Otherwise */ + /* the serial console won't work if the user had */ + /* the serial ports set to "Faster" mode in MacOS. */ + + iop_preinit(); + mac_debug_init(); + + printk ("Detected Macintosh model: %d \n", model); + /* * Report booter data: */ @@ -566,12 +670,6 @@ #endif /* - * Save the pointer - */ - - macintosh_config=m; - - /* * TODO: set the various fields in macintosh_config->hw_present here! */ switch (macintosh_config->scsi_type) { @@ -592,7 +690,10 @@ break; } - via_configure_base(); + iop_init(); + via_init(); + oss_init(); + psc_init(); } void mac_report_hardware(void) @@ -604,8 +705,133 @@ { strcpy(str,"Macintosh "); strcat(str, macintosh_config->name); - if(mach_l2_flush && !(via_read(via2, vBufB)&VIA2B_vCDis)) - strcat(str, "(+L2 cache)"); +} + +/* + * The power switch - yes it's software! + */ + +void mac_poweroff(void) +{ + /* + * MAC_ADB_IISI may need to be moved up here if it doesn't actually + * work using the ADB packet method. --David Kilzer + */ + + if (oss_present) { + oss_poweroff(); + } else if (macintosh_config->adb_type == MAC_ADB_II) { + via_poweroff(); + } else { + adb_poweroff(); + } +} + +/* + * Not all Macs support software power down; for the rest, just + * try the ROM reset vector ... + */ +void mac_reset(void) +{ + /* + * MAC_ADB_IISI may need to be moved up here if it doesn't actually + * work using the ADB packet method. --David Kilzer + */ + + if (macintosh_config->adb_type == MAC_ADB_II) { + unsigned long cpu_flags; + + /* need ROMBASE in booter */ + /* indeed, plus need to MAP THE ROM !! */ + + if (mac_bi_data.rombase == 0) + mac_bi_data.rombase = 0x40800000; + + /* works on some */ + rom_reset = (void *) (mac_bi_data.rombase + 0xa); + + if (macintosh_config->ident == MAC_MODEL_SE30) { + /* + * MSch: Machines known to crash on ROM reset ... + */ + printk("System halted.\n"); + while(1); + } else { + save_flags(cpu_flags); + cli(); + + rom_reset(); + + restore_flags(cpu_flags); + } + + /* We never make it this far... it usually panics above. */ + printk ("Restart failed. Please restart manually.\n"); + + /* XXX - delay do we need to spin here ? */ + while(1); /* Just in case .. */ + } else if (macintosh_config->adb_type == MAC_ADB_IISI + || macintosh_config->adb_type == MAC_ADB_CUDA) { + adb_hwreset(); + } else if (CPU_IS_030) { + + /* 030-specific reset routine. The idea is general, but the + * specific registers to reset are '030-specific. Until I + * have a non-030 machine, I can't test anything else. + * -- C. Scott Ananian + */ + + unsigned long rombase = 0x40000000; + + /* make a 1-to-1 mapping, using the transparent tran. reg. */ + unsigned long virt = (unsigned long) mac_reset; + unsigned long phys = virt_to_phys(mac_reset); + unsigned long offset = phys-virt; + cli(); /* lets not screw this up, ok? */ + __asm__ __volatile__(".chip 68030\n\t" + "pmove %0,%/tt0\n\t" + ".chip 68k" + : : "m" ((phys&0xFF000000)|0x8777)); + /* Now jump to physical address so we can disable MMU */ + __asm__ __volatile__( + ".chip 68030\n\t" + "lea %/pc@(1f),%/a0\n\t" + "addl %0,%/a0\n\t"/* fixup target address and stack ptr */ + "addl %0,%/sp\n\t" + "pflusha\n\t" + "jmp %/a0@\n\t" /* jump into physical memory */ + "0:.long 0\n\t" /* a constant zero. */ + /* OK. Now reset everything and jump to reset vector. */ + "1:\n\t" + "lea %/pc@(0b),%/a0\n\t" + "pmove %/a0@, %/tc\n\t" /* disable mmu */ + "pmove %/a0@, %/tt0\n\t" /* disable tt0 */ + "pmove %/a0@, %/tt1\n\t" /* disable tt1 */ + "movel #0, %/a0\n\t" + "movec %/a0, %/vbr\n\t" /* clear vector base register */ + "movec %/a0, %/cacr\n\t" /* disable caches */ + "movel #0x0808,%/a0\n\t" + "movec %/a0, %/cacr\n\t" /* flush i&d caches */ + "movew #0x2700,%/sr\n\t" /* set up status register */ + "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */ + "movec %/a0, %/isp\n\t" + "movel %1@(0x4),%/a0\n\t" /* load reset vector */ + "reset\n\t" /* reset external devices */ + "jmp %/a0@\n\t" /* jump to the reset vector */ + ".chip 68k" + : : "r" (offset), "a" (rombase) : "a0"); + + /* should never get here */ + sti(); /* sure, why not */ + printk ("030 Restart failed. Please restart manually.\n"); + while(1); + } else { + /* We never make it here... The above shoule handle all cases. */ + printk ("Restart failed. Please restart manually.\n"); + + /* XXX - delay do we need to spin here ? */ + while(1); /* Just in case .. */ + } } /* diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c --- v2.3.16/linux/arch/m68k/mac/debug.c Tue Aug 31 17:29:12 1999 +++ linux/arch/m68k/mac/debug.c Sat Sep 4 13:06:41 1999 @@ -243,7 +243,7 @@ } } -#ifdef CONFIG_SERIAL_CONSOLE +#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_SERIAL) int mac_sccb_console_wait_key(struct console *co) { int i; @@ -384,6 +384,16 @@ mac_SCC_init_done = 1; } #endif /* DEBUG_SERIAL */ + +void mac_init_scca_port( int cflag ) +{ + mac_init_scc_port(cflag, 0); +} + +void mac_init_sccb_port( int cflag ) +{ + mac_init_scc_port(cflag, 1); +} void __init mac_debug_init(void) { diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/iop.c linux/arch/m68k/mac/iop.c --- v2.3.16/linux/arch/m68k/mac/iop.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/iop.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,725 @@ +/* + * I/O Processor (IOP) management + * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice and this list of conditions. + * 2. Redistributions in binary form must reproduce the above copyright + * notice and this list of conditions in the documentation and/or other + * materials provided with the distribution. + */ + +/* + * The IOP chips are used in the IIfx and some Quadras (900, 950) to manage + * serial and ADB. They are actually a 6502 processor and some glue logic. + * + * 990429 (jmt) - Initial implementation, just enough to knock the SCC IOP + * into compatible mode so nobody has to fiddle with the + * Serial Switch control panel anymore. + * 990603 (jmt) - Added code to grab the correct ISM IOP interrupt for OSS + * and non-OSS machines (at least I hope it's correct on a + * non-OSS machine -- someone with a Q900 or Q950 needs to + * check this.) + * 990605 (jmt) - Rearranged things a bit wrt IOP detection; iop_present is + * gone, IOP base addresses are now in an array and the + * globally-visible functions take an IOP number instead of an + * an actual base address. + * 990610 (jmt) - Finished the message passing framework and it seems to work. + * Sending _definately_ works; my adb-bus.c mods can send + * messages and receive the MSG_COMPLETED status back from the + * IOP. The trick now is figuring out the message formats. + * 990611 (jmt) - More cleanups. Fixed problem where unclaimed messages on a + * receive channel were never properly acknowledged. Bracketed + * the remaining debug printk's with #ifdef's and disabled + * debugging. I can now type on the console. + * 990612 (jmt) - Copyright notice added. Reworked the way replies are handled. + * It turns out that replies are placed back in the send buffer + * for that channel; messages on the receive channels are always + * unsolicited messages from the IOP (and our replies to them + * should go back in the receive channel.) Also added tracking + * of device names to the listener functions ala the interrupt + * handlers. + * 990729 (jmt) - Added passing of pt_regs structure to IOP handlers. This is + * used by the new unified ADB driver. + * + * TODO: + * + * o Something should be periodically checking iop_alive() to make sure the + * IOP hasn't died. + * o Some of the IOP manager routines need better error checking and + * return codes. Nothing major, just prettying up. + */ + +/* + * ----------------------- + * IOP Message Passing 101 + * ----------------------- + * + * The host talks to the IOPs using a rather simple message-passing scheme via + * a shared memory area in the IOP RAM. Each IOP has seven "channels"; each + * channel is conneced to a specific software driver on the IOP. For example + * on the SCC IOP there is one channel for each serial port. Each channel has + * an incoming and and outgoing message queue with a depth of one. + * + * A message is 32 bytes plus a state byte for the channel (MSG_IDLE, MSG_NEW, + * MSG_RCVD, MSG_COMPLETE). To send a message you copy the message into the + * buffer, set the state to MSG_NEW and signal the IOP by setting the IRQ flag + * in the IOP control to 1. The IOP will move the state to MSG_RCVD when it + * receives the message and then to MSG_COMPLETE when the message processing + * has completed. It is the host's responsibility at that point to read the + * reply back out of the send channel buffer and reset the channel state back + * to MSG_IDLE. + * + * To receive message from the IOP the same procedure is used except the roles + * are reversed. That is, the IOP puts message in the channel with a state of + * MSG_NEW, and the host receives the message and move its state to MSG_RCVD + * and then to MSG_COMPLETE when processing is completed and the reply (if any) + * has been placed back in the receive channel. The IOP will then reset the + * channel state to MSG_IDLE. + * + * Two sets of host interrupts are provided, INT0 and INT1. Both appear on one + * interrupt level; they are distinguished by a pair of bits in the IOP status + * register. The IOP will raise INT0 when one or more messages in the send + * channels have gone to the MSG_COMPLETE state and it will raise INT1 when one + * or more messages on the receive channels have gone to the MSG_NEW state. + * + * Since each channel handles only one message we have to implement a small + * interrupt-driven queue on our end. Messages to e sent are placed on the + * queue for sending and contain a pointer to an optional callback function. + * The handler for a message is called when the message state goes to + * MSG_COMPLETE. + * + * For receiving message we maintain a list of handler functions to call when + * a message is received on that IOP/channel combination. The handlers are + * called much like an interrupt handler and are passed a copy of the message + * from the IOP. The message state will be in MSG_RCVD while the handler runs; + * it is the handler's responsibility to call iop_complete_message() when + * finished; this function moves the message state to MSG_COMPLETE and signals + * the IOP. This two-step process is provided to allow the handler to defer + * message processing to a bottom-half handler if the processing will take + * a signifigant amount of time (handlers are called at interrupt time so they + * should execute quickly.) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/*#define DEBUG_IOP*/ + +/* Set to nonezero if the IOPs are present. Set by iop_init() */ + +int iop_scc_present,iop_ism_present; + +#ifdef CONFIG_PROC_FS + +/* + * sneaky reuse of the PROC_MAC_VIA inode. It's not needed by via.c + * anymore so we'll use it to debut the IOPs. + */ + +int iop_get_proc_info(char *, char **, off_t, int, int); + +static struct proc_dir_entry proc_mac_iop = { + PROC_MAC_VIA, 7, "mac_iop", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, + &iop_get_proc_info +}; + +#endif /* CONFIG_PROC_FS */ + +/* structure for tracking channel listeners */ + +struct listener { + const char *devname; + void (*handler)(struct iop_msg *, struct pt_regs *); +}; + +/* + * IOP structures for the two IOPs + * + * The SCC IOP controls both serial ports (A and B) as its two functions. + * The ISM IOP controls the SWIM (floppy drive) and ADB. + */ + +static volatile struct mac_iop *iop_base[NUM_IOPS]; + +/* + * IOP message queues + */ + +static struct iop_msg iop_msg_pool[NUM_IOP_MSGS]; +static struct iop_msg *iop_send_queue[NUM_IOPS][NUM_IOP_CHAN]; +static struct listener iop_listeners[NUM_IOPS][NUM_IOP_CHAN]; + +void iop_ism_irq(int, void *, struct pt_regs *); + +extern void oss_irq_enable(int); + +/* + * Private access functions + */ + +static __inline__ void iop_loadaddr(volatile struct mac_iop *iop, __u16 addr) +{ + iop->ram_addr_lo = addr; + iop->ram_addr_hi = addr >> 8; +} + +static __inline__ __u8 iop_readb(volatile struct mac_iop *iop, __u16 addr) +{ + iop->ram_addr_lo = addr; + iop->ram_addr_hi = addr >> 8; + return iop->ram_data; +} + +static __inline__ void iop_writeb(volatile struct mac_iop *iop, __u16 addr, __u8 data) +{ + iop->ram_addr_lo = addr; + iop->ram_addr_hi = addr >> 8; + iop->ram_data = data; +} + +static __inline__ void iop_stop(volatile struct mac_iop *iop) +{ + iop->status_ctrl &= ~IOP_RUN; +} + +static __inline__ void iop_start(volatile struct mac_iop *iop) +{ + iop->status_ctrl = IOP_RUN | IOP_AUTOINC; +} + +static __inline__ void iop_bypass(volatile struct mac_iop *iop) +{ + iop->status_ctrl |= IOP_BYPASS; +} + +static __inline__ void iop_interrupt(volatile struct mac_iop *iop) +{ + iop->status_ctrl |= IOP_IRQ; +} + +static int iop_alive(volatile struct mac_iop *iop) +{ + int retval; + + retval = (iop_readb(iop, IOP_ADDR_ALIVE) == 0xFF); + iop_writeb(iop, IOP_ADDR_ALIVE, 0); + return retval; +} + +static struct iop_msg *iop_alloc_msg(void) +{ + int i; + ulong cpu_flags; + + save_flags(cpu_flags); + cli(); + + for (i = 0 ; i < NUM_IOP_MSGS ; i++) { + if (iop_msg_pool[i].status == IOP_MSGSTATUS_UNUSED) { + iop_msg_pool[i].status = IOP_MSGSTATUS_WAITING; + restore_flags(cpu_flags); + return &iop_msg_pool[i]; + } + } + + restore_flags(cpu_flags); + return NULL; +} + +static void iop_free_msg(struct iop_msg *msg) +{ + msg->status = IOP_MSGSTATUS_UNUSED; +} + +/* + * This is called by the startup code before anything else. Its purpose + * is to find and initalize the IOPs early in the boot sequence, so that + * the serial IOP can be placed into bypass mode _before_ we try to + * initialize the serial console. + */ + +void __init iop_preinit(void) +{ + if (macintosh_config->scc_type == MAC_SCC_IOP) { + if (macintosh_config->ident == MAC_MODEL_IIFX) { + iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_IIFX; + } else { + iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_QUADRA; + } + iop_base[IOP_NUM_SCC]->status_ctrl = 0x87; + iop_scc_present = 1; + } else { + iop_base[IOP_NUM_SCC] = NULL; + iop_scc_present = 0; + } + if (macintosh_config->adb_type == MAC_ADB_IOP) { + if (macintosh_config->ident == MAC_MODEL_IIFX) { + iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_IIFX; + } else { + iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_QUADRA; + } + iop_base[IOP_NUM_SCC]->status_ctrl = 0; + iop_ism_present = 1; + } else { + iop_base[IOP_NUM_ISM] = NULL; + iop_ism_present = 0; + } +} + +/* + * Initialize the IOPs, if present. + */ + +void __init iop_init(void) +{ + int i; + + if (iop_scc_present) { + printk("IOP: detected SCC IOP at %p\n", iop_base[IOP_NUM_SCC]); + } + if (iop_ism_present) { + printk("IOP: detected ISM IOP at %p\n", iop_base[IOP_NUM_ISM]); + iop_start(iop_base[IOP_NUM_ISM]); + iop_alive(iop_base[IOP_NUM_ISM]); /* clears the alive flag */ + } + + /* Make the whole pool available and empty the queues */ + + for (i = 0 ; i < NUM_IOP_MSGS ; i++) { + iop_msg_pool[i].status = IOP_MSGSTATUS_UNUSED; + } + + for (i = 0 ; i < NUM_IOP_CHAN ; i++) { + iop_send_queue[IOP_NUM_SCC][i] = 0; + iop_send_queue[IOP_NUM_ISM][i] = 0; + iop_listeners[IOP_NUM_SCC][i].devname = NULL; + iop_listeners[IOP_NUM_SCC][i].handler = NULL; + iop_listeners[IOP_NUM_ISM][i].devname = NULL; + iop_listeners[IOP_NUM_ISM][i].handler = NULL; + } + +#ifdef CONFIG_PROC_FS + proc_register(&proc_root, &proc_mac_iop); +#endif +} + +/* + * Register the interrupt handler for the IOPs. + * TODO: might be wrong for non-OSS machines. Anyone? + */ + +void __init iop_register_interrupts(void) +{ + if (iop_ism_present) { + if (oss_present) { + request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq, + IRQ_FLG_LOCK, "ISM IOP", + (void *) IOP_NUM_ISM); + oss_irq_enable(IRQ_MAC_ADB); + } else { + request_irq(IRQ_VIA2_0, iop_ism_irq, + IRQ_FLG_LOCK|IRQ_FLG_FAST, "ISM IOP", + (void *) IOP_NUM_ISM); + } + if (!iop_alive(iop_base[IOP_NUM_ISM])) { + printk("IOP: oh my god, they killed the ISM IOP!\n"); + } else { + printk("IOP: the ISM IOP seems to be alive.\n"); + } + } +} + +/* + * Register or unregister a listener for a specific IOP and channel + * + * If the handler pointer is NULL the current listener (if any) is + * unregistered. Otherwise the new listener is registered provided + * there is no existing listener registered. + */ + +int iop_listen(uint iop_num, uint chan, + void (*handler)(struct iop_msg *, struct pt_regs *), + const char *devname) +{ + if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL; + if (chan >= NUM_IOP_CHAN) return -EINVAL; + if (iop_listeners[iop_num][chan].handler && handler) return -EINVAL; + iop_listeners[iop_num][chan].devname = devname; + iop_listeners[iop_num][chan].handler = handler; + return 0; +} + +/* + * Complete reception of a message, which just means copying the reply + * into the buffer, setting the channel state to MSG_COMPLETE and + * notifying the IOP. + */ + +void iop_complete_message(struct iop_msg *msg) +{ + int iop_num = msg->iop_num; + int chan = msg->channel; + int i,offset; + +#ifdef DEBUG_IOP + printk("iop_complete(%p): iop %d chan %d\n", msg, msg->iop_num, msg->channel); +#endif + + offset = IOP_ADDR_RECV_MSG + (msg->channel * IOP_MSG_LEN); + + for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { + iop_writeb(iop_base[iop_num], offset, msg->reply[i]); + } + + iop_writeb(iop_base[iop_num], + IOP_ADDR_RECV_STATE + chan, IOP_MSG_COMPLETE); + iop_interrupt(iop_base[msg->iop_num]); + + iop_free_msg(msg); +} + +/* + * Actually put a message into a send channel buffer + */ + +static void iop_do_send(struct iop_msg *msg) +{ + volatile struct mac_iop *iop = iop_base[msg->iop_num]; + int i,offset; + + offset = IOP_ADDR_SEND_MSG + (msg->channel * IOP_MSG_LEN); + + for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { + iop_writeb(iop, offset, msg->message[i]); + } + + iop_writeb(iop, IOP_ADDR_SEND_STATE + msg->channel, IOP_MSG_NEW); + + iop_interrupt(iop); +} + +/* + * Handle sending a message on a channel that + * has gone into the IOP_MSG_COMPLETE state. + */ + +static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs) +{ + volatile struct mac_iop *iop = iop_base[iop_num]; + struct iop_msg *msg,*msg2; + int i,offset; + +#ifdef DEBUG_IOP + printk("iop_handle_send: iop %d channel %d\n", iop_num, chan); +#endif + + iop_writeb(iop, IOP_ADDR_SEND_STATE + chan, IOP_MSG_IDLE); + + if (!(msg = iop_send_queue[iop_num][chan])) return; + + msg->status = IOP_MSGSTATUS_COMPLETE; + offset = IOP_ADDR_SEND_MSG + (chan * IOP_MSG_LEN); + for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { + msg->reply[i] = iop_readb(iop, offset); + } + if (msg->handler) (*msg->handler)(msg, regs); + msg2 = msg; + msg = msg->next; + iop_free_msg(msg2); + + iop_send_queue[iop_num][chan] = msg; + if (msg) iop_do_send(msg); +} + +/* + * Handle reception of a message on a channel that has + * gone into the IOP_MSG_NEW state. + */ + +static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs) +{ + volatile struct mac_iop *iop = iop_base[iop_num]; + int i,offset; + struct iop_msg *msg; + +#ifdef DEBUG_IOP + printk("iop_handle_recv: iop %d channel %d\n", iop_num, chan); +#endif + + msg = iop_alloc_msg(); + msg->iop_num = iop_num; + msg->channel = chan; + msg->status = IOP_MSGSTATUS_UNSOL; + msg->handler = iop_listeners[iop_num][chan].handler; + + offset = IOP_ADDR_RECV_MSG + (chan * IOP_MSG_LEN); + + for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { + msg->message[i] = iop_readb(iop, offset); + } + + iop_writeb(iop, IOP_ADDR_RECV_STATE + chan, IOP_MSG_RCVD); + + /* If there is a listener, call it now. Otherwise complete */ + /* the message ourselves to avoid possible stalls. */ + + if (msg->handler) { + (*msg->handler)(msg, regs); + } else { +#ifdef DEBUG_IOP + printk("iop_handle_recv: unclaimed message on iop %d channel %d\n", iop_num, chan); + printk("iop_handle_recv:"); + for (i = 0 ; i < IOP_MSG_LEN ; i++) { + printk(" %02X", (uint) msg->message[i]); + } + printk("\n"); +#endif + iop_complete_message(msg); + } +} + +/* + * Send a message + * + * The message is placed at the end of the send queue. Afterwards if the + * channel is idle we force an immediate send of the next message in the + * queue. + */ + +int iop_send_message(uint iop_num, uint chan, void *privdata, + uint msg_len, __u8 *msg_data, + void (*handler)(struct iop_msg *, struct pt_regs *)) +{ + struct iop_msg *msg, *q; + + if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL; + if (chan >= NUM_IOP_CHAN) return -EINVAL; + if (msg_len > IOP_MSG_LEN) return -EINVAL; + + msg = iop_alloc_msg(); + if (!msg) return -ENOMEM; + + msg->next = NULL; + msg->status = IOP_MSGSTATUS_WAITING; + msg->iop_num = iop_num; + msg->channel = chan; + msg->caller_priv = privdata; + memcpy(msg->message, msg_data, msg_len); + msg->handler = handler; + + if (!(q = iop_send_queue[iop_num][chan])) { + iop_send_queue[iop_num][chan] = msg; + } else { + while (q->next) q = q->next; + q->next = msg; + } + + if (iop_readb(iop_base[iop_num], + IOP_ADDR_SEND_STATE + chan) == IOP_MSG_IDLE) { + iop_do_send(msg); + } + + return 0; +} + +/* + * Upload code to the shared RAM of an IOP. + */ + +void iop_upload_code(uint iop_num, __u8 *code_start, + uint code_len, __u16 shared_ram_start) +{ + if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return; + + iop_loadaddr(iop_base[iop_num], shared_ram_start); + + while (code_len--) { + iop_base[iop_num]->ram_data = *code_start++; + } +} + +/* + * Download code from the shared RAM of an IOP. + */ + +void iop_download_code(uint iop_num, __u8 *code_start, + uint code_len, __u16 shared_ram_start) +{ + if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return; + + iop_loadaddr(iop_base[iop_num], shared_ram_start); + + while (code_len--) { + *code_start++ = iop_base[iop_num]->ram_data; + } +} + +/* + * Compare the code in the shared RAM of an IOP with a copy in system memory + * and return 0 on match or the first nonmatching system memory address on + * failure. + */ + +__u8 *iop_compare_code(uint iop_num, __u8 *code_start, + uint code_len, __u16 shared_ram_start) +{ + if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return code_start; + + iop_loadaddr(iop_base[iop_num], shared_ram_start); + + while (code_len--) { + if (*code_start != iop_base[iop_num]->ram_data) { + return code_start; + } + code_start++; + } + return (__u8 *) 0; +} + +/* + * Handle an ISM IOP interrupt + */ + +void iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + uint iop_num = (uint) dev_id; + volatile struct mac_iop *iop = iop_base[iop_num]; + int i,state; + +#ifdef DEBUG_IOP + printk("iop_ism_irq: status = %02X\n", (uint) iop->status_ctrl); +#endif + + /* INT0 indicates a state change on an outgoing message channel */ + + if (iop->status_ctrl & IOP_INT0) { + iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC; +#ifdef DEBUG_IOP + printk("iop_ism_irq: new status = %02X, send states", + (uint) iop->status_ctrl); +#endif + for (i = 0 ; i < NUM_IOP_CHAN ; i++) { + state = iop_readb(iop, IOP_ADDR_SEND_STATE + i); +#ifdef DEBUG_IOP + printk(" %02X", state); +#endif + if (state == IOP_MSG_COMPLETE) { + iop_handle_send(iop_num, i, regs); + } + } +#ifdef DEBUG_IOP + printk("\n"); +#endif + } + + if (iop->status_ctrl & IOP_INT1) { /* INT1 for incoming msgs */ + iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC; +#ifdef DEBUG_IOP + printk("iop_ism_irq: new status = %02X, recv states", + (uint) iop->status_ctrl); +#endif + for (i = 0 ; i < NUM_IOP_CHAN ; i++) { + state = iop_readb(iop, IOP_ADDR_RECV_STATE + i); +#ifdef DEBUG_IOP + printk(" %02X", state); +#endif + if (state == IOP_MSG_NEW) { + iop_handle_recv(iop_num, i, regs); + } + } +#ifdef DEBUG_IOP + printk("\n"); +#endif + } + +} + +#ifdef CONFIG_PROC_FS + +char *iop_chan_state(int state) +{ + switch(state) { + case IOP_MSG_IDLE : return "idle "; + case IOP_MSG_NEW : return "new "; + case IOP_MSG_RCVD : return "received "; + case IOP_MSG_COMPLETE : return "completed "; + default : return "unknown "; + } +} + +int iop_dump_one_iop(char *buf, int iop_num, char *iop_name) +{ + int i,len = 0; + volatile struct mac_iop *iop = iop_base[iop_num]; + + len += sprintf(buf+len, "%s IOP channel states:\n\n", iop_name); + len += sprintf(buf+len, "## send_state recv_state device\n"); + len += sprintf(buf+len, "------------------------------------------------\n"); + for (i = 0 ; i < NUM_IOP_CHAN ; i++) { + len += sprintf(buf+len, "%2d %10s %10s %s\n", i, + iop_chan_state(iop_readb(iop, IOP_ADDR_SEND_STATE+i)), + iop_chan_state(iop_readb(iop, IOP_ADDR_RECV_STATE+i)), + iop_listeners[iop_num][i].handler? + iop_listeners[iop_num][i].devname : ""); + + } + len += sprintf(buf+len, "\n"); + return len; +} + +int iop_get_proc_info(char *buf, char **start, off_t pos, int count, int wr) +{ + int len, cnt; + + cnt = 0; + len = sprintf(buf, "IOPs detected:\n\n"); + + if (iop_scc_present) { + len += sprintf(buf+len, "SCC IOP (%p): status %02X\n", + iop_base[IOP_NUM_SCC], + (uint) iop_base[IOP_NUM_SCC]->status_ctrl); + } + if (iop_ism_present) { + len += sprintf(buf+len, "ISM IOP (%p): status %02X\n\n", + iop_base[IOP_NUM_ISM], + (uint) iop_base[IOP_NUM_ISM]->status_ctrl); + } + + if (iop_scc_present) { + len += iop_dump_one_iop(buf+len, IOP_NUM_SCC, "SCC"); + + } + + if (iop_ism_present) { + len += iop_dump_one_iop(buf+len, IOP_NUM_ISM, "ISM"); + + } + + if (len >= pos) { + if (!*start) { + *start = buf + pos; + cnt = len - pos; + } else { + cnt += len; + } + } + return (count > cnt) ? cnt : count; +} +#endif /* CONFIG_PROC_FS */ diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/mac_ksyms.c linux/arch/m68k/mac/mac_ksyms.c --- v2.3.16/linux/arch/m68k/mac/mac_ksyms.c Wed Sep 2 09:39:18 1998 +++ linux/arch/m68k/mac/mac_ksyms.c Sat Sep 4 13:06:41 1999 @@ -1,7 +1,8 @@ #include #include #include -/* Hook for mouse driver */ -extern void (*adb_mouse_interrupt_hook) (char *); -EXPORT_SYMBOL(adb_mouse_interrupt_hook); +/* Says whether we're using A/UX interrupts or not */ +extern int via_alt_mapping; + +EXPORT_SYMBOL(via_alt_mapping); diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/mac_penguin.S linux/arch/m68k/mac/mac_penguin.S --- v2.3.16/linux/arch/m68k/mac/mac_penguin.S Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/mac_penguin.S Sat Sep 4 13:06:41 1999 @@ -0,0 +1,75 @@ +.byte \ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0xFF,0xFF,0x0F,0xF0,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0x00,0xFF,0xFF,0x0F,0xFF,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0x0F,0xFF,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x0F,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x0F,0xF0,0x00,0x00,0xFF,0xF0,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x0F,0xF0,0xFF,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0xF0,0x00,0x00,\ +0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0xF0,0x00,0x00,\ +0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,\ +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,\ +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,\ +0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,\ +0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00 diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/macboing.c linux/arch/m68k/mac/macboing.c --- v2.3.16/linux/arch/m68k/mac/macboing.c Tue Jan 5 11:20:43 1999 +++ linux/arch/m68k/mac/macboing.c Sat Sep 4 13:06:41 1999 @@ -91,14 +91,8 @@ mac_special_bell = mac_quadra_start_bell; mac_asc_samplespersec = 22150; break; - case MAC_MODEL_Q650: - case MAC_MODEL_Q700: - case MAC_MODEL_Q800: - case MAC_MODEL_Q900: - case MAC_MODEL_Q950: - /* - * Currently not implemented! - */ + case MAC_MODEL_C660: + case MAC_MODEL_Q840: /* * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O. * It appears to be similar to the "AWACS" custom ASIC in the Power Mac @@ -126,6 +120,22 @@ */ mac_special_bell = mac_av_start_bell; break; + case MAC_MODEL_Q650: + case MAC_MODEL_Q700: + case MAC_MODEL_Q800: + case MAC_MODEL_Q900: + case MAC_MODEL_Q950: + /* + * Currently not implemented! + */ + mac_special_bell = NULL; + break; + default: + /* + * Every switch needs a default + */ + mac_special_bell = NULL; + break; } /* @@ -154,6 +164,12 @@ __u32 cfreq = ( freq << 5 ) / 468; __u32 flags; int i; + + if ( mac_special_bell == NULL ) + { + /* Do nothing */ + return; + } if ( !mac_asc_inited ) mac_init_asc(); diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c --- v2.3.16/linux/arch/m68k/mac/macints.c Tue Jan 5 11:20:43 1999 +++ linux/arch/m68k/mac/macints.c Sat Sep 4 13:06:41 1999 @@ -7,8 +7,8 @@ * interrupts with exception vectors 0x19-0x1f). The following interrupt levels * are used: * 1 - VIA1 - * - slot 0: one second interrupt - * - slot 1: VBlank + * - slot 0: one second interrupt (CA2) + * - slot 1: VBlank (CA1) * - slot 2: ADB data ready (SR full) * - slot 3: ADB data (CB2) * - slot 4: ADB clock (CB1) @@ -16,57 +16,103 @@ * - slot 6: timer 1 * - slot 7: status of IRQ; signals 'any enabled int.' * - * 2 - VIA2, RBV or OSS - * - slot 0: SCSI DRQ - * - slot 1: NUBUS IRQ - * - slot 3: SCSI IRQ - * - * 4 - SCC - * - subdivided into Channel B and Channel A interrupts - * - * 6 - Off switch (??) - * - * 7 - Debug output - * - * AV Macs only, handled by PSC: - * - * 3 - MACE ethernet IRQ (DMA complete on level 4) - * - * 5 - DSP ?? - * - * Using the autovector irq numbers for Linux/m68k hardware interrupts without - * the IRQ_MACHSPEC bit set would interfere with the general m68k interrupt - * handling in kernel versions 2.0.x, so the following strategy is used: - * - * - mac_init_IRQ installs the low-level entry points for the via1 and via2 - * exception vectors and the corresponding handlers (C functions); these - * entry points just add the machspec bit and call the handlers proper. - * (in principle, the C functions can be installed as the exception vectors - * directly, as they are hardcoded anyway; that's the current method). - * - * - via[12]_irq determine what interrupt sources have triggered the interrupt, - * and call the corresponding device interrupt handlers. - * (currently, via1_irq and via2_irq just call via_irq, passing the via base - * address. RBV interrupts are handled by (you guessed it) rbv_irq). - * Some interrupt functions want to have the interrupt number passed, so - * via_irq and rbv_irq need to generate the 'fake' numbers from scratch. - * - * - for the request/free/enable/disable business, interrupt sources are - * numbered internally (suggestion: keep irq 0-7 unused :-). One bit in the - * irq number specifies the via# to use, i.e. via1 interrupts are 8-16, - * via2 interrupts 17-32, rbv interrupts ... - * The device interrupt table and the irq_enable bitmap is maintained by - * the machspec interrupt code; all device drivers should only use these - * functions ! - * - * - For future porting to version 2.1 (and removing of the machspec bit) it - * should be sufficient to use the same numbers (everything > 7 is assumed - * to be machspec, according to Jes!). + * 2 - VIA2 or RBV + * - slot 0: SCSI DRQ (CA2) + * - slot 1: NUBUS IRQ (CA1) need to read port A to find which + * - slot 2: /EXP IRQ (only on IIci) + * - slot 3: SCSI IRQ (CB2) + * - slot 4: ASC IRQ (CB1) + * - slot 5: timer 2 (not on IIci) + * - slot 6: timer 1 (not on IIci) + * - slot 7: status of IRQ; signals 'any enabled int.' + * + * 2 - OSS (IIfx only?) + * - slot 0: SCSI interrupt + * - slot 1: Sound interrupt + * + * Levels 3-6 vary by machine type. For VIA or RBV Macintohes: + * + * 3 - unused (?) + * + * 4 - SCC (slot number determined by reading RR3 on the SSC itself) + * - slot 0: SCC channel A + * - slot 1: SCC channel B + * + * 5 - unused (?) + * [serial errors or special conditions seem to raise level 6 + * interrupts on some models (LC4xx?)] + * + * 6 - off switch (?) + * + * For OSS Macintoshes (IIfx only at this point): + * + * 3 - Nubus interrupt + * - slot 0: Slot $9 + * - slot 1: Slot $A + * - slot 2: Slot $B + * - slot 3: Slot $C + * - slot 4: Slot $D + * - slot 5: Slot $E + * + * 4 - SCC IOP + * - slot 0: SCC channel A + * - slot 1: SCC channel B + * + * 5 - ISM IOP (ADB?) + * + * 6 - unused + * + * For PSC Macintoshes (660AV, 840AV): + * + * 3 - PSC level 3 + * - slot 0: MACE + * + * 4 - PSC level 4 + * - slot 1: SCC channel A interrupt + * - slot 2: SCC channel B interrupt + * - slot 3: MACE DMA + * + * 5 - PSC level 5 + * + * 6 - PSC level 6 + * + * Finally we have good 'ole level 7, the non-maskable interrupt: + * + * 7 - NMI (programmer's switch on the back of some Macs) + * Also RAM parity error on models which support it (IIc, IIfx?) + * + * The current interrupt logic looks something like this: + * + * - We install dispatchers for the autovector interrupts (1-7). These + * dispatchers are responsible for querying the hardware (the + * VIA/RBV/OSS/PSC chips) to determine the actual interrupt source. Using + * this information a machspec interrupt number is generated by placing the + * index of the interrupt hardware into the low three bits and the original + * autovector interrupt number in the upper 5 bits. The handlers for the + * resulting machspec interrupt are then called. + * + * - Nubus is a special case because its interrupts are hidden behind two + * layers of hardware. Nubus interrupts come in as index 1 on VIA #2, + * which translates to IRQ number 17. In this spot we install _another_ + * dispatcher. This dispatcher finds the interrupting slot number (9-F) and + * then forms a new machspec interrupt number as above with the slot number + * minus 9 in the low three bits and the pseudo-level 7 in the upper five + * bits. The handlers for this new machspec interrupt number are then + * called. This puts Nubus interrupts into the range 56-62. + * + * - We support "fast" and "slow" handlers, just like the Amiga port. The + * fast handlers are called first and with all interrupts disabled. They + * are expected to execute quickly (hence the name). The slow handlers are + * called last with interrupts enabled and the interrupt level restored. + * They must therefore be reentrant. + * + * - Drivers should never try to request autovector interrupt numbers. It + * won't work. * * TODO: - * - integrate Nubus interrupts in request/free_irq * - * - + * o Perhaps build some intelligence into mac_SCC_handler(); we could check + * the SCC ourselves and only call the handler for the appopriate channel. */ #include @@ -82,124 +128,53 @@ #include #include #include -#include "via6522.h" +#include +#include #include /* - * Interrupt handler and parameter types - */ -struct irqhandler { - void (*handler)(int, void *, struct pt_regs *); - void *dev_id; -}; - -struct irqparam { - unsigned long flags; - const char *devname; -}; - -struct irqflags { - unsigned int disabled; - unsigned int pending; -}; - -/* - * Array with irq's and their parameter data. - */ -static struct irqhandler via1_handler[8]; -static struct irqhandler via2_handler[8]; -static struct irqhandler rbv_handler[8]; -static struct irqhandler psc3_handler[8]; -static struct irqhandler scc_handler[8]; -static struct irqhandler psc5_handler[8]; -static struct irqhandler psc6_handler[8]; -static struct irqhandler nubus_handler[8]; - -static struct irqhandler *handler_table[8]; - -/* - * This array hold the rest of parameters of int handlers: type - * (slow,fast,prio) and the name of the handler. These values are only - * accessed from C - */ -static struct irqparam via1_param[8]; -static struct irqparam via2_param[8]; -static struct irqparam rbv_param[8]; -static struct irqparam psc3_param[8]; -static struct irqparam scc_param[8]; -static struct irqparam psc5_param[8]; -static struct irqparam psc6_param[8]; -static struct irqparam nubus_param[8]; - -static struct irqparam *param_table[8]; - -/* - * This array holds the 'disabled' and 'pending' software flags maintained - * by mac_{enable,disable}_irq and the generic via_irq function. + * VIA/RBV hooks */ -static struct irqflags irq_flags[8]; +extern void via_init(void); +extern void via_register_interrupts(void); +extern void via_irq_enable(int); +extern void via_irq_disable(int); +extern void via_irq_clear(int); +extern int via_irq_pending(int); /* - * This array holds the pointers to the various VIA or other interrupt - * controllers, indexed by interrupt level + * OSS hooks */ -static volatile unsigned char *via_table[8]; - -/* - * Arrays with irq statistics - */ -static unsigned long via1_irqs[8]; -static unsigned long via2_irqs[8]; -static unsigned long rbv_irqs[8]; -static unsigned long psc3_irqs[8]; -static unsigned long scc_irqs[8]; -static unsigned long psc5_irqs[8]; -static unsigned long psc6_irqs[8]; -static unsigned long nubus_irqs[8]; - -static unsigned long *mac_irqs[8]; - -/* - * Some special nutcases ... - */ +extern int oss_present; -static unsigned long mac_ide_irqs = 0; -static unsigned long nubus_stuck_events = 0; +extern void oss_init(void); +extern void oss_register_interrupts(void); +extern void oss_irq_enable(int); +extern void oss_irq_disable(int); +extern void oss_irq_clear(int); +extern int oss_irq_pending(int); /* - * VIA/RBV/OSS/PSC register base pointers + * PSC hooks */ -volatile unsigned char *via2_regp=(volatile unsigned char *)VIA2_BAS; -volatile unsigned char *rbv_regp=(volatile unsigned char *)VIA2_BAS_IIci; -volatile unsigned char *oss_regp=(volatile unsigned char *)OSS_BAS; -volatile unsigned char *psc_regp=(volatile unsigned char *)PSC_BAS; - -/* - * Flags to control via2 / rbv behaviour - */ - -static int via2_is_rbv = 0; -static int via2_is_oss = 0; -static int rbv_clear = 0; +extern int psc_present; -/* fake VIA2 to OSS bit mapping */ -static int oss_map[8] = {2, 7, 0, 1, 3, 4, 5}; - -void oss_irq(int irq, void *dev_id, struct pt_regs *regs); -static void oss_do_nubus(int irq, void *dev_id, struct pt_regs *regs); - -/* PSC ints */ -void psc_irq(int irq, void *dev_id, struct pt_regs *regs); +extern void psc_init(void); +extern void psc_register_interrupts(void); +extern void psc_irq_enable(int); +extern void psc_irq_disable(int); +extern void psc_irq_clear(int); +extern int psc_irq_pending(int); /* - * PSC hooks + * IOP hooks */ -extern void psc_init(void); +extern void iop_register_interrupts(void); /* * console_loglevel determines NMI handler function @@ -207,656 +182,317 @@ extern int console_loglevel; -/* - * ADB test hooks - */ -extern int in_keybinit; -void adb_queue_poll(void); - -/* Defined in entry.S; only increments 'num_spurious' */ -asmlinkage void bad_interrupt(void); - -void nubus_wtf(int slot, void *via, struct pt_regs *regs); - -void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *regs); -void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs); +extern void mac_bang(int, void *, struct pt_regs *); -static void via_do_nubus(int slot, void *via, struct pt_regs *regs); +void mac_nmi_handler(int, void *, struct pt_regs *); +void mac_SCC_handler(int, void *, struct pt_regs *); /* #define DEBUG_MACINTS */ -#define DEBUG_SPURIOUS -#define DEBUG_NUBUS_SPURIOUS -#define DEBUG_NUBUS_INT - -/* #define DEBUG_VIA */ -#define DEBUG_VIA_NUBUS - void mac_init_IRQ(void) { - int i; - #ifdef DEBUG_MACINTS - printk("Mac interrupt stuff initializing ...\n"); + printk("mac_init_IRQ(): Setting things up...\n"); #endif - - via2_regp = (unsigned char *)VIA2_BAS; - rbv_regp = (unsigned char *)VIA2_BAS_IIci; - - /* initialize the hardwired (primary, autovector) IRQs */ - - /* level 1 IRQ: VIA1, always present */ - sys_request_irq(1, via1_irq, IRQ_FLG_LOCK, "via1", via1_irq); - - /* via2 or rbv?? */ - if (macintosh_config->via_type == MAC_VIA_IIci) { - /* - * A word of caution: the definitions here only affect interrupt - * handling, see via6522.c for yet another file to change - * base addresses and RBV flags - */ - - /* yes, this is messy - the IIfx deserves a class of his own */ - if (macintosh_config->ident == MAC_MODEL_IIFX) { - /* no real VIA2, the OSS seems _very_ different */ - via2_is_oss = 1; - /* IIfx has OSS, at a different base address than RBV */ - rbv_regp = (unsigned char *) OSS_BAS; - sys_request_irq(2, oss_irq, IRQ_FLG_LOCK, "oss", oss_irq); - } else { - /* VIA2 is part of the RBV: different base, other offsets */ - via2_is_rbv = 1; - - /* LC III weirdness: IFR seems to behave like VIA2 */ - /* FIXME: maybe also for LC II ?? */ - if (macintosh_config->ident == MAC_MODEL_LCIII) { - rbv_clear = 0x0; - } else { - rbv_clear = 0x80; - } - /* level 2 IRQ: RBV/OSS; we only care about RBV for now */ - sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq); - } - } else - /* level 2 IRQ: VIA2 */ - sys_request_irq(2, via2_irq, IRQ_FLG_LOCK, "via2", via2_irq); - /* - * level 4 IRQ: SCC - use 'master' interrupt routine that calls the - * registered channel-specific interrupts in turn. - * Currently, one interrupt per channel is used, solely - * to pass the correct async_info as parameter! + * Register the handlers for the the master IRQ handlers + * at levels 1-7. Most of the work is done elsewhere. */ - sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler); - - /* level 6 */ - sys_request_irq(6, mac_bang, IRQ_FLG_LOCK, "offswitch", mac_bang); - - /* level 7 (or NMI) : debug stuff */ - sys_request_irq(7, mac_nmi_handler, IRQ_FLG_STD, "NMI", mac_nmi_handler); - - /* initialize the handler tables for VIAs */ - for (i = 0; i < 8; i++) { - via1_handler[i].handler = mac_default_handler; - via1_handler[i].dev_id = NULL; - via1_param[i].flags = IRQ_FLG_STD; - via1_param[i].devname = NULL; - - via2_handler[i].handler = mac_default_handler; - via2_handler[i].dev_id = NULL; - via2_param[i].flags = IRQ_FLG_STD; - via2_param[i].devname = NULL; - - rbv_handler[i].handler = mac_default_handler; - rbv_handler[i].dev_id = NULL; - rbv_param[i].flags = IRQ_FLG_STD; - rbv_param[i].devname = NULL; - - scc_handler[i].handler = mac_default_handler; - scc_handler[i].dev_id = NULL; - scc_param[i].flags = IRQ_FLG_STD; - scc_param[i].devname = NULL; - - /* NUBUS interrupts routed through VIA2 slot 2 - special */ - nubus_handler[i].handler = nubus_wtf; - nubus_handler[i].dev_id = NULL; - nubus_param[i].flags = IRQ_FLG_STD; - nubus_param[i].devname = NULL; - - } - - /* initialize the handler tables (level 1 -> via_handler[0] !!!) */ - via_table[0] = via1_regp; - handler_table[0] = &via1_handler[0]; - param_table[0] = &via1_param[0]; - mac_irqs[0] = &via1_irqs[0]; - - if (via2_is_rbv || via2_is_oss) { - via_table[1] = rbv_regp; - handler_table[1] = &rbv_handler[0]; - param_table[1] = &rbv_param[0]; - mac_irqs[1] = &rbv_irqs[0]; + if (oss_present) { + oss_register_interrupts(); } else { - via_table[1] = via2_regp; - handler_table[1] = &via2_handler[0]; - param_table[1] = &via2_param[0]; - mac_irqs[1] = &via2_irqs[0]; - } - via_table[2] = NULL; - via_table[3] = NULL; - - handler_table[2] = &rbv_handler[0]; - handler_table[3] = &scc_handler[0]; - handler_table[4] = NULL; - handler_table[5] = NULL; - handler_table[6] = NULL; - handler_table[7] = &nubus_handler[0]; - - param_table[2] = &rbv_param[0]; - param_table[3] = &scc_param[0]; - param_table[7] = &nubus_param[0]; - - mac_irqs[2] = &rbv_irqs[0]; - mac_irqs[3] = &scc_irqs[0]; - mac_irqs[7] = &nubus_irqs[0]; - - /* - * Nubus Macs: turn off the Nubus dispatch interrupt for now - */ - - mac_turnoff_irq(IRQ_MAC_NUBUS); - - /* - * AV Macs: shutup the PSC ints - */ - if (macintosh_config->ident == MAC_MODEL_C660 - || macintosh_config->ident == MAC_MODEL_Q840) - { - psc_init(); - - handler_table[2] = &psc3_handler[0]; - /* handler_table[3] = &psc4_handler[0]; */ - handler_table[4] = &psc5_handler[0]; - handler_table[5] = &psc6_handler[0]; - - param_table[2] = &psc3_param[0]; - /* param_table[3] = &psc4_param[0]; */ - param_table[4] = &psc5_param[0]; - param_table[5] = &psc6_param[0]; - - mac_irqs[2] = &psc3_irqs[0]; - /* mac_irqs[3] = &psc4_irqs[0]; */ - mac_irqs[4] = &psc5_irqs[0]; - mac_irqs[5] = &psc6_irqs[0]; - - sys_request_irq(3, psc_irq, IRQ_FLG_STD, "PSC3", psc_irq); - sys_request_irq(4, psc_irq, IRQ_FLG_STD, "PSC4", psc_irq); - sys_request_irq(5, psc_irq, IRQ_FLG_STD, "PSC5", psc_irq); - sys_request_irq(6, psc_irq, IRQ_FLG_STD, "PSC6", psc_irq); + via_register_interrupts(); } - + if (psc_present) psc_register_interrupts(); + iop_register_interrupts(); + request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler); #ifdef DEBUG_MACINTS - printk("Mac interrupt init done!\n"); + printk("mac_init_IRQ(): Done!\n"); #endif } /* - * We have no machine specific interrupts on a macintoy - * Yet, we need to register/unregister interrupts ... :-) - * Currently unimplemented: Test for valid irq number, chained irqs, - * Nubus interrupts (use nubus_request_irq!). + * Routines to work with irq_node_t's on linked lists lifted from + * the Amiga code written by Roman Zippel. */ - -int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id) -{ - int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - struct irqhandler *via_handler; - struct irqparam *via_param; - volatile unsigned char *via; - -#ifdef DEBUG_MACINTS - printk ("%s: IRQ %d on VIA%d[%d] requested from %s\n", - __FUNCTION__, irq, srcidx+1, irqidx, devname); -#endif - - if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) { - printk ("%s: Bad irq type %ld requested from %s\n", - __FUNCTION__, flags, devname); - return -EINVAL; - } - - /* figure out what VIA is handling this irq */ - if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) { - /* non-via irqs unimplemented */ - printk ("%s: Bad irq source %d on VIA %d requested from %s\n", - __FUNCTION__, irq, srcidx, devname); - return -EINVAL; - } - - /* figure out if SCC pseudo-irq (redundant ??) */ - if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) { - /* set specific SCC handler */ - scc_handler[irqidx].handler = handler; - scc_handler[irqidx].dev_id = dev_id; - scc_param[irqidx].flags = flags; - scc_param[irqidx].devname = devname; - /* and done! */ - return 0; - } - - /* - * code below: only for VIA irqs currently - * add similar hack for Nubus pseudo-irq here - hide nubus_request_irq - */ - via = (volatile unsigned char *) via_table[srcidx]; - if (!via) - return -EINVAL; - - via_handler = handler_table[srcidx]; - via_param = param_table[srcidx]; - - /* check for conflicts or possible replacement */ - - /* set the handler - no chained irqs yet !! */ - via_handler[irqidx].handler = handler; - via_handler[irqidx].dev_id = dev_id; - via_param[irqidx].flags = flags; - via_param[irqidx].devname = devname; - - /* and turn it on ... careful, that's VIA only ... */ - if (srcidx == SRC_VIA2 && via2_is_rbv) - via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx))); - else if (srcidx == SRC_VIA2 && via2_is_oss) - via_write(oss_regp, oss_map[irqidx]+8, 2); - else - via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx))); - - - if (irq == IRQ_IDX(IRQ_MAC_SCSI)) { - /* - * Set vPCR for SCSI interrupts. (what about RBV here?) - * 980429 MS: RBV is ok, OSS seems to be different - */ - if (!via2_is_oss) - if (macintosh_config->scsi_type == MAC_SCSI_OLD) { - /* CB2 (IRQ) indep. interrupt input, positive edge */ - /* CA2 (DRQ) indep. interrupt input, positive edge */ - via_write(via, vPCR, 0x66); - } else { - /* CB2 (IRQ) indep. interrupt input, negative edge */ - /* CA2 (DRQ) indep. interrupt input, negative edge */ - via_write(via, vPCR, 0x22); - } -#if 0 - else - /* CB2 (IRQ) indep. interrupt input, negative edge */ - /* CA2 (DRQ) indep. interrupt input, negative edge */ - via_write(via, vPCR, 0x22); -#endif - } - return 0; -} - -void mac_free_irq (unsigned int irq, void *dev_id) +static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node) { - unsigned long flags; - int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - struct irqhandler *via_handler; - struct irqparam *via_param; - volatile unsigned char *via; + unsigned long cpu_flags; + irq_node_t *cur; -#ifdef DEBUG_MACINTS - printk ("%s: IRQ %d on VIA%d[%d] freed\n", - __FUNCTION__, irq, srcidx+1, irqidx); -#endif + if (!node->dev_id) + printk("%s: Warning: dev_id of %s is zero\n", + __FUNCTION__, node->devname); - /* figure out what VIA is handling this irq */ - if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) { - /* non-via irqs unimplemented */ - return; - } - - save_flags(flags); + save_flags(cpu_flags); cli(); - /* figure out if SCC pseudo-irq */ - if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) { - /* clear specific SCC handler */ - scc_handler[irqidx].handler = mac_default_handler; - scc_handler[irqidx].dev_id = NULL; - scc_param[irqidx].flags = IRQ_FLG_STD; - scc_param[irqidx].devname = NULL; - /* and done! */ - restore_flags(flags); - return; - } + cur = *list; - via = (volatile unsigned char *) via_table[srcidx]; - via_handler = handler_table[srcidx]; - via_param = param_table[srcidx]; - - if ( !via || (via_handler[irqidx].dev_id != dev_id) ) { - restore_flags(flags); - goto not_found; + if (node->flags & IRQ_FLG_FAST) { + node->flags &= ~IRQ_FLG_SLOW; + while (cur && cur->flags & IRQ_FLG_FAST) { + list = &cur->next; + cur = cur->next; + } + } else if (node->flags & IRQ_FLG_SLOW) { + while (cur) { + list = &cur->next; + cur = cur->next; + } + } else { + while (cur && !(cur->flags & IRQ_FLG_SLOW)) { + list = &cur->next; + cur = cur->next; + } } - /* clear the handler - no chained irqs yet !! */ - via_handler[irqidx].handler = mac_default_handler; - via_handler[irqidx].dev_id = NULL; - via_param[irqidx].flags = IRQ_FLG_STD; - via_param[irqidx].devname = NULL; - - /* and turn it off */ - if (srcidx == SRC_VIA2 && via2_is_rbv) - via_write(via, rIER, (via_read(via, rIER)&(1<next = cur; + *list = node; + restore_flags(cpu_flags); } -/* - * {en,dis}able_irq have the usual semantics of temporary blocking the - * interrupt, but not loosing requests that happen between disabling and - * enabling. On Atari, this is done with the MFP mask registers. - * - * On the Mac, this isn't possible: there is no VIA mask register. - * Needs to be implemented in software, setting 'mask' bits in a separate - * struct for each interrupt controller. These mask bits need to be checked - * by the VIA interrupt routine which should ignore requests for masked IRQs - * (after possibly ack'ing them). - * - * On second thought: some of the IRQ sources _can_ be turned off via bits - * in the VIA output registers. Need to check this ... - * - * TBI: According to the VIA docs, clearing a bit in the IER has the effect of - * blocking generation of the interrupt, but the internal interrupt condition - * is preserved. So the IER might be used as mask register here, and turnon_irq - * would need to clear the interrupt bit in the IFR to prevent getting an - * interrupt at all. - * - * Implementation note: the irq no's here are the _machspec_ irqs, hence the - * hack with srcidx to figure out which VIA/RBV handles the interrupt. - * That's fundamentally different when it comes to the interrupt handlers - * proper: these get the interrupt level no. as argument, all information about - * which source triggered the int. is buried in the VIA IFR ... The int. level - * points us to the proper handler, so we could do a sanity check there ... - */ - -void mac_enable_irq (unsigned int irq) +static inline void mac_delete_irq(irq_node_t **list, void *dev_id) { - int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); + unsigned long cpu_flags; + irq_node_t *node; - irq_flags[srcidx].disabled &= ~(1<>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); + save_flags(cpu_flags); + cli(); - irq_flags[srcidx].disabled |= (1<next, node = *list) { + if (node->dev_id == dev_id) { + *list = node->next; + /* Mark it as free. */ + node->handler = NULL; + restore_flags(cpu_flags); + return; + } + } + restore_flags(cpu_flags); + printk ("%s: tried to remove invalid irq\n", __FUNCTION__); } /* - * In opposite to {en,dis}able_irq, requests between turn{off,on}_irq are not - * "stored". This is done with the VIA interrupt enable register on VIAs. + * Call all the handlers for a given interrupt. Fast handlers are called + * first followed by slow handlers. * - * Note: Using these functions on non-VIA/OSS/PSC ints will panic, or at least - * have undesired side effects. + * This code taken from the original Amiga code written by Roman Zippel. */ -void mac_turnon_irq( unsigned int irq ) +void mac_do_irq_list(int irq, struct pt_regs *fp) { - int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - volatile unsigned char *via; - - via = (volatile unsigned char *) via_table[srcidx]; - if (!via) - return; + irq_node_t *node, *slow_nodes, **list = NULL; + unsigned long cpu_flags; - if (srcidx == SRC_VIA2 && via2_is_rbv) /* RBV as VIA2 */ - via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx))); - else if (srcidx == SRC_VIA2 && via2_is_oss) /* OSS */ - via_write(oss_regp, oss_map[irqidx]+8, 2); - else if (srcidx > SRC_VIA2) /* hope AVs have VIA2 */ - via_write(via, (0x104 + 0x10*srcidx), - via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx))); - else /* VIA1+2 */ - via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx))); + kstat.irqs[0][irq]++; -} - -void mac_turnoff_irq( unsigned int irq ) -{ - int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - volatile unsigned char *via; + if (irq < VIA1_SOURCE_BASE) { + list = &autoirq_list[irq]; + } else if (irq < NUM_MAC_SOURCES) { + list = &userirq_list[irq - VIA1_SOURCE_BASE]; + } + if (!list) return; - via = (volatile unsigned char *) via_table[srcidx]; - if (!via) +#ifdef DEBUG_SPURIOUS + if (!*list && (console_loglevel > 7)) { + printk("mac_do_irq_list: spurious interrupt %d!\n", irq); return; + } +#endif - if (srcidx == SRC_VIA2 && via2_is_rbv) /* RBV as VIA2 */ - via_write(via, rIER, (via_read(via, rIER)&(1< SRC_VIA2) - via_write(via, (0x104 + 0x10*srcidx), - via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx))); - else /* VIA1+2 */ - via_write(via, vIER, (via_read(via, vIER)&(1<flags & IRQ_FLG_SLOW)); + node = node->next) + node->handler(irq, node->dev_id, fp); + if (!node) return; + save_flags(cpu_flags); + restore_flags((cpu_flags & ~0x0700) | (fp->sr & 0x0700)); + /* if slow handlers exists, serve them now */ + slow_nodes = node; + for (; node; node = node->next) { + node->handler(irq, node->dev_id, fp); + } } /* - * These functions currently only handle the software-maintained irq pending - * list for disabled irqs - manipulating the actual irq flags in the via would - * require clearing single bits in the via, such as (probably) - * via_write(via, vIFR, (via_read(via, vIFR)&(1<>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - - irq_flags[srcidx].pending &= ~(1<>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - - pending = irq_flags[srcidx].pending & (1< SRC_VIA2) - pending |= via_read(via, (0x100 + 0x10*srcidx))&(1<>3) - 1; - irqidx = (i & IRQ_IDX_MASK); - - /* - * Not present: skip - */ - - if (mac_irqs[srcidx] == NULL) - continue; - - /* - * never used by VIAs, unused by others so far, counts - * the magic 'nothing pending' cases ... - */ - if (irqidx == 7 && mac_irqs[srcidx][irqidx]) { - len += sprintf(buf+len, "Level %01d: %10lu (spurious) \n", - srcidx, - mac_irqs[srcidx][irqidx]); - continue; - } - - /* - * Nothing registered for this IPL: skip - */ - - if (handler_table[srcidx] == NULL) - continue; - - /* - * No handler installed: skip - */ - - if (handler_table[srcidx][irqidx].handler == mac_default_handler || - handler_table[srcidx][irqidx].handler == nubus_wtf) - continue; - - - if (i < VIA2_SOURCE_BASE) - len += sprintf(buf+len, "via1 %01d: %10lu ", - irqidx, - mac_irqs[srcidx][irqidx]); - else if (i < RBV_SOURCE_BASE) - len += sprintf(buf+len, "via2 %01d: %10lu ", - irqidx, - mac_irqs[srcidx][irqidx]); - else if (i < MAC_SCC_SOURCE_BASE) - len += sprintf(buf+len, "rbv %01d: %10lu ", - irqidx, - mac_irqs[srcidx][irqidx]); - else if (i < NUBUS_SOURCE_BASE) - len += sprintf(buf+len, "scc %01d: %10lu ", - irqidx, - mac_irqs[srcidx][irqidx]); - else /* Nubus */ - len += sprintf(buf+len, "nubus %01d: %10lu ", - irqidx, - mac_irqs[srcidx][irqidx]); - - len += sprintf(buf+len, "%s\n", - param_table[srcidx][irqidx].devname); +#ifdef DEBUG_MACINTS + printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname); +#endif + if (irq < VIA1_SOURCE_BASE) { + vec = VEC_SPUR + irq; + } else if (irq < NUM_MAC_SOURCES) { + vec = VEC_USER + irq - VIA1_SOURCE_BASE; + } else { + printk ("%s: unknown irq %d requested by %s\n", + __FUNCTION__, irq, devname); + return -EAGAIN; } - if (num_spurious) - len += sprintf(buf+len, "spurio.: %10u\n", num_spurious); - - /* - * XXX Fixme: Nubus sources are never logged above ... - */ - - len += sprintf(buf+len, "Nubus interrupts:\n"); - - for (i = 0; i < 7; i++) { - if (nubus_handler[i].handler == nubus_wtf) - continue; - len += sprintf(buf+len, "nubus %01X: %10lu ", - i+9, - nubus_irqs[i]); - len += sprintf(buf+len, "%s\n", - nubus_param[i].devname); + ret = sys_request_listirq(vec, handler, flags, devname, dev_id); + if (!ret) { + vectors[vec] = autoirq_listhandler; + mac_enable_irq(irq); } - len += sprintf(buf+len, "nubus spurious ints: %10lu\n", - nubus_irqs[7]); - len += sprintf(buf+len, "nubus stuck events : %10lu\n", - nubus_stuck_events); -#ifdef CONFIG_BLK_DEV_IDE - len += sprintf(buf+len, "nubus/IDE interrupt: %10lu\n", - mac_ide_irqs); -#endif - return len; + return ret; } + +/* + * Removes an interrupt service routine from an interrupt source. + */ -void via_scsi_clear(void) +void mac_free_irq(unsigned int irq, void *dev_id) { - volatile unsigned char deep_magic; - if (via2_is_rbv) { - via_write(rbv_regp, rIFR, (1<<3)|(1<<0)|0x80); - deep_magic = via_read(rbv_regp, rBufB); - } else if (via2_is_oss) { - /* nothing */ - /* via_write(oss_regp, 9, 0) */; - } else - deep_magic = via_read(via2_regp, vBufB); - mac_enable_irq( IRQ_IDX(IRQ_MAC_SCSI) ); -} + irq_node_t **list = NULL; + int vec = 0; - -void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs) -{ -#ifdef DEBUG_SPURIOUS - if (console_loglevel > 6) - printk("Unexpected IRQ %d on device %p\n", irq, dev_id); +#ifdef DEBUG_MACINTS + printk ("%s: irq %d freed by %p\n", __FUNCTION__, irq, dev_id); #endif -} -static int num_debug[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + if (irq < VIA1_SOURCE_BASE) { + vec = VEC_SPUR + irq; + list = &autoirq_list[irq]; + } else if (irq < NUM_MAC_SOURCES) { + vec = VEC_USER + irq - VIA1_SOURCE_BASE; + list = &userirq_list[irq - VIA1_SOURCE_BASE]; + } + if (!list) return; -void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs) -{ - if (num_debug[irq] < 10) { - printk("DEBUG: Unexpected IRQ %d\n", irq); - num_debug[irq]++; + sys_free_irq(vec, dev_id); + + /* If the list for this interrupt is */ + /* empty then disable the source. */ + + if (!*list) { + mac_disable_irq(irq); + vectors[vec] = bad_interrupt; } } -void scsi_mac_debug(void); -void scsi_mac_polled(void); - static int in_nmi = 0; static volatile int nmi_hold = 0; @@ -869,10 +505,6 @@ */ in_nmi++; -#if 0 - scsi_mac_debug(); - printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp); -#endif for (i=0; i<100; i++) udelay(1000); @@ -889,10 +521,6 @@ while (nmi_hold == 1) udelay(1000); -#if 0 - scsi_mac_polled(); -#endif - if ( console_loglevel >= 8 ) { #if 0 show_state(); @@ -916,799 +544,12 @@ } /* - * Unexpected via interrupt - */ - -void via_wtf(int slot, void *via, struct pt_regs *regs) -{ -#ifdef DEBUG_SPURIOUS - if (console_loglevel > 6) - printk("Unexpected nubus event %d on via %p\n",slot,via); -#endif -} - -/* - * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's - * via6522.c :-), disable/pending masks added. - * The int *viaidx etc. is just to keep the prototype happy ... - */ - -static void via_irq(unsigned char *via, int *viaidx, struct pt_regs *regs) -{ - unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F; - int i; - int ct = 0; - struct irqhandler *via_handler = handler_table[*viaidx]; - struct irqparam *via_param = param_table[*viaidx]; - unsigned long *via_irqs = mac_irqs[*viaidx]; - - /* to be changed, possibly: for each non'masked', enabled IRQ, read - * flag bit, ack and call handler ... - * Currently: all pending irqs ack'ed en bloc. - * If ack for masked IRQ required: keep 'pending' info separate. - */ - - /* shouldn't we disable interrupts here ?? */ - - - /* - * Shouldnt happen - */ - - if(events==0) - { -#ifdef DEBUG_VIA - /* should go away; mostly missing timer ticks and ADB events */ - printk("via%d_irq: nothing pending, flags %x mask %x!\n", - *viaidx + 1, via_read(via, vIFR), via_read(via,vIER)); -#endif - via_irqs[7]++; - return; - } - -#ifdef DEBUG_VIA - /* - * limited verbosity for VIA interrupts - */ -#if 0 - if ( (*viaidx == 0 && events != 1<<6) /* timer int */ - || (*viaidx == 1 && events != 1<<3) ) /* SCSI IRQ */ -#else - if ( *viaidx == 0 && (events & 1<<2) ) -#endif - printk("via_irq: irq %d events %x !\n", (*viaidx)+1, events); -#endif - - do { - /* - * Clear the pending flag - */ - - via_write(via, vIFR, events); - - /* - * Now see what bits are raised - */ - - for(i=0;i<7;i++) - { - /* determine machspec. irq no. */ - int irq = ((*viaidx)+1)* 8 + i; - /* call corresponding handlers */ - if (events&(1< mark pending */ - irq_flags[*viaidx].pending |= (1< call handler */ - (via_handler[i].handler)(irq, via, regs); - } - } - /* and call handlers for pending irqs - first ?? */ - if ( (irq_flags[*viaidx].pending & (1<8) - { -#ifdef DEBUG_VIA - printk("via%d: stuck events %x\n", (*viaidx)+1, events); -#endif - break; - } - } - while(events); -#if 0 - scsi_mac_polled(); -#endif -} - -/* - * Caution: the following stuff is called from process_int as _autovector_ - * system interrupts. So irq is always in the range 0-7 :-( and the selection - * of the appropriate VIA is up to the irq handler here based on the autovec - * irq number. There's no information whatsoever about which source on the VIA - * triggered the int - and that's what the machspec irq no's are about. - * Broken design :-(((( - */ - -/* - * System interrupts - */ - -void via1_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - int srcidx = IRQ_IDX(irq) - 1; - via_irq((unsigned char *)via1_regp, &srcidx, regs); -} - - -/* - * Nubus / SCSI interrupts, VIA style (could be wrapped into via1_irq or - * via_irq directly by selecting the regp based on the irq!) - */ - -void via2_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - int srcidx = IRQ_IDX(irq) - 1; - via_irq((unsigned char *)via2_regp, &srcidx, regs); -} - -/* - * Nubus / SCSI interrupts; RBV style - * The RBV is different. RBV appears to stand for randomly broken - * VIA (or even real broken VIA). - */ - -void rbv_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - int srcidx = IRQ_IDX(irq) - 1; /* MUST be 1 !! */ - volatile unsigned char *via = rbv_regp; - unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F; - int i; - int ct = 0; - struct irqhandler *via_handler = handler_table[srcidx]; - struct irqparam *via_param = param_table[srcidx]; - - /* shouldn't we disable interrupts here ?? */ - - - /* - * Shouldnt happen - */ - - if(events==0) - { -#ifdef DEBUG_VIA - printk("rbv_irq: nothing pending, flags %x mask %x!\n", - via_read(via, rIFR), via_read(via,rIER)); -#endif - rbv_irqs[7]++; - return; - } - -#ifdef DEBUG_VIA - /* - * limited verbosity for RBV interrupts (add more if needed) - */ - if ( srcidx == 1 && events != 1<<3 ) /* SCSI IRQ */ - printk("rbv_irq: irq %d (%d) events %x !\n", irq, srcidx+1, events); -#endif - - /* to be changed, possibly: for each non'masked', enabled IRQ, read - * flag bit, ack and call handler ... - * Currently: all pending irqs ack'ed en bloc. - * If ack for masked IRQ required: keep 'pending' info separate. - */ - - do { - /* - * Clear the pending flag - */ - - via_write(via, rIFR, events | rbv_clear); - - /* - * Now see what bits are raised - */ - - for(i=0;i<7;i++) - { - /* determine machspec. irq no. */ - int irq = (srcidx+1)* 8 + i; - /* call corresponding handlers */ - if (events&(1< mark pending */ - irq_flags[srcidx].pending |= (1< call handler */ - (via_handler[i].handler)(irq, via, regs); - } - } - /* and call handlers for pending irqs - first ?? */ - if ( (irq_flags[srcidx].pending & (1<8) - { - printk("rbv: stuck events %x\n",events); - for(i=0;i<7;i++) - { - if(events&(1< mark pending */ - irq_flags[srcidx].pending |= (1< call handler */ - (via_handler[i].handler)(irq, via, regs); - } - } - /* and call handlers for pending irqs - first ?? */ - if ( (irq_flags[srcidx].pending & (1<8) - { - printk("oss: stuck events %x\n",events); - for(i=0;i<7;i++) - { - if(events&(1< 6) - printk("Unexpected interrupt on nubus slot %d\n",slot); -#endif -} - -/* * SCC master interrupt handler; sole purpose: pass the registered * async struct to the SCC handler proper. */ void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs) { - int i; - /* 1+2: compatibility with PSC ! */ - for (i = 1; i < 3; i++) /* currently only these two used */ - if (scc_handler[i].handler != mac_default_handler) { - (scc_handler[i].handler)(i, scc_handler[i].dev_id, regs); - scc_irqs[i]++; - } -} - -/* - * PSC interrupt handler - */ - -void psc_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - int srcidx = IRQ_IDX(irq) - 1; - volatile unsigned char *via = psc_regp; - unsigned int pIFR = 0x100 + 0x10*srcidx; - unsigned int pIER = 0x104 + 0x10*srcidx; - unsigned char events=(via_read(via, pIFR)&via_read(via,pIER))&0xF; - int i; - int ct = 0; - struct irqhandler *via_handler = handler_table[srcidx]; - struct irqparam *via_param = param_table[srcidx]; - - /* shouldn't we disable interrupts here ?? */ - - - /* - * Shouldnt happen - */ - - if(events==0) - { -#ifdef DEBUG_VIA - printk("psc_irq: nothing pending, flags %x mask %x!\n", - via_read(via, pIFR), via_read(via,pIER)); -#endif - mac_irqs[srcidx][7]++; - return; - } - -#ifdef DEBUG_VIA - /* - * limited verbosity for PSC interrupts (add more if needed) - */ - if ( srcidx == 1 && events != 1<<3 && events != 1<<1 ) /* SCSI IRQ */ - printk("psc_irq: irq %d srcidx+1 %d events %x !\n", irq, srcidx+1, events); -#endif - - /* to be changed, possibly: for each non'masked', enabled IRQ, read - * flag bit, ack and call handler ... - * Currently: all pending irqs ack'ed en bloc. - * If ack for masked IRQ required: keep 'pending' info separate. - */ - - do { - /* - * Clear the pending flag - */ - - /* via_write(via, pIFR, events); */ - - /* - * Now see what bits are raised - */ - - for(i=0;i<7;i++) - { - /* determine machspec. irq no. */ - int irq = (srcidx+1)* 8 + i; - /* call corresponding handlers */ - if (events&(1< mark pending */ - irq_flags[srcidx].pending |= (1< call handler */ - (via_handler[i].handler)(irq, via, regs); - } - } - /* and call handlers for pending irqs - first ?? */ - if ( (irq_flags[srcidx].pending & (1<8) - { - printk("psc: stuck events %x\n",events); - for(i=0;i<7;i++) - { - if(events&(1< 5) - printk("nubus_irq: nothing pending, map %x mask %x active %x\n", - allints, nubus_active, map); -#endif - nubus_irqs[7]++; - } - /* clear it */ - if (allints) - if (via2_is_rbv) - via_write(rbv_regp, rIFR, 0x02); - else - via_write(via2_regp, vIFR, 0x02); - break; - } - -#ifdef DEBUG_VIA_NUBUS - if (console_loglevel > 6) - printk("nubus_irq: map %x mask %x active %x\n", - allints, nubus_active, map); -#endif - -#ifdef CONFIG_BLK_DEV_MAC_IDE - if (mac_ide_intr_hook && ide_pending) { - mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs); - mac_ide_irqs++; - } -#endif - - if(ct++>2) - { - if (console_loglevel > 5) - printk("nubus stuck events - %x/%x/%x ide %x\n", - allints, nubus_active, map, ide_pending); - nubus_stuck_events++; - - return; - } - - for(i=0;i<7;i++) - { - if(map&(1<2) - { -#if 0 - printk("nubus stuck events - %d/%d\n", map, nubus_active); -#endif - return; - } - - for(i=0;i<7;i++) - { - if(map&(1< +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +int oss_present; +volatile struct mac_oss *oss; + +void oss_irq(int, void *, struct pt_regs *); +void oss_nubus_irq(int, void *, struct pt_regs *); + +extern void via1_irq(int, void *, struct pt_regs *); +extern void mac_SCC_handler(int, void *, struct pt_regs *); +extern int console_loglevel; + +/* + * Initialize the OSS + * + * The OSS "detection" code is actually in via_init() which is always called + * before us. Thus we can count on oss_present being valid on entry. + */ + +void __init oss_init(void) +{ + int i; + + if (!oss_present) return; + + oss = (struct mac_oss *) OSS_BASE; + + /* Disable all interrupts. Unlike a VIA it looks like we */ + /* do this by setting the source's interrupt level to zero. */ + + for (i = 0; i <= OSS_NUM_SOURCES; i++) { + oss->irq_level[i] = OSS_IRQLEV_DISABLED; + } + /* If we disable VIA1 here, we never really handle it... */ + oss->irq_level[OSS_VIA1] = OSS_IRQLEV_VIA1; +} + +/* + * Register the OSS and NuBus interrupt dispatchers. + */ + +void __init oss_register_interrupts(void) +{ + request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK, + "OSS SCSI Dispatch", (void *) oss); + request_irq(OSS_IRQLEV_IOPSCC, mac_SCC_handler, IRQ_FLG_LOCK, + "SCC Dispatch", mac_SCC_handler); + request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK, + "Nubus Dispatch", (void *) oss); + request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK, + "OSS Sound Dispatch", (void *) oss); + request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK, + "VIA1 Dispatch", (void *) via1); +} + +/* + * Initialize OSS for Nubus access + */ + +void __init oss_nubus_init(void) +{ +} + +/* + * Turn off the power via the ROM control register + * + * FIXME: not sure how this is supposed to work exactly... + */ + +void oss_poweroff(void) +{ + oss->rom_ctrl = OSS_POWEROFF; + + /* We should never make it this far... */ + + printk ("It is now safe to switch off your machine.\n"); + while(1); +} + +/* + * Handle miscellaneous OSS interrupts. Right now that's just sound + * and SCSI; everything else is routed to its own autovector IRQ. + */ + +void oss_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int events; + + events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI); + if (!events) return; + +#ifdef DEBUG_IRQS + if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) { + printk("oss_irq: irq %d events = 0x%04X\n", irq, + (int) oss->irq_pending); + } +#endif + /* FIXME: how do you clear a pending IRQ? */ + + if (events & OSS_IP_SOUND) { + /* FIXME: call sound handler */ + oss->irq_pending &= ~OSS_IP_SOUND; + } else if (events & OSS_IP_SCSI) { + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED; + mac_do_irq_list(IRQ_MAC_SCSI, regs); + oss->irq_pending &= ~OSS_IP_SCSI; + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; + } else { + /* FIXME: error check here? */ + } +} + +/* + * Nubus IRQ handler, OSS style + * + * Unlike the VIA/RBV this is on its own autovector interupt level. + */ + +void oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int events, irq_bit, i; + + events = oss->irq_pending & OSS_IP_NUBUS; + if (!events) return; + +#ifdef DEBUG_NUBUS_INT + if (console_loglevel > 7) { + printk("oss_nubus_irq: events = 0x%04X\n", events); + } +#endif + /* There are only six slots on the OSS, not seven */ + + for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) { + if (events & irq_bit) { + oss->irq_level[i] = OSS_IRQLEV_DISABLED; + mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs); + oss->irq_pending &= ~irq_bit; + oss->irq_level[i] = OSS_IRQLEV_NUBUS; + } + } +} + +/* + * Enable an OSS interrupt + * + * It looks messy but it's rather straightforward. The switch() statement + * just maps the machspec interrupt numbers to the right OSS interrupt + * source (if the OSS handles that interrupt) and then sets the interrupt + * level for that source to nonzero, thus enabling the interrupt. + */ + +void oss_irq_enable(int irq) { +#ifdef DEBUG_IRQUSE + printk("oss_irq_enable(%d)\n", irq); +#endif + switch(irq) { + case IRQ_SCC: + case IRQ_SCCA: + case IRQ_SCCB: + oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_IOPSCC; + break; + case IRQ_MAC_ADB: + oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_IOPISM; + break; + case IRQ_MAC_SCSI: + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; + break; + case IRQ_NUBUS_9: + case IRQ_NUBUS_A: + case IRQ_NUBUS_B: + case IRQ_NUBUS_C: + case IRQ_NUBUS_D: + case IRQ_NUBUS_E: + irq -= NUBUS_SOURCE_BASE; + oss->irq_level[irq] = OSS_IRQLEV_NUBUS; + break; +#ifdef DEBUG_IRQUSE + default: + printk("%s unknown irq %d\n",__FUNCTION__, irq); + break; +#endif + } +} + +/* + * Disable an OSS interrupt + * + * Same as above except we set the source's interrupt level to zero, + * to disable the interrupt. + */ + +void oss_irq_disable(int irq) { +#ifdef DEBUG_IRQUSE + printk("oss_irq_disable(%d)\n", irq); +#endif + switch(irq) { + case IRQ_SCC: + case IRQ_SCCA: + case IRQ_SCCB: + oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_DISABLED; + break; + case IRQ_MAC_ADB: + oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_DISABLED; + break; + case IRQ_MAC_SCSI: + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED; + break; + case IRQ_NUBUS_9: + case IRQ_NUBUS_A: + case IRQ_NUBUS_B: + case IRQ_NUBUS_C: + case IRQ_NUBUS_D: + case IRQ_NUBUS_E: + irq -= NUBUS_SOURCE_BASE; + oss->irq_level[irq] = OSS_IRQLEV_DISABLED; + break; +#ifdef DEBUG_IRQUSE + default: + printk("%s unknown irq %d\n", __FUNCTION__, irq); + break; +#endif + } +} + +/* + * Clear an OSS interrupt + * + * Not sure if this works or not but it's the only method I could + * think of based on the contents of the mac_oss structure. + */ + +void oss_irq_clear(int irq) { + /* FIXME: how to do this on OSS? */ + switch(irq) { + case IRQ_SCC: + case IRQ_SCCA: + case IRQ_SCCB: + oss->irq_pending &= ~OSS_IP_IOPSCC; + break; + case IRQ_MAC_ADB: + oss->irq_pending &= ~OSS_IP_IOPISM; + break; + case IRQ_MAC_SCSI: + oss->irq_pending &= ~OSS_IP_SCSI; + break; + case IRQ_NUBUS_9: + case IRQ_NUBUS_A: + case IRQ_NUBUS_B: + case IRQ_NUBUS_C: + case IRQ_NUBUS_D: + case IRQ_NUBUS_E: + irq -= NUBUS_SOURCE_BASE; + oss->irq_pending &= ~(1 << irq); + break; + } +} + +/* + * Check to see if a specific OSS interrupt is pending + */ + +int oss_irq_pending(int irq) +{ + switch(irq) { + case IRQ_SCC: + case IRQ_SCCA: + case IRQ_SCCB: + return oss->irq_pending & OSS_IP_IOPSCC; + break; + case IRQ_MAC_ADB: + return oss->irq_pending & OSS_IP_IOPISM; + break; + case IRQ_MAC_SCSI: + return oss->irq_pending & OSS_IP_SCSI; + break; + case IRQ_NUBUS_9: + case IRQ_NUBUS_A: + case IRQ_NUBUS_B: + case IRQ_NUBUS_C: + case IRQ_NUBUS_D: + case IRQ_NUBUS_E: + irq -= NUBUS_SOURCE_BASE; + return oss->irq_pending & (1 << irq); + break; + } + return 0; +} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/psc.c linux/arch/m68k/mac/psc.c --- v2.3.16/linux/arch/m68k/mac/psc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/psc.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,203 @@ +/* + * Apple Peripheral System Controller (PSC) + * + * The PSC is used on the AV Macs to control IO functions not handled + * by the VIAs (Ethernet, DSP, SCC). + * + * TO DO: + * + * Try to figure out what's going on in pIFR5 and pIFR6. There seem to be + * persisant interrupt conditions in those registers and I have no idea what + * they are. Granted it doesn't affect since we're not enabling any interrupts + * on those levels at the moment, but it would be nice to know. I have a feeling + * they aren't actually interrupt lines but data lines (to the DSP?) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DEBUG_PSC + +int psc_present; +volatile __u8 *psc; + +void psc_irq(int, void *, struct pt_regs *); + +extern int console_loglevel; + +/* + * Debugging dump, used in various places to see what's going on. + */ + +void psc_debug_dump(void) +{ + int i; + + if (!psc_present) return; + for (i = 0x30 ; i < 0x70 ; i += 0x10) { + printk("PSC #%d: IFR = 0x%02X IER = 0x%02X\n", + i >> 4, + (int) psc_read_byte(pIFRbase + i), + (int) psc_read_byte(pIERbase + i)); + } +} + +/* + * Try to kill all DMA channels on the PSC. Not sure how this his + * supposed to work; this is code lifted from macmace.c and then + * expanded to cover what I think are the other 7 channels. + */ + +void psc_dma_die_die_die(void) +{ + int i; + + printk("Killing all PSC DMA channels..."); + for (i = 0 ; i < 9 ; i++) { + psc_write_word(PSC_CTL_BASE + (i << 4), 0x8800); + psc_write_word(PSC_CTL_BASE + (i << 4), 0x1000); + psc_write_word(PSC_CMD_BASE + (i << 5), 0x1100); + psc_write_word(PSC_CMD_BASE + (i << 5) + 0x10, 0x1100); + } + printk("done!\n"); +} + +/* + * Initialize the PSC. For now this just involves shutting down all + * interrupt sources using the IERs. + */ + +void __init psc_init(void) +{ + int i; + + if (macintosh_config->ident != MAC_MODEL_C660 + && macintosh_config->ident != MAC_MODEL_Q840) + { + psc = NULL; + psc_present = 0; + return; + } + + /* + * The PSC is always at the same spot, but using psc + * keeps things consisant with the psc_xxxx functions. + */ + + psc = (void *) PSC_BASE; + psc_present = 1; + + printk("PSC detected at %p\n", psc); + + psc_dma_die_die_die(); + +#ifdef DEBUG_PSC + psc_debug_dump(); +#endif + /* + * Mask and clear all possible interrupts + */ + + for (i = 0x30 ; i < 0x70 ; i += 0x10) { + psc_write_byte(pIERbase + i, 0x0F); + psc_write_byte(pIFRbase + i, 0x0F); + } +} + +/* + * Register the PSC interrupt dispatchers for autovector interrupts 3-6. + */ + +void __init psc_register_interrupts(void) +{ + request_irq(3, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", + (void *) 0x30); + request_irq(4, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", + (void *) 0x40); + request_irq(5, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", + (void *) 0x50); + request_irq(6, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", + (void *) 0x60); +} + +/* + * PSC interrupt handler. It's a lot like the VIA interrupt handler. + */ + +void psc_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int pIFR = pIFRbase + ((int) dev_id); + int pIER = pIERbase + ((int) dev_id); + int base_irq; + int irq_bit,i; + unsigned char events; + + irq -= VEC_SPUR; + base_irq = irq << 3; + +#ifdef DEBUG_IRQS + printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n", + irq, (int) psc_read_byte(pIFR), (int) psc_read_byte(pIER)); +#endif + + events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF; + if (!events) return; + + for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) { + if (events & irq_bit) { + psc_write_byte(pIER, irq_bit); + mac_do_irq_list(base_irq + i, regs); + psc_write_byte(pIFR, irq_bit); + psc_write_byte(pIER, irq_bit | 0x80); + } + } +} + +void psc_irq_enable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int pIER = pIERbase + (irq_src << 4); + +#ifdef DEBUG_IRQUSE + printk("psc_irq_enable(%d)\n", irq); +#endif + psc_write_byte(pIER, (1 << irq_idx) | 0x80); +} + +void psc_irq_disable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int pIER = pIERbase + (irq_src << 4); + +#ifdef DEBUG_IRQUSE + printk("psc_irq_disable(%d)\n", irq); +#endif + psc_write_byte(pIER, 1 << irq_idx); +} + +void psc_irq_clear(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int pIFR = pIERbase + (irq_src << 4); + + psc_write_byte(pIFR, 1 << irq_idx); +} + +int psc_irq_pending(int irq) +{ + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int pIFR = pIERbase + (irq_src << 4); + + return psc_read_byte(pIFR) & (1 << irq_idx); +} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/via.c linux/arch/m68k/mac/via.c --- v2.3.16/linux/arch/m68k/mac/via.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/via.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,774 @@ +/* + * 6522 Versatile Interface Adapter (VIA) + * + * There are two of these on the Mac II. Some IRQ's are vectored + * via them as are assorted bits and bobs - eg RTC, ADB. + * + * CSA: Motorola seems to have removed documentation on the 6522 from + * their web site; try + * http://nerini.drf.com/vectrex/other/text/chips/6522/ + * http://www.zymurgy.net/classic/vic20/vicdet1.htm + * and + * http://193.23.168.87/mikro_laborversuche/via_iobaustein/via6522_1.html + * for info. A full-text web search on 6522 AND VIA will probably also + * net some usefulness. 20apr1999 + * + * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b + * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org) + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +volatile __u8 *via1, *via2; +#if 0 +/* See note in mac_via.h about how this is possibly not useful */ +volatile long *via_memory_bogon=(long *)&via_memory_bogon; +#endif +int rbv_present,via_alt_mapping; +__u8 rbv_clear; + +/* + * Globals for accessing the VIA chip registers without having to + * check if we're hitting a real VIA or an RBV. Normally you could + * just hit the combined register (ie, vIER|rIER) but that seems to + * break on AV Macs...probably because they actually decode more than + * eight address bits. Why can't Apple engineers at least be + * _consistantly_ lazy? - 1999-05-21 (jmt) + */ + +static int gIER,gIFR,gBufA,gBufB; + +/* + * Timer defs. + */ + +#define TICK_SIZE 10000 +#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */ +#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) +#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) + +static int nubus_active; + +void via_debug_dump(void); +void via1_irq(int, void *, struct pt_regs *); +void via2_irq(int, void *, struct pt_regs *); +void via_nubus_irq(int, void *, struct pt_regs *); +void via_irq_enable(int irq); +void via_irq_disable(int irq); +void via_irq_clear(int irq); + +extern void mac_bang(int, void *, struct pt_regs *); +extern void mac_SCC_handler(int, void *, struct pt_regs *); +extern int console_loglevel; +extern int oss_present; + +/* + * Initialize the VIAs + * + * First we figure out where they actually _are_ as well as what type of + * VIA we have for VIA2 (it could be a real VIA or an RBV or even an OSS.) + * Then we pretty much clear them out and disable all IRQ sources. + * + * Note: the OSS is actually "detected" here and not in oss_init(). It just + * seems more logical to do it here since via_init() needs to know + * these things anyways. + */ + +void __init via_init(void) +{ + switch(macintosh_config->via_type) { + + /* IIci, IIsi, IIvx, IIvi (P6xx), LC series */ + + case MAC_VIA_IIci: + via1 = (void *) VIA1_BASE; + if (macintosh_config->ident == MAC_MODEL_IIFX) { + via2 = NULL; + rbv_present = 0; + oss_present = 1; + } else { + via2 = (void *) RBV_BASE; + rbv_present = 1; + oss_present = 0; + } + if (macintosh_config->ident == MAC_MODEL_LCIII) { + rbv_clear = 0x00; + } else { + /* on most RBVs (& unlike the VIAs), you */ + /* need to set bit 7 when you write to IFR */ + /* in order for your clear to occur. */ + rbv_clear = 0x80; + } + gIER = rIER; + gIFR = rIFR; + gBufA = rSIFR; + gBufB = rBufB; + break; + + /* Quadra and early MacIIs agree on the VIA locations */ + + case MAC_VIA_QUADRA: + case MAC_VIA_II: + via1 = (void *) VIA1_BASE; + via2 = (void *) VIA2_BASE; + rbv_present = 0; + oss_present = 0; + rbv_clear = 0x00; + gIER = vIER; + gIFR = vIFR; + gBufA = vBufA; + gBufB = vBufB; + break; + default: + panic("UNKNOWN VIA TYPE"); + } + + printk("VIA1 at %p is a 6522 or clone\n", via1); + + printk("VIA2 at %p is ", via2); + if (rbv_present) { + printk("an RBV\n"); + } else if (oss_present) { + printk("an OSS\n"); + } else { + printk("a 6522 or clone\n"); + } + +#ifdef DEBUG_VIA + via_debug_dump(); +#endif + + /* + * Shut down all IRQ sources, reset the timers, and + * kill the timer latch on VIA1. + */ + + via1[vIER] = 0x7F; + via1[vIFR] = 0x7F; + via1[vT1LL] = 0; + via1[vT1LH] = 0; + via1[vT1CL] = 0; + via1[vT1CH] = 0; + via1[vT2CL] = 0; + via1[vT2CH] = 0; + via1[vACR] &= 0x3F; + + /* + * SE/30: disable video IRQ + * XXX: testing for SE/30 VBL + */ + + if (macintosh_config->ident == MAC_MODEL_SE30) { + via1[vDirB] |= 0x40; + via1[vBufB] |= 0x40; + } + + /* + * Set the RTC bits to a known state: all lines to outputs and + * RTC disabled (yes that's 0 to enable and 1 to disable). + */ + + via1[vDirB] |= (VIA1B_vRTCEnb | VIA1B_vRTCClk | VIA1B_vRTCData); + via1[vBufB] |= (VIA1B_vRTCEnb | VIA1B_vRTCClk); + + /* Everything below this point is VIA2/RBV only... */ + + if (oss_present) return; + +#if 1 + /* Some machines support an alternate IRQ mapping that spreads */ + /* Ethernet and Sound out to their own autolevel IRQs and moves */ + /* VIA1 to level 6. A/UX uses this mapping and we do too. Note */ + /* that the IIfx emulates this alternate mapping using the OSS. */ + + switch(macintosh_config->ident) { + case MAC_MODEL_C610: + case MAC_MODEL_Q610: + case MAC_MODEL_C650: + case MAC_MODEL_Q650: + case MAC_MODEL_Q700: + case MAC_MODEL_Q800: + case MAC_MODEL_Q900: + case MAC_MODEL_Q950: + via_alt_mapping = 1; + via1[vDirB] |= 0x40; + via1[vBufB] &= ~0x40; + break; + default: + via_alt_mapping = 0; + break; + } +#else + /* The alernate IRQ mapping seems to just not work. Anyone with a */ + /* supported machine is welcome to take a stab at fixing it. It */ + /* _should_ work on the following Quadras: 610,650,700,800,900,950 */ + /* - 1999-06-12 (jmt) */ + + via_alt_mapping = 0; +#endif + + /* + * Now initialize VIA2. For RBV we just kill all interrupts; + * for a regular VIA we also reset the timers and stuff. + */ + + via2[gIER] = 0x7F; + via2[gIFR] = 0x7F | rbv_clear; + if (!rbv_present) { + via2[vT1LL] = 0; + via2[vT1LH] = 0; + via2[vT1CL] = 0; + via2[vT1CH] = 0; + via2[vT2CL] = 0; + via2[vT2CH] = 0; + via2[vACR] &= 0x3F; + } +} + +/* + * Start the 100 Hz clock + */ + +void __init via_init_clock(void (*func)(int, void *, struct pt_regs *)) +{ + via1[vACR] |= 0x40; + via1[vT1LL] = MAC_CLOCK_LOW; + via1[vT1LH] = MAC_CLOCK_HIGH; + via1[vT1CL] = MAC_CLOCK_LOW; + via1[vT1CH] = MAC_CLOCK_HIGH; + + request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func); +} + +/* + * Register the interrupt dispatchers for VIA or RBV machines only. + */ + +void __init via_register_interrupts(void) +{ + if (via_alt_mapping) { + request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "Software IRQ", (void *) via1); + request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "VIA1 Dispatch", (void *) via1); + } else { + request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "VIA1 Dispatch", (void *) via1); +#if 0 /* interferes with serial on some machines */ + if (!psc_present) { + request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK, + "Off Switch", mac_bang); + } +#endif + } + request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "VIA2 Dispatch", (void *) via2); + if (!psc_present) { + request_irq(IRQ_AUTO_4, mac_SCC_handler, IRQ_FLG_LOCK, + "SCC Dispatch", mac_SCC_handler); + } + request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "Nubus Dispatch", (void *) via2); +} + +/* + * Debugging dump, used in various places to see what's going on. + */ + +void via_debug_dump(void) +{ + printk("VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n", + (uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]); + printk(" PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n", + (uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]); + if (oss_present) { + printk("VIA2: \n"); + } else if (rbv_present) { + printk("VIA2: IFR = 0x%02X IER = 0x%02X\n", + (uint) via2[rIFR], (uint) via2[rIER]); + printk(" SIFR = 0x%02X SIER = 0x%02X\n", + (uint) via2[rSIFR], (uint) via2[rSIER]); + } else { + printk("VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n", + (uint) via2[vDirA], (uint) via2[vDirB], + (uint) via2[vACR]); + printk(" PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n", + (uint) via2[vPCR], + (uint) via2[vIFR], (uint) via2[vIER]); + } +} + +/* + * This is always executed with interrupts disabled. + * + * TBI: get time offset between scheduling timer ticks + */ + +unsigned long mac_gettimeoffset (void) +{ + unsigned long ticks, offset = 0; + + /* read VIA1 timer 2 current value */ + ticks = via1[vT1CL] | (via1[vT1CH] << 8); + /* The probability of underflow is less than 2% */ + if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50) + /* Check for pending timer interrupt in VIA1 IFR */ + if (via1[vIFR] & 0x40) offset = TICK_SIZE; + + ticks = MAC_CLOCK_TICK - ticks; + ticks = ticks * 10000L / MAC_CLOCK_TICK; + + return ticks + offset; +} + +/* + * Flush the L2 cache on Macs that have it by flipping + * the system into 24-bit mode for an instant. + */ + +void via_flush_cache(void) +{ + via2[gBufB] &= ~VIA2B_vMode32; + via2[gBufB] |= VIA2B_vMode32; +} + +/* + * Return the status of the L2 cache on a IIci + */ + +int via_get_cache_disable(void) +{ + /* Safeguard against being called accidentally */ + if (!via2) { + printk(KERN_ERR "via_get_cache_disable called on a non-VIA machine!\n"); + return 1; + } + + return (int) via2[gBufB] & VIA2B_vCDis; +} + +/* + * VIA-based power switch, for machines that support it. + */ + +void via_poweroff(void) +{ + if (rbv_present) { + via2[rBufB] &= ~0x04; + } else { + /* Direction of vDirB is output */ + via2[vDirB] |= 0x04; + /* Send a value of 0 on that line */ + via2[vBufB] &= ~0x04; + /* Otherwise it prints "It is now.." then shuts off */ + mdelay(1000); + } + + /* We should never make it this far... */ + printk ("It is now safe to switch off your machine.\n"); + while(1); +} + +/* + * Initialize VIA2 for Nubus access + */ + +void __init via_nubus_init(void) +{ + nubus_active = 0; + + /* unlock nubus transactions */ + + if (!rbv_present) { + /* set the line to be an output on non-RBV machines */ + via2[vDirB] |= 0x02; + } + via2[gBufB] |= 0x02; + + /* disable nubus slot interrupts. */ + if (rbv_present) { + via2[rSIER] = 0x7F; /* like VIA; bit 7=clr,set */ + } else { + via2[vBufA] = 0xFF; /* active low irqs, force high */ + via2[vDirA] = 0xFF; /* ddr to output. */ + } +} + +/* + * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's + * via6522.c :-), disable/pending masks added. + * + * The new interrupt architecture in macints.c takes care of a lot of the + * gruntwork for us, including tallying the interrupts and calling the + * handlers on the linked list. All we need to do here is basically generate + * the machspec interrupt number after clearing the interrupt. + */ + +void via1_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int irq_bit, i; + unsigned char events, mask; + + irq -= VEC_SPUR; + + mask = via1[vIER] & 0x7F; + if (!(events = via1[vIFR] & mask)) return; + + for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) + if (events & irq_bit) { + via1[vIER] = irq_bit; + mac_do_irq_list(VIA1_SOURCE_BASE + i, regs); + via1[vIFR] = irq_bit; + via1[vIER] = irq_bit | 0x80; + } + + if (!oss_present) { + /* This (still) seems to be necessary to get IDE + working. However, if you enable VBL interrupts, + you're screwed... */ + /* FIXME: should we check the SLOTIRQ bit before + pulling this stunt? */ + /* No, it won't be set. that's why we're doing this. */ + via_irq_disable(IRQ_MAC_NUBUS); + via_irq_clear(IRQ_MAC_NUBUS); + mac_do_irq_list(IRQ_MAC_NUBUS, regs); + via_irq_enable(IRQ_MAC_NUBUS); + } +} + +void via2_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int irq_bit, i; + unsigned char events, mask; + + irq -= VEC_SPUR; + + mask = via2[gIER] & 0x7F; + if (!(events = via2[gIFR] & mask)) return; + + for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) + if (events & irq_bit) { + via2[gIER] = irq_bit; + mac_do_irq_list(VIA2_SOURCE_BASE + i, regs); + via2[gIFR] = irq_bit | rbv_clear; + via2[gIER] = irq_bit | 0x80; + } +} + +/* + * Dispatch Nubus interrupts. We are called as a secondary dispatch by the + * VIA2 dispatcher as a fast interrupt handler. + */ + +void via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int irq_bit, i; + unsigned char events; + + if (!(events = ~via2[gBufA] & nubus_active)) return; + + for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) { + if (events & irq_bit) { + via_irq_disable(NUBUS_SOURCE_BASE + i); + mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs); + via_irq_enable(NUBUS_SOURCE_BASE + i); + } + } +} + +void via_irq_enable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int irq_bit = 1 << irq_idx; + +#ifdef DEBUG_IRQUSE + printk("via_irq_enable(%d)\n", irq); +#endif + + if (irq_src == 1) { + via1[vIER] = irq_bit | 0x80; + } else if (irq_src == 2) { + /* + * Set vPCR for SCSI interrupts (but not on RBV) + */ + if ((irq_idx == 0) && !rbv_present) { + if (macintosh_config->scsi_type == MAC_SCSI_OLD) { + /* CB2 (IRQ) indep. input, positive edge */ + /* CA2 (DRQ) indep. input, positive edge */ + via2[vPCR] = 0x66; + } else { + /* CB2 (IRQ) indep. input, negative edge */ + /* CA2 (DRQ) indep. input, negative edge */ + via2[vPCR] = 0x22; + } + } + via2[gIER] = irq_bit | 0x80; + } else if (irq_src == 7) { + if (rbv_present) { + /* enable the slot interrupt. SIER works like IER. */ + via2[rSIER] = IER_SET_BIT(irq_idx); + } else { + /* Make sure the bit is an input, to enable the irq */ + via2[vDirA] &= ~irq_bit; + } + nubus_active |= irq_bit; + } +} + +void via_irq_disable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int irq_bit = 1 << irq_idx; + +#ifdef DEBUG_IRQUSE + printk("via_irq_disable(%d)\n", irq); +#endif + + if (irq_src == 1) { + via1[vIER] = irq_bit; + } else if (irq_src == 2) { + via2[gIER] = irq_bit; + } else if (irq_src == 7) { + if (rbv_present) { + /* disable the slot interrupt. SIER works like IER. */ + via2[rSIER] = IER_CLR_BIT(irq_idx); + } else { + /* disable the nubus irq by changing dir to output */ + via2[vDirA] |= irq_bit; + } + nubus_active &= ~irq_bit; + } +} + +void via_irq_clear(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int irq_bit = 1 << irq_idx; + + if (irq_src == 1) { + via1[vIFR] = irq_bit; + } else if (irq_src == 2) { + via2[gIFR] = irq_bit | rbv_clear; + } else if (irq_src == 7) { + /* FIXME: hmm.. */ + } +} + +/* + * Returns nonzero if an interrupt is pending on the given + * VIA/IRQ combination. + */ + +int via_irq_pending(int irq) +{ + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int irq_bit = 1 << irq_idx; + + if (irq_src == 1) { + return via1[vIFR] & irq_bit; + } else if (irq_src == 2) { + return via2[gIFR] & irq_bit; + } else if (irq_src == 7) { + return ~via2[gBufA] & irq_bit; + } + return 0; +} + +void via_scsi_clear(void) +{ + volatile unsigned char deep_magic; + +#ifdef DEBUG_IRQUSE + printk("via_scsi_clear()\n"); +#endif + + /* We handle this in oss.c , but this gets called in mac_scsinew.c */ + if(oss_present) return; + + if (rbv_present) { + via2[rIFR] = (1<<3) | (1<<0) | rbv_clear; + deep_magic = via2[rBufB]; + } else { + deep_magic = via2[vBufB]; + } + mac_enable_irq(IRQ_MAC_SCSI); +} + +/* + * PRAM/RTC access routines + * + * Must be called with interrupts disabled and + * the RTC should be enabled. + */ + +static __u8 via_pram_readbyte(void) +{ + int i,reg; + __u8 data; + + reg = via1[vBufB] & ~VIA1B_vRTCClk; + + /* Set the RTC data line to be an input. */ + + via1[vDirB] &= ~VIA1B_vRTCData; + + /* The bits of the byte come out in MSB order */ + + data = 0; + for (i = 0 ; i < 8 ; i++) { + via1[vBufB] = reg; + via1[vBufB] = reg | VIA1B_vRTCClk; + data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData); + } + + /* Return RTC data line to output state */ + + via1[vDirB] |= VIA1B_vRTCData; + + return data; +} + +static void via_pram_writebyte(__u8 data) +{ + int i,reg,bit; + + reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData); + + /* The bits of the byte go in in MSB order */ + + for (i = 0 ; i < 8 ; i++) { + bit = data & 0x80? 1 : 0; + data <<= 1; + via1[vBufB] = reg | bit; + via1[vBufB] = reg | bit | VIA1B_vRTCClk; + } +} + +/* + * Execute a PRAM/RTC command. For read commands + * data should point to a one-byte buffer for the + * resulting data. For write commands it should point + * to the data byte to for the command. + * + * This function disables all interrupts while running. + */ + +void via_pram_command(int command, __u8 *data) +{ + unsigned long cpu_flags; + int is_read; + + save_flags(cpu_flags); + cli(); + + /* Enable the RTC and make sure the strobe line is high */ + + via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb; + + if (command & 0xFF00) { /* extended (two-byte) command */ + via_pram_writebyte((command & 0xFF00) >> 8); + via_pram_writebyte(command & 0xFF); + is_read = command & 0x8000; + } else { /* one-byte command */ + via_pram_writebyte(command); + is_read = command & 0x80; + } + if (is_read) { + *data = via_pram_readbyte(); + } else { + via_pram_writebyte(*data); + } + + /* All done, disable the RTC */ + + via1[vBufB] |= VIA1B_vRTCEnb; + + restore_flags(cpu_flags); +} + +/* + * Return the current time in seconds since January 1, 1904. + * + * This only works on machines with the VIA-based PRAM/RTC, which + * is basically any machine with Mac II-style ADB. + */ + +__u32 via_read_time(void) +{ + union { + __u8 cdata[4]; + __u32 idata; + } result, last_result; + int ct; + + /* + * The NetBSD guys say to loop until you get the same reading + * twice in a row. + */ + + ct = 0; + do { + if (++ct > 10) { + printk("via_read_time: couldn't get valid time, " + "last read = 0x%08X and 0x%08X\n", last_result.idata, + result.idata); + break; + } + + last_result.idata = result.idata; + result.idata = 0; + + via_pram_command(0x81, &result.cdata[3]); + via_pram_command(0x85, &result.cdata[2]); + via_pram_command(0x89, &result.cdata[1]); + via_pram_command(0x8D, &result.cdata[0]); + } while (result.idata != last_result.idata); + + return result.idata; +} + +/* + * Set the current time to a number of seconds since January 1, 1904. + * + * This only works on machines with the VIA-based PRAM/RTC, which + * is basically any machine with Mac II-style ADB. + */ + +void via_write_time(__u32 time) +{ + union { + __u8 cdata[4]; + __u32 idata; + } data; + __u8 temp; + + /* Clear the write protect bit */ + + temp = 0x55; + via_pram_command(0x35, &temp); + + data.idata = time; + via_pram_command(0x01, &data.cdata[3]); + via_pram_command(0x05, &data.cdata[2]); + via_pram_command(0x09, &data.cdata[1]); + via_pram_command(0x0D, &data.cdata[0]); + + /* Set the write protect bit */ + + temp = 0xD5; + via_pram_command(0x35, &temp); +} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/via6522.c linux/arch/m68k/mac/via6522.c --- v2.3.16/linux/arch/m68k/mac/via6522.c Thu Dec 17 09:06:29 1998 +++ linux/arch/m68k/mac/via6522.c Wed Dec 31 16:00:00 1969 @@ -1,419 +0,0 @@ -/* - * 6522 Versatile Interface Adapter (VIA) - * - * There are two of these on the Mac II. Some IRQ's are vectored - * via them as are assorted bits and bobs - eg rtc, adb. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include "via6522.h" -#include - -volatile unsigned char *via1=(unsigned char *)VIABASE; -volatile unsigned char *via2=(unsigned char *)VIABASE2; -volatile unsigned char *psc=(unsigned char *)PSCBASE; - -volatile long *via_memory_bogon=(long *)&via_memory_bogon; - -unsigned char via1_clock, via1_datab; - -static int rbv=0; -static int oss=0; - -extern void adb_interrupt(int slot, void *via, struct pt_regs *regs); - -/* - * hardware reset vector - */ -static void (*rom_reset)(void); - -/* - * Timer defs. - */ -#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */ -#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) -#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) - - -void via_configure_base(void) -{ - - switch(macintosh_config->via_type) - { - /* - * CI, SI, VX, LC - */ - case MAC_VIA_IIci: - via1=(void *)0x50F00000; - via2=(void *)0x50F26000; - rbv=1; - if (macintosh_config->ident == MAC_MODEL_IIFX) { - via2=(void *)0x50F1A000; - oss=1; - } - break; - /* - * Quadra and early MacIIs agree on the VIA locations - */ - case MAC_VIA_QUADRA: - case MAC_VIA_II: - via1=(void *)0x50F00000; - via2=(void *)0x50F02000; - break; - default: - } -} - - -void via_init_clock(void (*func)(int, void *, struct pt_regs *)) -{ - unsigned char c; - - via1_clock=via_read(via1, vACR); - via1_datab=via_read(via1, vBufB); - - /* - * Tell what MacOS left us with - */ - - printk("via_init: boot via1 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n", - (int)via1_clock, (int)via_read(via1, vPCR), - (int)via_read(via1, vBufA), (int)via_read(via1, vDirA), - (int)via_read(via1, vBufB), (int)via_read(via1, vDirB)); - - if (rbv == 0) - printk("via_init: boot via2 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n", - (int)via_read(via2, vACR), (int)via_read(via2, vPCR), - (int)via_read(via2, vBufA), (int)via_read(via2, vDirA), - (int)via_read(via2, vBufB), (int)via_read(via2, vDirB)); - - /* - * Shut it down - */ - - via_write(via1,vIER, 0x7F); - - /* - * Kill the timers - */ - - via_write(via1,vT1LL,0); - via_write(via1,vT1LH,0); - via_write(via1,vT1CL,0); - via_write(via1,vT1CH,0); - via_write(via1,vT2CL,0); - via_write(via1,vT2CH,0); - - /* - * Now do via2 - */ - - if(rbv==0) - { - via_write(via2,vT1LL,0); - via_write(via2,vT1LH,0); - via_write(via2,vT1CL,0); - via_write(via2,vT1CH,0); - via_write(via2,vT2CL,0); - via_write(via2,vT2CH,0); - via_write(via2,vIER, 0x7F); - } - else if (oss==0) - { - /* - * Init the RBV chip a bit - */ - - via_write(via2, rIER,0x7F); - } - - /* - * Disable the timer latches - */ - - c=via_read(via1,vACR); - via_write(via1,vACR,c&0x3F); - - if(rbv==0) - { - c=via_read(via2,vACR); - via_write(via2,vACR,c&0x3F); - } - - /* - * Now start the clock - we want 100Hz - */ - - via_write(via1,vACR,via_read(via1,vACR)|0x40); - - via_write(via1,vT1LL, MAC_CLOCK_LOW); - via_write(via1,vT1LH, MAC_CLOCK_HIGH); - via_write(via1,vT1CL, MAC_CLOCK_LOW); - via_write(via1,vT1CH, MAC_CLOCK_HIGH); - - /* - * And enable its interrupt - */ - - request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func); - - /* - * SE/30: disable video int. - * XXX: testing for SE/30 VBL - */ - - if (macintosh_config->ident == MAC_MODEL_SE30) { - c = via_read(via1, vBufB); - via_write(via1, vBufB, c|(0x40)); - c = via_read(via1, vDirB); - via_write(via1, vDirB, c|(0x40)); - } - -#if 0 /* gone to mac_init_IRQ */ - /* - * Set vPCR for SCSI interrupts. - * - * That is: CA1 negative edge int., CA2 indep., positive edge int.; - * CB1 negative edge int., CB2 indep., positive edge int.. - */ - via_write(via2,vPCR, 0x66); -#endif - -} - -/* - * TBI: get time offset between scheduling timer ticks - */ -#define TICK_SIZE 10000 - -/* This is always executed with interrupts disabled. */ - -unsigned long mac_gettimeoffset (void) -{ - unsigned long ticks, offset = 0; - - /* read VIA1 timer 2 current value */ - ticks = via_read(via1, vT1CL) + (via_read(via1, vT1CH)<<8); - /* The probability of underflow is less than 2% */ - if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50) - /* Check for pending timer interrupt in VIA1 IFR */ - if (via_read(via1, vIFR) & 0x40) - offset = TICK_SIZE; - - ticks = MAC_CLOCK_TICK - ticks; - ticks = ticks * 10000L / MAC_CLOCK_TICK; - - return ticks + offset; -} - -/* - * PSC (AV Macs; level 3-6): initialize interrupt enable registers - */ - -void psc_init(void) -{ - via_write(psc, pIER3, 0x01); - via_write(psc, pIER4, 0x09); - via_write(psc, pIER4, 0x86); - via_write(psc, pIER5, 0x03); - via_write(psc, pIER6, 0x07); -} - -/* - * The power switch - yes it's software! - */ - -void mac_poweroff(void) -{ - - /* - * MAC_ADB_IISI may need to be moved up here if it doesn't actually - * work using the ADB packet method. --David Kilzer - */ - - if (macintosh_config->adb_type == MAC_ADB_II) - { - if(rbv) { - via_write(via2, rBufB, via_read(via2, rBufB)&~0x04); - } else { - /* Direction of vDirB is output */ - via_write(via2,vDirB,via_read(via2,vDirB)|0x04); - /* Send a value of 0 on that line */ - via_write(via2,vBufB,via_read(via2,vBufB)&~0x04); - /* Otherwise it prints "It is now.." then shuts off */ - mdelay(1000); - } - - /* We should never make it this far... */ - printk ("It is now safe to switch off your machine.\n"); - - /* XXX - delay do we need to spin here ? */ - while(1); /* Just in case .. */ - } - - /* - * Initially discovered this technique in the Mach kernel of MkLinux in - * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c. Found equivalent LinuxPPC - * code in arch/ppc/kernel/setup.c, which also has a PMU technique for PowerBooks! - * --David Kilzer - */ - - else if (macintosh_config->adb_type == MAC_ADB_IISI - || macintosh_config->adb_type == MAC_ADB_CUDA) - { - struct adb_request req; - - /* - * Print our "safe" message before we send the request - * just in case the request never returns. - */ - - printk ("It is now safe to switch off your machine.\n"); - - adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN); - - printk ("ADB powerdown request sent.\n"); - for (;;) - { - adb_poll(); - } - } -} - -/* - * Not all Macs support software power down; for the rest, just - * try the ROM reset vector ... - */ -void mac_reset(void) -{ - /* - * MAC_ADB_IISI may need to be moved up here if it doesn't actually - * work using the ADB packet method. --David Kilzer - */ - - if (macintosh_config->adb_type == MAC_ADB_II) - { - unsigned long flags; - unsigned long *reset_hook; - - /* need ROMBASE in booter */ - /* indeed, plus need to MAP THE ROM !! */ - - if (mac_bi_data.rombase == 0) - mac_bi_data.rombase = 0x40800000; - - /* works on some */ - rom_reset = (void *) (mac_bi_data.rombase + 0xa); - -#if 0 - /* testing, doesn't work on SE/30 either */ - reset_hook = (unsigned long *) (mac_bi_data.rombase + 0x4); - printk("ROM reset hook: %p\n", *reset_hook); - rom_reset = *reset_hook; -#endif - if (macintosh_config->ident == MAC_MODEL_SE30) { - /* - * MSch: Machines known to crash on ROM reset ... - */ - printk("System halted.\n"); - while(1); - } else { - save_flags(flags); - cli(); - - rom_reset(); - - restore_flags(flags); - } - - /* We never make it this far... it usually panics above. */ - printk ("Restart failed. Please restart manually.\n"); - - /* XXX - delay do we need to spin here ? */ - while(1); /* Just in case .. */ - } - - /* - * Initially discovered this technique in the Mach kernel of MkLinux in - * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c. Found equivalent LinuxPPC - * code in arch/ppc/kernel/setup.c, which also has a PMU technique! - * --David Kilzer - * - * I suspect the MAC_ADB_CUDA code might work with other ADB types of machines - * but have no way to test this myself. --DDK - */ - - else if (macintosh_config->adb_type == MAC_ADB_IISI - || macintosh_config->adb_type == MAC_ADB_CUDA) - { - struct adb_request req; - - adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM); - - printk ("Restart failed. Please restart manually.\n"); - for (;;) - { - adb_poll(); - } - } -} - -/* - * Set up the keyboard - */ - -void via_setup_keyboard(void) -{ -#if 0 /* moved to adb */ - via1_func_tab.vector[2]=adb_interrupt; -#else - request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, "adb interrupt", - adb_interrupt); -#endif -} - -/* - * Floppy hook - */ - -void via1_set_head(int head) -{ - if(head==0) - via_write(via1, vBufA, via_read(via1, vBufA)&~0x20); - else - via_write(via1, vBufA, via_read(via1, vBufA)|0x20); -} - -void nubus_init_via(void) -{ - if (rbv) { - if (oss==0) { - via_write(via2, rBufB, via_read(via2, rBufB)|0x02); - via_write(via2, rIER, 0x82); /* Interrupts on */ - } - } else { - /* Assert the nubus active */ - via_write(via2, vDirB, via_read(via2, vDirB)|0x02); - via_write(via2, vBufB, via_read(via2, vBufB)|0x02); - /* Make the nubus interrupt source register all output (disable) */ - /* via_write(via2, vDirA, 0xFF); */ - via_write(via2, vIER, 0x82); /* Interrupts on */ - } - - printk("nubus_init_via: via1 acr=%X datab=%X pcr=%X\n", - (int)via_read(via1, vACR), (int)via_read(via1, vBufB), - (int)via_read(via1, vPCR)); - - if (rbv==0) - printk("nubus_init_via: via2 acr=%X datab=%X pcr=%X\n", - (int)via_read(via2, vACR), (int)via_read(via2, vBufB), - (int)via_read(via2, vPCR)); -} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/via6522.h linux/arch/m68k/mac/via6522.h --- v2.3.16/linux/arch/m68k/mac/via6522.h Mon Oct 5 13:54:39 1998 +++ linux/arch/m68k/mac/via6522.h Wed Dec 31 16:00:00 1969 @@ -1,131 +0,0 @@ -/* - * 6522 Versatile Interface Adapter (VIA) - * - * There are two of these on the Mac II. Some IRQ's are vectored - * via them as are assorted bits and bobs - eg rtc, adb. The picture - * is a bit incomplete as the Mac documentation doesnt cover this well - */ - -#ifndef _ASM_VIA6522_H_ -#define _ASM_VIA6522_H_ - -#define VIABASE 0x50F00000 -#define VIABASE2 0x50F02000 - -/* - * Not all of these are true post MacII I think - */ - -#define VIA1A_vSccWrReq 0x80 /* SCC write */ -#define VIA1A_vRev8 0x40 /* Revision 8 board ??? */ -#define VIA1A_vHeadSel 0x20 /* Head select for IWM */ -#define VIA1A_vOverlay 0x10 -#define VIA1A_vSync 0x08 -#define VIA1A_vVolume 0x07 /* Audio volume mask */ - -#define VIA1B_vSound 0x80 /* Audio on/off */ -#define VIA1B_vMystery 0x40 -#define VIA1B_vADBS2 0x20 /* ADB state 2 */ -#define VIA1B_vADBS1 0x10 /* ADB state 1 */ -#define VIA1B_vADBInt 0x08 /* ADB interrupt */ -#define VIA1B_vRTCEnb 0x04 /* Real time clock */ -#define VIA1B_vRTCClk 0x02 -#define VIA1B_vRTCData 0x01 - -/* - * VIA2 A register is the interrupt lines raised off the nubus - * slots. - */ - -#define VIA2A_vIRQE 0x20 -#define VIA2A_vIRQD 0x10 -#define VIA2A_vIRQC 0x08 -#define VIA2A_vIRQB 0x04 -#define VIA2A_vIRQA 0x02 -#define VIA2A_vIRQ9 0x01 - -/* - * Register B has the fun stuff in it - */ - -#define VIA2B_vMode32 0x08 /* 24/32bit switch - doubles as cache flush */ -#define VIA2B_vPower 0x04 /* Off switch */ -#define VIA2B_vBusLk 0x02 /* Nubus in use ?? */ -#define VIA2B_vCDis 0x01 /* Cache disable */ - -/* - * The 6522 via is a 2MHz part, and needs a delay. MacOS seems to - * execute MOV (Ax),(Ax) for this... Oh and we can't use udelay - * here... see we need the via to calibrate the udelay loop ... - */ - -extern volatile long *via_memory_bogon; - -extern __inline__ void via_write(volatile unsigned char *via,int reg, int v) -{ - *via_memory_bogon; - *via_memory_bogon; - *via_memory_bogon; - via[reg]=v; -} - -extern __inline__ int via_read(volatile unsigned char *via,int reg) -{ - *via_memory_bogon; - *via_memory_bogon; - *via_memory_bogon; - return (int)via[reg]; -} - -extern volatile unsigned char *via1,*via2; - -/* - * 6522 registers - see databook - */ - -#define vBufB 0x0000 -#define vBufA 0x0200 -#define vDirB 0x0400 -#define vDirA 0x0600 -#define vT1CL 0x0800 -#define vT1CH 0x0a00 -#define vT1LL 0x0c00 -#define vT1LH 0x0e00 -#define vT2CL 0x1000 -#define vT2CH 0x1200 -#define vSR 0x1400 -#define vACR 0x1600 -#define vPCR 0x1800 -#define vIFR 0x1a00 -#define vIER 0x1c00 -#define vANH 0x1e00 /* register A (no shake) */ - -#define rBufB 0x00 -#define rBufA 0x02 -/*#define rIFR 0x03*/ -#define rIFR 0x1A03 -#define rVideo 0x10 -#define rSlot 0x12 -/*#define rIER 0x13*/ -#define rIER 0x1C13 -/* -#define R_rIFR 0x03 -#define R_rIER 0x13 -#define W_rIFR 0x1A03 -#define W_rIER 0x1C13 -*/ -/* - * VIA interrupt - */ - -struct via_irq_tab -{ - void (*vector[8])(int, void *, struct pt_regs *); -}; - -extern void via1_irq(int, void *, struct pt_regs *); -extern void via2_irq(int, void *, struct pt_regs *); - -extern void via_setup_keyboard(void); - -#endif /* _ASM_VIA6522_H_ */ diff -u --recursive --new-file v2.3.16/linux/arch/m68k/math-emu/fp_entry.S linux/arch/m68k/math-emu/fp_entry.S --- v2.3.16/linux/arch/m68k/math-emu/fp_entry.S Tue Aug 17 10:39:02 1999 +++ linux/arch/m68k/math-emu/fp_entry.S Sat Sep 4 13:06:41 1999 @@ -35,7 +35,6 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/m68k/math-emu/fp_util.S linux/arch/m68k/math-emu/fp_util.S --- v2.3.16/linux/arch/m68k/math-emu/fp_util.S Tue Aug 17 10:39:17 1999 +++ linux/arch/m68k/math-emu/fp_util.S Sat Sep 4 13:06:41 1999 @@ -35,8 +35,6 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include - #include "fp_emu.h" /* diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mm/Makefile linux/arch/m68k/mm/Makefile --- v2.3.16/linux/arch/m68k/mm/Makefile Sat Jun 13 13:14:33 1998 +++ linux/arch/m68k/mm/Makefile Sat Sep 4 13:06:41 1999 @@ -8,6 +8,13 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o fault.o memory.o kmap.o extable.o hwtest.o +O_OBJS := init.o fault.o extable.o hwtest.o + +ifndef CONFIG_SUN3 +O_OBJS += kmap.o memory.o motorola.o +else +O_OBJS += sun3mmu.o +endif + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v2.3.16/linux/arch/m68k/mm/init.c Tue Aug 31 17:29:12 1999 +++ linux/arch/m68k/mm/init.c Sat Sep 4 13:06:41 1999 @@ -2,6 +2,9 @@ * linux/arch/m68k/mm/init.c * * Copyright (C) 1995 Hamish Macdonald + * + * Contains common initialization routines, specific init code moved + * to motorola.c and sun3mmu.c */ #include @@ -28,7 +31,10 @@ #include #endif -extern void die_if_kernel(char *,struct pt_regs *,long); +#ifdef CONFIG_SUN3 +void mmu_emu_reserve_pages(unsigned long max_page); +#endif + extern void show_net_buffers(void); int do_check_pgt_cache(int low, int high) @@ -58,7 +64,7 @@ * ZERO_PAGE is a special page that is used for zero-initialized * data and COW. */ -static unsigned long empty_bad_page_table; +unsigned long empty_bad_page_table; pte_t *__bad_pagetable(void) { @@ -66,7 +72,7 @@ return (pte_t *)empty_bad_page_table; } -static unsigned long empty_bad_page; +unsigned long empty_bad_page; pte_t __bad_page(void) { @@ -111,169 +117,6 @@ #endif } -#ifndef mm_cachebits -/* - * Bits to add to page descriptors for "normal" caching mode. - * For 68020/030 this is 0. - * For 68040, this is _PAGE_CACHE040 (cachable, copyback) - */ -unsigned long mm_cachebits = 0; -#endif - -static pte_t * __init kernel_page_table(unsigned long *memavailp) -{ - pte_t *ptablep; - - ptablep = (pte_t *)*memavailp; - *memavailp += PAGE_SIZE; - - clear_page((unsigned long)ptablep); - flush_page_to_ram((unsigned long) ptablep); - flush_tlb_kernel_page((unsigned long) ptablep); - nocache_page ((unsigned long)ptablep); - - return ptablep; -} - -static pmd_t *last_pgtable __initdata = NULL; -static pmd_t *zero_pgtable __initdata = NULL; - -static pmd_t * __init kernel_ptr_table(unsigned long *memavailp) -{ - if (!last_pgtable) { - unsigned long pmd, last; - int i; - - /* Find the last ptr table that was used in head.S and - * reuse the remaining space in that page for further - * ptr tables. - */ - last = (unsigned long)kernel_pg_dir; - for (i = 0; i < PTRS_PER_PGD; i++) { - if (!pgd_present(kernel_pg_dir[i])) - continue; - pmd = pgd_page(kernel_pg_dir[i]); - if (pmd > last) - last = pmd; - } - - last_pgtable = (pmd_t *)last; -#ifdef DEBUG - printk("kernel_ptr_init: %p\n", last_pgtable); -#endif - } - - if (((unsigned long)(last_pgtable + PTRS_PER_PMD) & ~PAGE_MASK) == 0) { - last_pgtable = (pmd_t *)*memavailp; - *memavailp += PAGE_SIZE; - - clear_page((unsigned long)last_pgtable); - flush_page_to_ram((unsigned long)last_pgtable); - flush_tlb_kernel_page((unsigned long)last_pgtable); - nocache_page((unsigned long)last_pgtable); - } else - last_pgtable += PTRS_PER_PMD; - - return last_pgtable; -} - -static unsigned long __init -map_chunk (unsigned long addr, long size, unsigned long *memavailp) -{ -#define PTRTREESIZE (256*1024) -#define ROOTTREESIZE (32*1024*1024) - static unsigned long virtaddr = PAGE_OFFSET; - unsigned long physaddr; - pgd_t *pgd_dir; - pmd_t *pmd_dir; - pte_t *pte_dir; - - physaddr = (addr | m68k_supervisor_cachemode | - _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); - if (CPU_IS_040_OR_060) - physaddr |= _PAGE_GLOBAL040; - - while (size > 0) { -#ifdef DEBUG - if (!(virtaddr & (PTRTREESIZE-1))) - printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK, - virtaddr); -#endif - pgd_dir = pgd_offset_k(virtaddr); - if (virtaddr && CPU_IS_020_OR_030) { - if (!(virtaddr & (ROOTTREESIZE-1)) && - size >= ROOTTREESIZE) { -#ifdef DEBUG - printk ("[very early term]"); -#endif - pgd_val(*pgd_dir) = physaddr; - size -= ROOTTREESIZE; - virtaddr += ROOTTREESIZE; - physaddr += ROOTTREESIZE; - continue; - } - } - if (!pgd_present(*pgd_dir)) { - pmd_dir = kernel_ptr_table(memavailp); -#ifdef DEBUG - printk ("[new pointer %p]", pmd_dir); -#endif - pgd_set(pgd_dir, pmd_dir); - } else - pmd_dir = pmd_offset(pgd_dir, virtaddr); - - if (CPU_IS_020_OR_030) { - if (virtaddr) { -#ifdef DEBUG - printk ("[early term]"); -#endif - pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr; - physaddr += PTRTREESIZE; - } else { - int i; -#ifdef DEBUG - printk ("[zero map]"); -#endif - zero_pgtable = kernel_ptr_table(memavailp); - pte_dir = (pte_t *)zero_pgtable; - pmd_dir->pmd[0] = virt_to_phys(pte_dir) | - _PAGE_TABLE | _PAGE_ACCESSED; - pte_val(*pte_dir++) = 0; - physaddr += PAGE_SIZE; - for (i = 1; i < 64; physaddr += PAGE_SIZE, i++) - pte_val(*pte_dir++) = physaddr; - } - size -= PTRTREESIZE; - virtaddr += PTRTREESIZE; - } else { - if (!pmd_present(*pmd_dir)) { -#ifdef DEBUG - printk ("[new table]"); -#endif - pte_dir = kernel_page_table(memavailp); - pmd_set(pmd_dir, pte_dir); - } - pte_dir = pte_offset(pmd_dir, virtaddr); - - if (virtaddr) { - if (!pte_present(*pte_dir)) - pte_val(*pte_dir) = physaddr; - } else - pte_val(*pte_dir) = 0; - size -= PAGE_SIZE; - virtaddr += PAGE_SIZE; - physaddr += PAGE_SIZE; - } - - } -#ifdef DEBUG - printk("\n"); -#endif - - return virtaddr; -} - -extern unsigned long free_area_init(unsigned long, unsigned long); extern void init_pointer_table(unsigned long ptable); /* References to section boundaries */ @@ -281,87 +124,7 @@ extern char _text, _etext, _edata, __bss_start, _end; extern char __init_begin, __init_end; -/* - * paging_init() continues the virtual memory environment setup which - * was begun by the code in arch/head.S. - */ -unsigned long __init paging_init(unsigned long start_mem, - unsigned long end_mem) -{ - int chunk; - unsigned long mem_avail = 0; - -#ifdef DEBUG - { - extern unsigned long availmem; - printk ("start of paging_init (%p, %lx, %lx, %lx)\n", - kernel_pg_dir, availmem, start_mem, end_mem); - } -#endif - - /* Fix the cache mode in the page descriptors for the 680[46]0. */ - if (CPU_IS_040_OR_060) { - int i; -#ifndef mm_cachebits - mm_cachebits = _PAGE_CACHE040; -#endif - for (i = 0; i < 16; i++) - pgprot_val(protection_map[i]) |= _PAGE_CACHE040; - } - /* Fix the PAGE_NONE value. */ - if (CPU_IS_040_OR_060) { - /* On the 680[46]0 we can use the _PAGE_SUPER bit. */ - pgprot_val(protection_map[0]) |= _PAGE_SUPER; - pgprot_val(protection_map[VM_SHARED]) |= _PAGE_SUPER; - } else { - /* Otherwise we must fake it. */ - pgprot_val(protection_map[0]) &= ~_PAGE_PRESENT; - pgprot_val(protection_map[0]) |= _PAGE_FAKE_SUPER; - pgprot_val(protection_map[VM_SHARED]) &= ~_PAGE_PRESENT; - pgprot_val(protection_map[VM_SHARED]) |= _PAGE_FAKE_SUPER; - } - - /* - * Map the physical memory available into the kernel virtual - * address space. It may allocate some memory for page - * tables and thus modify availmem. - */ - - for (chunk = 0; chunk < m68k_num_memory; chunk++) { - mem_avail = map_chunk (m68k_memory[chunk].addr, - m68k_memory[chunk].size, &start_mem); - - } - - flush_tlb_all(); -#ifdef DEBUG - printk ("memory available is %ldKB\n", mem_avail >> 10); - printk ("start_mem is %#lx\nvirtual_end is %#lx\n", - start_mem, end_mem); -#endif - - /* - * initialize the bad page table and bad page to point - * to a couple of allocated pages - */ - empty_bad_page_table = start_mem; - start_mem += PAGE_SIZE; - empty_bad_page = start_mem; - start_mem += PAGE_SIZE; - empty_zero_page = start_mem; - start_mem += PAGE_SIZE; - memset((void *)empty_zero_page, 0, PAGE_SIZE); - - /* - * Set up SFC/DFC registers (user data space) - */ - set_fs (USER_DS); - -#ifdef DEBUG - printk ("before free_area_init\n"); -#endif - return PAGE_ALIGN(free_area_init(start_mem, end_mem)); -} +extern pmd_t *zero_pgtable; void __init mem_init(unsigned long start_mem, unsigned long end_mem) { @@ -386,18 +149,22 @@ atari_stram_reserve_pages( start_mem ); #endif +#ifdef CONFIG_SUN3 + /* reserve rom pages */ + mmu_emu_reserve_pages(max_mapnr); +#endif + for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) { +#ifndef CONFIG_SUN3 if (virt_to_phys ((void *)tmp) >= mach_max_dma_address) clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); +#endif if (PageReserved(mem_map+MAP_NR(tmp))) { if (tmp >= (unsigned long)&_text - && tmp < (unsigned long)&_edata) { - if (tmp < (unsigned long) &_etext) - codepages++; - else - datapages++; - } else if (tmp >= (unsigned long) &__init_begin - && tmp < (unsigned long) &__init_end) + && tmp < (unsigned long)&_etext) + codepages++; + else if (tmp >= (unsigned long) &__init_begin + && tmp < (unsigned long) &__init_end) initpages++; else datapages++; @@ -410,7 +177,8 @@ #endif free_page(tmp); } - + +#ifndef CONFIG_SUN3 /* insert pointer tables allocated so far into the tablelist */ init_pointer_table((unsigned long)kernel_pg_dir); for (i = 0; i < PTRS_PER_PGD; i++) { @@ -421,6 +189,7 @@ /* insert also pointer table that we used to unmap the zero page */ if (zero_pgtable) init_pointer_table((unsigned long)zero_pgtable); +#endif printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), @@ -428,18 +197,6 @@ codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10)); -} - -void free_initmem(void) -{ - unsigned long addr; - - addr = (unsigned long)&__init_begin; - for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - set_page_count(mem_map+MAP_NR(addr), 1); - free_page(addr); - } } void si_meminfo(struct sysinfo *val) diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c --- v2.3.16/linux/arch/m68k/mm/memory.c Tue Aug 31 17:29:12 1999 +++ linux/arch/m68k/mm/memory.c Sat Sep 4 13:06:41 1999 @@ -385,7 +385,7 @@ } #ifndef CONFIG_SINGLE_MEMORY_CHUNK -void *mm_ptov (unsigned long paddr) +unsigned long mm_ptov (unsigned long paddr) { int i = 0; unsigned long poff, voff = PAGE_OFFSET; @@ -396,7 +396,7 @@ #ifdef DEBUGPV printk ("PTOV(%lx)=%lx\n", paddr, poff + voff); #endif - return (void *)(poff + voff); + return poff + voff; } voff += m68k_memory[i].size; } while (++i < m68k_num_memory); @@ -429,9 +429,9 @@ * to the ZTWO_VADDR range */ if (MACH_IS_AMIGA && paddr < 16*1024*1024) - return (void *)ZTWO_VADDR(paddr); + return ZTWO_VADDR(paddr); #endif - return (void *)-1; + return -1; } #endif @@ -491,14 +491,7 @@ * this?). So we have to push first and then additionally to invalidate. */ -#ifdef CONFIG_M68K_L2_CACHE -/* - * Jes was worried about performance (urhh ???) so its optional - */ - -void (*mach_l2_flush)(int) = NULL; -#endif - + /* * cache_clear() semantics: Clear any cache entries for the area in question, * without writing back dirty entries first. This is useful if the data will diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mm/motorola.c linux/arch/m68k/mm/motorola.c --- v2.3.16/linux/arch/m68k/mm/motorola.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mm/motorola.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,299 @@ +/* + * linux/arch/m68k/motorola.c + * + * Routines specific to the Motorola MMU, originally from: + * linux/arch/m68k/init.c + * which are Copyright (C) 1995 Hamish Macdonald + * + * Moved 8/20/1999 Sam Creasey + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_RAM +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_ATARI +#include +#endif + +#undef DEBUG + +#ifndef mm_cachebits +/* + * Bits to add to page descriptors for "normal" caching mode. + * For 68020/030 this is 0. + * For 68040, this is _PAGE_CACHE040 (cachable, copyback) + */ +unsigned long mm_cachebits = 0; +#endif + +static pte_t * __init kernel_page_table(unsigned long *memavailp) +{ + pte_t *ptablep; + + ptablep = (pte_t *)*memavailp; + *memavailp += PAGE_SIZE; + + clear_page((unsigned long)ptablep); + flush_page_to_ram((unsigned long) ptablep); + flush_tlb_kernel_page((unsigned long) ptablep); + nocache_page ((unsigned long)ptablep); + + return ptablep; +} + +static pmd_t *last_pgtable __initdata = NULL; +pmd_t *zero_pgtable __initdata = NULL; + +static pmd_t * __init kernel_ptr_table(unsigned long *memavailp) +{ + if (!last_pgtable) { + unsigned long pmd, last; + int i; + + /* Find the last ptr table that was used in head.S and + * reuse the remaining space in that page for further + * ptr tables. + */ + last = (unsigned long)kernel_pg_dir; + for (i = 0; i < PTRS_PER_PGD; i++) { + if (!pgd_present(kernel_pg_dir[i])) + continue; + pmd = pgd_page(kernel_pg_dir[i]); + if (pmd > last) + last = pmd; + } + + last_pgtable = (pmd_t *)last; +#ifdef DEBUG + printk("kernel_ptr_init: %p\n", last_pgtable); +#endif + } + + if (((unsigned long)(last_pgtable + PTRS_PER_PMD) & ~PAGE_MASK) == 0) { + last_pgtable = (pmd_t *)*memavailp; + *memavailp += PAGE_SIZE; + + clear_page((unsigned long)last_pgtable); + flush_page_to_ram((unsigned long)last_pgtable); + flush_tlb_kernel_page((unsigned long)last_pgtable); + nocache_page((unsigned long)last_pgtable); + } else + last_pgtable += PTRS_PER_PMD; + + return last_pgtable; +} + +static unsigned long __init +map_chunk (unsigned long addr, long size, unsigned long *memavailp) +{ +#define PTRTREESIZE (256*1024) +#define ROOTTREESIZE (32*1024*1024) + static unsigned long virtaddr = PAGE_OFFSET; + unsigned long physaddr; + pgd_t *pgd_dir; + pmd_t *pmd_dir; + pte_t *pte_dir; + + physaddr = (addr | m68k_supervisor_cachemode | + _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); + if (CPU_IS_040_OR_060) + physaddr |= _PAGE_GLOBAL040; + + while (size > 0) { +#ifdef DEBUG + if (!(virtaddr & (PTRTREESIZE-1))) + printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK, + virtaddr); +#endif + pgd_dir = pgd_offset_k(virtaddr); + if (virtaddr && CPU_IS_020_OR_030) { + if (!(virtaddr & (ROOTTREESIZE-1)) && + size >= ROOTTREESIZE) { +#ifdef DEBUG + printk ("[very early term]"); +#endif + pgd_val(*pgd_dir) = physaddr; + size -= ROOTTREESIZE; + virtaddr += ROOTTREESIZE; + physaddr += ROOTTREESIZE; + continue; + } + } + if (!pgd_present(*pgd_dir)) { + pmd_dir = kernel_ptr_table(memavailp); +#ifdef DEBUG + printk ("[new pointer %p]", pmd_dir); +#endif + pgd_set(pgd_dir, pmd_dir); + } else + pmd_dir = pmd_offset(pgd_dir, virtaddr); + + if (CPU_IS_020_OR_030) { + if (virtaddr) { +#ifdef DEBUG + printk ("[early term]"); +#endif + pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr; + physaddr += PTRTREESIZE; + } else { + int i; +#ifdef DEBUG + printk ("[zero map]"); +#endif + zero_pgtable = kernel_ptr_table(memavailp); + pte_dir = (pte_t *)zero_pgtable; + pmd_dir->pmd[0] = virt_to_phys(pte_dir) | + _PAGE_TABLE | _PAGE_ACCESSED; + pte_val(*pte_dir++) = 0; + physaddr += PAGE_SIZE; + for (i = 1; i < 64; physaddr += PAGE_SIZE, i++) + pte_val(*pte_dir++) = physaddr; + } + size -= PTRTREESIZE; + virtaddr += PTRTREESIZE; + } else { + if (!pmd_present(*pmd_dir)) { +#ifdef DEBUG + printk ("[new table]"); +#endif + pte_dir = kernel_page_table(memavailp); + pmd_set(pmd_dir, pte_dir); + } + pte_dir = pte_offset(pmd_dir, virtaddr); + + if (virtaddr) { + if (!pte_present(*pte_dir)) + pte_val(*pte_dir) = physaddr; + } else + pte_val(*pte_dir) = 0; + size -= PAGE_SIZE; + virtaddr += PAGE_SIZE; + physaddr += PAGE_SIZE; + } + + } +#ifdef DEBUG + printk("\n"); +#endif + + return virtaddr; +} + +extern unsigned long free_area_init(unsigned long, unsigned long); +extern unsigned long empty_bad_page_table; +extern unsigned long empty_bad_page; + +/* + * paging_init() continues the virtual memory environment setup which + * was begun by the code in arch/head.S. + */ +unsigned long __init paging_init(unsigned long start_mem, + unsigned long end_mem) +{ + int chunk; + unsigned long mem_avail = 0; + +#ifdef DEBUG + { + extern unsigned long availmem; + printk ("start of paging_init (%p, %lx, %lx, %lx)\n", + kernel_pg_dir, availmem, start_mem, end_mem); + } +#endif + + /* Fix the cache mode in the page descriptors for the 680[46]0. */ + if (CPU_IS_040_OR_060) { + int i; +#ifndef mm_cachebits + mm_cachebits = _PAGE_CACHE040; +#endif + for (i = 0; i < 16; i++) + pgprot_val(protection_map[i]) |= _PAGE_CACHE040; + } + /* Fix the PAGE_NONE value. */ + if (CPU_IS_040_OR_060) { + /* On the 680[46]0 we can use the _PAGE_SUPER bit. */ + pgprot_val(protection_map[0]) |= _PAGE_SUPER; + pgprot_val(protection_map[VM_SHARED]) |= _PAGE_SUPER; + } else { + /* Otherwise we must fake it. */ + pgprot_val(protection_map[0]) &= ~_PAGE_PRESENT; + pgprot_val(protection_map[0]) |= _PAGE_FAKE_SUPER; + pgprot_val(protection_map[VM_SHARED]) &= ~_PAGE_PRESENT; + pgprot_val(protection_map[VM_SHARED]) |= _PAGE_FAKE_SUPER; + } + + /* + * Map the physical memory available into the kernel virtual + * address space. It may allocate some memory for page + * tables and thus modify availmem. + */ + + for (chunk = 0; chunk < m68k_num_memory; chunk++) { + mem_avail = map_chunk (m68k_memory[chunk].addr, + m68k_memory[chunk].size, &start_mem); + + } + + flush_tlb_all(); +#ifdef DEBUG + printk ("memory available is %ldKB\n", mem_avail >> 10); + printk ("start_mem is %#lx\nvirtual_end is %#lx\n", + start_mem, end_mem); +#endif + + /* + * initialize the bad page table and bad page to point + * to a couple of allocated pages + */ + empty_bad_page_table = start_mem; + start_mem += PAGE_SIZE; + empty_bad_page = start_mem; + start_mem += PAGE_SIZE; + empty_zero_page = start_mem; + start_mem += PAGE_SIZE; + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + /* + * Set up SFC/DFC registers (user data space) + */ + set_fs (USER_DS); + +#ifdef DEBUG + printk ("before free_area_init\n"); +#endif + return PAGE_ALIGN(free_area_init(start_mem, end_mem)); +} + +extern char __init_begin, __init_end; + +void free_initmem(void) +{ + unsigned long addr; + + addr = (unsigned long)&__init_begin; + for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) { + mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); + set_page_count(mem_map+MAP_NR(addr), 1); + free_page(addr); + } +} + + diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mm/sun3mmu.c linux/arch/m68k/mm/sun3mmu.c --- v2.3.16/linux/arch/m68k/mm/sun3mmu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mm/sun3mmu.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,98 @@ +/* + * linux/arch/m68k/mm/sun3mmu.c + * + * Implementations of mm routines specific to the sun3 MMU. + * + * Moved here 8/20/1999 Sam Creasey + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_RAM +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +extern void mmu_emu_init (void); + +extern unsigned long free_area_init(unsigned long, unsigned long); + +const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; + +extern unsigned long empty_bad_page_table; +extern unsigned long empty_bad_page; + +void free_initmem(void) +{ +} +/* For the sun3 we try to follow the i386 paging_init() more closely */ +/* start_mem and end_mem have PAGE_OFFSET added already */ +/* now sets up tables using sun3 PTEs rather than i386 as before. --m */ +unsigned long __init paging_init(unsigned long start_mem, + unsigned long end_mem) +{ + pgd_t * pg_dir; + pte_t * pg_table; + int i; + unsigned long address; + +#ifdef TEST_VERIFY_AREA + wp_works_ok = 0; +#endif + start_mem = PAGE_ALIGN(start_mem); + empty_bad_page_table = start_mem; + start_mem += PAGE_SIZE; + empty_bad_page = start_mem; + start_mem += PAGE_SIZE; + empty_zero_page = start_mem; + start_mem += PAGE_SIZE; + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + address = PAGE_OFFSET; + pg_dir = swapper_pg_dir; + memset (swapper_pg_dir, 0, sizeof (swapper_pg_dir)); + memset (kernel_pg_dir, 0, sizeof (kernel_pg_dir)); + + /* Map whole memory from PAGE_OFFSET (0x0E000000) */ + pg_dir += PAGE_OFFSET >> PGDIR_SHIFT; + + while (address < end_mem) { + pg_table = (pte_t *) __pa (start_mem); + start_mem += PTRS_PER_PTE * sizeof (pte_t); + pgd_val(*pg_dir) = (unsigned long) pg_table; + pg_dir++; + + /* now change pg_table to kernel virtual addresses */ + pg_table = (pte_t *) __va ((unsigned long) pg_table); + for (i=0; i= end_mem) + pte_val (pte) = 0; + set_pte (pg_table, pte); + address += PAGE_SIZE; + } + } + + mmu_emu_init(); + + current->mm = NULL; + + return PAGE_ALIGN(free_area_init(start_mem, end_mem)); +} + + diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/Makefile linux/arch/m68k/sun3/Makefile --- v2.3.16/linux/arch/m68k/sun3/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/Makefile Sat Sep 4 13:06:41 1999 @@ -0,0 +1,16 @@ +# +# Makefile for Linux arch/m68k/sun3 source directory +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.o: + $(CC) -D__ASSEMBLY__ -traditional -Wa,-m68020 -c $< -o $*.o + +O_TARGET := sun3.o +O_OBJS := config.o idprom.o mmu_emu.o sun3ints.o leds.o dvma.o sbus.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/config.c linux/arch/m68k/sun3/config.c --- v2.3.16/linux/arch/m68k/sun3/config.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/config.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,173 @@ +/* + * linux/arch/m68k/sun3/config.c + * + * Copyright (C) 1996,1997 Pekka Pietik{inen + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char _text, _end; + +static int kernel_start, kernel_end; +char sun3_reserved_pmeg[SUN3_PMEGS_NUM]; + +static unsigned long sun3_gettimeoffset(void); +extern int sun3_get_irq_list (char *); +extern void sun3_sched_init(void (*handler)(int, void *, struct pt_regs *)); +extern void sun3_init_IRQ (void); +extern void (*sun3_default_handler[]) (int, void *, struct pt_regs *); +extern int sun3_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id); +extern void sun3_free_irq (unsigned int irq, void *dev_id); +extern void sun3_enable_irq (unsigned int); +extern void sun3_disable_irq (unsigned int); +extern void sun3_enable_interrupts (void); +extern void sun3_disable_interrupts (void); +extern void sun3_get_model (unsigned char* model); +extern void idprom_init (void); +void sun3_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp); + +extern unsigned long sun_serial_setup(unsigned long memory_start); +volatile char* clock_va; +extern unsigned char* sun3_intreg; + +__initfunc(void sun3_init(void)) +{ + unsigned char enable_register; + int i; + + m68k_machtype= MACH_SUN3; + m68k_cputype = CPU_68020; + m68k_fputype = FPU_68881; /* mc68881 actually */ + m68k_mmutype = MMU_SUN3; + clock_va = (char *) 0xfe06000; /* dark */ + sun3_intreg = (unsigned char *) 0xfe0a000; /* magic */ + sun3_disable_interrupts(); + + prom_init((void *)LINUX_OPPROM_BEGVM); + + GET_CONTROL_BYTE(AC_SENABLE,enable_register); + enable_register |= 0x40; /* Enable FPU */ + SET_CONTROL_BYTE(AC_SENABLE,enable_register); + GET_CONTROL_BYTE(AC_SENABLE,enable_register); + + /* This code looks suspicious, because it doesn't subtract + memory belonging to the kernel from the available space */ + + + memset(sun3_reserved_pmeg, 0, sizeof(sun3_reserved_pmeg)); + + /* Reserve important PMEGS */ + /* FIXME: These should be probed instead of hardcoded */ + + for (i=0; i<8; i++) /* Kernel PMEGs */ + sun3_reserved_pmeg[i] = 1; + + sun3_reserved_pmeg[247] = 1; /* ROM mapping */ + sun3_reserved_pmeg[248] = 1; /* AMD Ethernet */ + sun3_reserved_pmeg[251] = 1; /* VB area */ + sun3_reserved_pmeg[254] = 1; /* main I/O */ + + sun3_reserved_pmeg[249] = 1; + sun3_reserved_pmeg[252] = 1; + sun3_reserved_pmeg[253] = 1; + set_fs(KERNEL_DS); +} + +/* Without this, Bad Things happen when something calls arch_reset. */ +static void sun3_reboot (void) +{ + prom_reboot ("vmlinux"); +} + +__initfunc(void config_sun3(unsigned long *start_mem_p, unsigned long *end_mem_p)) +{ + printk("ARCH: SUN3\n"); + idprom_init(); + + /* Subtract kernel memory from available memory */ + + mach_sched_init = sun3_sched_init; + mach_init_IRQ = sun3_init_IRQ; + mach_default_handler = &sun3_default_handler; + mach_request_irq = sun3_request_irq; + mach_free_irq = sun3_free_irq; +// mach_keyb_init = sun3_keyb_init; + enable_irq = sun3_enable_irq; + disable_irq = sun3_disable_irq; + mach_get_irq_list = sun3_get_irq_list; + mach_gettod = sun3_gettod; + mach_reset = sun3_reboot; + mach_gettimeoffset = sun3_gettimeoffset; + mach_get_model = sun3_get_model; +#ifndef CONFIG_SERIAL_CONSOLE + conswitchp = &dummy_con; +#endif + kernel_start = 0x00000000; /* NOT &_text */ + kernel_end = ((((int)&_end) + 0x2000) & ~0x1fff) - 1; + + *start_mem_p = kernel_end + 1; +// PROM seems to want the last couple of physical pages. --m + *end_mem_p = *(romvec->pv_sun3mem) + PAGE_OFFSET - 2*PAGE_SIZE; + m68k_num_memory=1; + m68k_memory[0].size=*(romvec->pv_sun3mem); + + *start_mem_p = sun_serial_setup(*start_mem_p); +} + +__initfunc(void sun3_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) +{ + sun3_disable_interrupts(); + intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE); + intersil_clock->int_reg=INTERSIL_HZ_100_MASK; + intersil_clear(); + sun3_enable_irq(5); + intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_ENABLE|INTERSIL_24H_MODE); + sun3_enable_interrupts(); + intersil_clear(); +} + +static unsigned long sun3_gettimeoffset(void) +{ + return 1; +} + +void sun3_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + struct intersil_dt* todintersil; + todintersil = (struct intersil_dt *) &intersil_clock->counter; + *secp = todintersil->second; + *minp = todintersil->minute; + *hourp = todintersil->hour; + *dayp = todintersil->day; + *monp = todintersil->month; + *yearp = todintersil->year+68; /* The base year for sun3 is 1968 */ +} + diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/dvma.c linux/arch/m68k/sun3/dvma.c --- v2.3.16/linux/arch/m68k/sun3/dvma.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/dvma.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,33 @@ + +/* dvma support routines */ + +#include +#include +#include +#include +#include +#include + +unsigned long dvma_next_free = DVMA_START; + +/* get needed number of free dma pages, or panic if not enough */ + +void *sun3_dvma_malloc(int len) +{ + unsigned long vaddr; + + /* if the next free pages have been accessed, skip them */ + while((dvma_next_free < DVMA_END) && + (sun3_get_pte(dvma_next_free) & SUN3_PAGE_ACCESSED)) + dvma_next_free += SUN3_PTE_SIZE; + + if((dvma_next_free + len) > DVMA_END) + panic("sun3_dvma_malloc: out of dvma pages"); + + vaddr = dvma_next_free; + dvma_next_free = PAGE_ALIGN(dvma_next_free + len); + + return (void *)vaddr; +} + + diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/idprom.c linux/arch/m68k/sun3/idprom.c --- v2.3.16/linux/arch/m68k/sun3/idprom.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/idprom.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,129 @@ +/* $Id: idprom.c,v 1.22 1996/11/13 05:09:25 davem Exp $ + * idprom.c: Routines to load the idprom into kernel addresses and + * interpret the data contained within. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Sun3/3x models added by David Monro (davidm@psrg.cs.usyd.edu.au) + */ + +#include +#include +#include +#include + +#include +#include +#include /* Fun with Sun released architectures. */ + +struct idprom *idprom; +static struct idprom idprom_buffer; + +/* Here is the master table of Sun machines which use some implementation + * of the Sparc CPU and have a meaningful IDPROM machtype value that we + * know about. See asm-sparc/machines.h for empirical constants. + */ +struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = { +/* First, Sun3's */ +{ "Sun 3/160 Series", (SM_SUN3 | SM_3_160) }, +{ "Sun 3/50", (SM_SUN3 | SM_3_50) }, +{ "Sun 3/260 Series", (SM_SUN3 | SM_3_260) }, +{ "Sun 3/110 Series", (SM_SUN3 | SM_3_110) }, +{ "Sun 3/60", (SM_SUN3 | SM_3_60) }, +{ "Sun 3/E", (SM_SUN3 | SM_3_E) }, +/* Now, Sun3x's */ +{ "Sun 3/460 Series", (SM_SUN3 | SM_3_460) }, +{ "Sun 3/80", (SM_SUN3 | SM_3_80) }, +/* Then, Sun4's */ +//{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) }, +//{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) }, +//{ "Sun 4/300 Series", (SM_SUN4 | SM_4_330) }, +//{ "Sun 4/400 Series", (SM_SUN4 | SM_4_470) }, +/* And now, Sun4c's */ +//{ "Sun4c SparcStation 1", (SM_SUN4C | SM_4C_SS1) }, +//{ "Sun4c SparcStation IPC", (SM_SUN4C | SM_4C_IPC) }, +//{ "Sun4c SparcStation 1+", (SM_SUN4C | SM_4C_SS1PLUS) }, +//{ "Sun4c SparcStation SLC", (SM_SUN4C | SM_4C_SLC) }, +//{ "Sun4c SparcStation 2", (SM_SUN4C | SM_4C_SS2) }, +//{ "Sun4c SparcStation ELC", (SM_SUN4C | SM_4C_ELC) }, +//{ "Sun4c SparcStation IPX", (SM_SUN4C | SM_4C_IPX) }, +/* Finally, early Sun4m's */ +//{ "Sun4m SparcSystem600", (SM_SUN4M | SM_4M_SS60) }, +//{ "Sun4m SparcStation10/20", (SM_SUN4M | SM_4M_SS50) }, +//{ "Sun4m SparcStation5", (SM_SUN4M | SM_4M_SS40) }, +/* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */ +//{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } +}; + +__initfunc(static void display_system_type(unsigned char machtype)) +{ + register int i; + + for (i = 0; i < NUM_SUN_MACHINES; i++) { + if(Sun_Machines[i].id_machtype == machtype) { + if (machtype != (SM_SUN4M_OBP | 0x00)) + printk("TYPE: %s\n", Sun_Machines[i].name); + else { +#if 0 + prom_getproperty(prom_root_node, "banner-name", + sysname, sizeof(sysname)); + printk("TYPE: %s\n", sysname); +#endif + } + return; + } + } + + prom_printf("IDPROM: Bogus id_machtype value, 0x%x\n", machtype); + prom_halt(); +} + +void sun3_get_model(unsigned char* model) +{ + register int i; + + for (i = 0; i < NUM_SUN_MACHINES; i++) { + if(Sun_Machines[i].id_machtype == idprom->id_machtype) { + strcpy(model, Sun_Machines[i].name); + return; + } + } +} + + + +/* Calculate the IDPROM checksum (xor of the data bytes). */ +__initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom)) +{ + unsigned char cksum, i, *ptr = (unsigned char *)idprom; + + for (i = cksum = 0; i <= 0x0E; i++) + cksum ^= *ptr++; + + return cksum; +} + +/* Create a local IDPROM copy, verify integrity, and display information. */ +__initfunc(void idprom_init(void)) +{ + prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer)); + + idprom = &idprom_buffer; + + if (idprom->id_format != 0x01) { + prom_printf("IDPROM: Unknown format type!\n"); + prom_halt(); + } + + if (idprom->id_cksum != calc_idprom_cksum(idprom)) { + prom_printf("IDPROM: Checksum failure (nvram=%x, calc=%x)!\n", + idprom->id_cksum, calc_idprom_cksum(idprom)); + prom_halt(); + } + + display_system_type(idprom->id_machtype); + + printk("Ethernet address: %x:%x:%x:%x:%x:%x\n", + idprom->id_ethaddr[0], idprom->id_ethaddr[1], + idprom->id_ethaddr[2], idprom->id_ethaddr[3], + idprom->id_ethaddr[4], idprom->id_ethaddr[5]); +} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/leds.c linux/arch/m68k/sun3/leds.c --- v2.3.16/linux/arch/m68k/sun3/leds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/leds.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +#define FC_CONTROL 3 /* This should go somewhere else... */ + +void sun3_leds(unsigned char byte) +{ + unsigned char dfc; + + GET_DFC(dfc); + SET_DFC(FC_CONTROL); + SET_CONTROL_BYTE(AC_LEDS,byte); + SET_DFC(dfc); +} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/mmu_emu.c linux/arch/m68k/sun3/mmu_emu.c --- v2.3.16/linux/arch/m68k/sun3/mmu_emu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/mmu_emu.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,445 @@ +/* +** Tablewalk MMU emulator +** +** by Toshiyasu Morita +** +** Started 1/16/98 @ 2:22 am +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void prom_reboot (char *) __attribute__ ((__noreturn__)); + +#undef DEBUG_MMU_EMU + +/* +** Defines +*/ + +#define CONTEXTS_NUM 8 +#define SEGMAPS_PER_CONTEXT_NUM 2048 +#define PAGES_PER_SEGMENT 16 +#define PMEGS_NUM 256 +#define PMEG_MASK 0xFF + +/* +** Globals +*/ + +unsigned long vmalloc_end = 0; +unsigned long pmeg_vaddr[PMEGS_NUM]; +unsigned char pmeg_alloc[PMEGS_NUM]; +unsigned char pmeg_ctx[PMEGS_NUM]; + +/* pointers to the mm structs for each task in each + context. 0xffffffff is a marker for kernel context */ +struct mm_struct *ctx_alloc[CONTEXTS_NUM] = {0xffffffff, 0, 0, 0, 0, 0, 0, 0}; +/* has this context been mmdrop'd? */ +unsigned char ctx_live[CONTEXTS_NUM] = {1, 0, 0, 0, 0, 0, 0, 0}; +static unsigned char ctx_avail = CONTEXTS_NUM-1; +unsigned char ctx_next_to_die = 1; + +/* array of pages to be marked off for the rom when we do mem_init later */ +/* 256 pages lets the rom take up to 2mb of physical ram.. I really + hope it never wants mote than that. */ +unsigned long rom_pages[256]; + +/* Print a PTE value in symbolic form. For debugging. */ +void print_pte (pte_t pte) +{ +#if 0 + /* Verbose version. */ + unsigned long val = pte_val (pte); + printk (" pte=%lx [addr=%lx", + val, (val & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT); + if (val & SUN3_PAGE_VALID) printk (" valid"); + if (val & SUN3_PAGE_WRITEABLE) printk (" write"); + if (val & SUN3_PAGE_SYSTEM) printk (" sys"); + if (val & SUN3_PAGE_NOCACHE) printk (" nocache"); + if (val & SUN3_PAGE_ACCESSED) printk (" accessed"); + if (val & SUN3_PAGE_MODIFIED) printk (" modified"); + switch (val & SUN3_PAGE_TYPE_MASK) { + case SUN3_PAGE_TYPE_MEMORY: printk (" memory"); break; + case SUN3_PAGE_TYPE_IO: printk (" io"); break; + case SUN3_PAGE_TYPE_VME16: printk (" vme16"); break; + case SUN3_PAGE_TYPE_VME32: printk (" vme32"); break; + } + printk ("]\n"); +#else + /* Terse version. More likely to fit on a line. */ + unsigned long val = pte_val (pte); + char flags[7], *type; + + flags[0] = (val & SUN3_PAGE_VALID) ? 'v' : '-'; + flags[1] = (val & SUN3_PAGE_WRITEABLE) ? 'w' : '-'; + flags[2] = (val & SUN3_PAGE_SYSTEM) ? 's' : '-'; + flags[3] = (val & SUN3_PAGE_NOCACHE) ? 'x' : '-'; + flags[4] = (val & SUN3_PAGE_ACCESSED) ? 'a' : '-'; + flags[5] = (val & SUN3_PAGE_MODIFIED) ? 'm' : '-'; + flags[6] = '\0'; + + switch (val & SUN3_PAGE_TYPE_MASK) { + case SUN3_PAGE_TYPE_MEMORY: type = "memory"; break; + case SUN3_PAGE_TYPE_IO: type = "io" ; break; + case SUN3_PAGE_TYPE_VME16: type = "vme16" ; break; + case SUN3_PAGE_TYPE_VME32: type = "vme32" ; break; + default: type = "unknown?"; break; + } + + printk (" pte=%08lx [%07lx %s %s]\n", + val, (val & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT, flags, type); +#endif +} + +/* Print the PTE value for a given virtual address. For debugging. */ +void print_pte_vaddr (unsigned long vaddr) +{ + printk (" vaddr=%lx [%02lx]", vaddr, sun3_get_segmap (vaddr)); + print_pte (__pte (sun3_get_pte (vaddr))); +} + +/* + * Initialise the MMU emulator. + */ +void mmu_emu_init(void) +{ + unsigned long seg, num; + int i,j; + extern char _stext, _etext; + unsigned long page; + + memset(rom_pages, 0, sizeof(rom_pages)); + memset(pmeg_vaddr, 0, sizeof(pmeg_vaddr)); + memset(pmeg_alloc, 0, sizeof(pmeg_alloc)); + memset(pmeg_ctx, 0, sizeof(pmeg_ctx)); + +#ifdef DEBUG_MMU_EMU + printk ("mmu_emu_init: stext=%p etext=%p pmegs=%u\n", &_stext, + &_etext, (&_etext-&_stext+SUN3_PMEG_SIZE-1) >> + SUN3_PMEG_SIZE_BITS); +#endif + + /* mark the pmegs copied in sun3-head.S as used */ + for (i=0; i<10; ++i) + pmeg_alloc[i] = 2; + + /* I'm thinking that most of the top pmeg's are going to be + used for something, and we probably shouldn't risk it */ + for(num = 0xf0; num <= 0xff; num++) + pmeg_alloc[num] = 2; + + j = 0; + for (num=0, seg=0x0F800000; seg<0x10000000; seg+=16*PAGE_SIZE) { + if (sun3_get_segmap (seg) != SUN3_INVALID_PMEG) { +#ifdef DEBUG_MMU_EMU + printk ("mapped:"); + print_pte_vaddr (seg); +#endif + // the lowest mapping here is the end of our + // vmalloc region + if(!vmalloc_end) + vmalloc_end = seg; + + // mark the segmap alloc'd, and reserve any + // of the first 0xbff pages the hardware is + // already using... does any sun3 support > 24mb? + pmeg_alloc[sun3_get_segmap(seg)] = 2; + for(i = 0; i < SUN3_PMEG_SIZE; i += PAGE_SIZE) + { + page = (sun3_get_pte(seg+i) & + SUN3_PAGE_PGNUM_MASK); + + if((page) && (page < 0xbff)) { + rom_pages[j] = page; + j++; + } + } + } + } + + + /* blank everything below the kernel, and we've got the base + mapping to start all the contexts off with... */ + for(seg = 0; seg < PAGE_OFFSET; seg += SUN3_PMEG_SIZE) + sun3_put_segmap(seg, SUN3_INVALID_PMEG); + + set_fs(MAKE_MM_SEG(3)); + for(seg = 0; seg < 0x10000000; seg += SUN3_PMEG_SIZE) { + i = sun3_get_segmap(seg); + for(j = 1; j < CONTEXTS_NUM; j++) + (*(romvec->pv_setctxt))(j, (void *)seg, i); + } + set_fs(KERNEL_DS); + +} + +/* called during mem_init to create the needed holes in the mem + mappings */ +void mmu_emu_reserve_pages(unsigned long max_page) +{ + int i = 0; + + while(rom_pages[i] != 0) { + // don't tamper with pages that wound up after end_mem + if(rom_pages[i] < max_page) + set_bit(PG_reserved, &mem_map[rom_pages[i]].flags); + i++; + } +} + +/* erase the mappings for a dead context. Uses the pg_dir for hints + as the pmeg tables proved somewhat unreliable, and unmapping all of + TASK_SIZE was much slower and no more stable. */ +/* todo: find a better way to keep track of the pmegs used by a + context for when they're cleared */ +void clear_context(unsigned long context) +{ + unsigned char oldctx; + unsigned long i; + + if(!ctx_alloc[context]) + panic("clear_context: context not allocated\n"); + + oldctx = sun3_get_context(); + + sun3_put_context(context); + + /* ctx_live denotes if we're clearing a context with an active + mm, in which case we can use the pgd for clues and also should + mark that mm as lacking a context. if the context has been + mmdrop'd, then flush outright. */ + + if(!ctx_live[context]) { + for(i = 0; i < TASK_SIZE ; i += SUN3_PMEG_SIZE) + sun3_put_segmap(i, SUN3_INVALID_PMEG); + } else { + pgd_t *pgd; + + pgd = ctx_alloc[context]->pgd; + ctx_alloc[context]->context = SUN3_INVALID_CONTEXT; + for(i = 0; i < (TASK_SIZE>>PGDIR_SHIFT); i++, pgd++) + { + if(pgd_val(*pgd)) { + sun3_put_segmap(i<= PAGE_OFFSET) { + /* map kernel pmegs into all contexts */ + unsigned char i; + + for(i = 0; i < CONTEXTS_NUM; i++) { + sun3_put_context(i); + sun3_put_segmap (vaddr, curr_pmeg); + } + sun3_put_context(context); + pmeg_alloc[curr_pmeg] = 2; + pmeg_ctx[curr_pmeg] = 0; + + } + else { + pmeg_alloc[curr_pmeg] = 1; + pmeg_ctx[curr_pmeg] = context; + sun3_put_segmap (vaddr, curr_pmeg); + + } + pmeg_vaddr[curr_pmeg] = vaddr; + + /* Set hardware mapping and clear the old PTE entries. */ + for (i=0; i ? + +// kernel_fault is set when a kernel page couldn't be demand mapped, +// and forces another try using the kernel page table. basically a +// hack so that vmalloc would work correctly. + +int mmu_emu_handle_fault (unsigned long vaddr, int read_flag, int kernel_fault) +{ + unsigned long segment, offset; + unsigned char context; + pte_t *pte; + pgd_t * crp; + + if(current->mm == NULL) { + crp = swapper_pg_dir; + context = 0; + } else { + context = current->mm->context; + if(kernel_fault) + crp = swapper_pg_dir; + else + crp = current->mm->pgd; + } + +#ifdef DEBUG_MMU_EMU + printk ("mmu_emu_handle_fault: vaddr=%lx type=%s crp=%p\n", + vaddr, read_flag ? "read" : "write", crp); +#endif + + segment = (vaddr >> SUN3_PMEG_SIZE_BITS) & 0x7FF; + offset = (vaddr >> SUN3_PTE_SIZE_BITS) & 0xF; + +#ifdef DEBUG_MMU_EMU + printk ("mmu_emu_handle_fault: segment=%lx offset=%lx\n", segment, offset); +#endif + + pte = (pte_t *) pgd_val (*(crp + segment)); + +//todo: next line should check for valid pmd properly. + if (!pte) { +// printk ("mmu_emu_handle_fault: invalid pmd\n"); + return 0; + } + + pte = (pte_t *) __va ((unsigned long)(pte + offset)); + + /* Make sure this is a valid page */ + if (!(pte_val (*pte) & SUN3_PAGE_VALID)) + return 0; + + /* Make sure there's a pmeg allocated for the page */ + if (sun3_get_segmap (vaddr&~SUN3_PMEG_MASK) == SUN3_INVALID_PMEG) + mmu_emu_map_pmeg (context, vaddr); + + /* Write the pte value to hardware MMU */ + sun3_put_pte (vaddr&PAGE_MASK, pte_val (*pte)); + + /* Update software copy of the pte value */ +// I'm not sure this is necessary. If this is required, we ought to simply +// copy this out when we reuse the PMEG or at some other convenient time. +// Doing it here is fairly meaningless, anyway, as we only know about the +// first access to a given page. --m + if (!read_flag) { + if (pte_val (*pte) & SUN3_PAGE_WRITEABLE) + pte_val (*pte) |= (SUN3_PAGE_ACCESSED + | SUN3_PAGE_MODIFIED); + else + return 0; /* Write-protect error. */ + } else + pte_val (*pte) |= SUN3_PAGE_ACCESSED; + +#ifdef DEBUG_MMU_EMU + printk ("seg:%d crp:%p ->", get_fs().seg, crp); + print_pte_vaddr (vaddr); + printk ("\n"); +#endif + + return 1; +} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/prom/Makefile linux/arch/m68k/sun3/prom/Makefile --- v2.3.16/linux/arch/m68k/sun3/prom/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/prom/Makefile Sat Sep 4 13:06:41 1999 @@ -0,0 +1,22 @@ +# $Id: Makefile,v 1.5 1995/11/25 00:59:48 davem Exp $ +# Makefile for the Sun Boot PROM interface library under +# Linux. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +OBJS = init.o console.o printf.o misc.o +#bootstr.o init.o misc.o segment.o console.o printf.o +all: promlib.a + +promlib.a: $(OBJS) + $(AR) rcs promlib.a $(OBJS) + sync + +dep: + $(CPP) -M *.c > .depend + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/prom/console.c linux/arch/m68k/sun3/prom/console.c --- v2.3.16/linux/arch/m68k/sun3/prom/console.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/prom/console.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,175 @@ +/* $Id: console.c,v 1.10 1996/12/18 06:46:54 tridge Exp $ + * console.c: Routines that deal with sending and receiving IO + * to/from the current console device using the PROM. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Non blocking get character from console input device, returns -1 + * if no input was taken. This can be used for polling. + */ +int +prom_nbgetchar(void) +{ + int i = -1; + unsigned long flags; + + save_flags(flags); cli(); + i = (*(romvec->pv_nbgetchar))(); + restore_flags(flags); + return i; /* Ugh, we could spin forever on unsupported proms ;( */ +} + +/* Non blocking put character to console device, returns -1 if + * unsuccessful. + */ +int +prom_nbputchar(char c) +{ + unsigned long flags; + int i = -1; + + save_flags(flags); cli(); + i = (*(romvec->pv_nbputchar))(c); + restore_flags(flags); + return i; /* Ugh, we could spin forever on unsupported proms ;( */ +} + +/* Blocking version of get character routine above. */ +char +prom_getchar(void) +{ + int character; + while((character = prom_nbgetchar()) == -1) ; + return (char) character; +} + +/* Blocking version of put character routine above. */ +void +prom_putchar(char c) +{ + while(prom_nbputchar(c) == -1) ; + return; +} + +/* Query for input device type */ +#if 0 +enum prom_input_device +prom_query_input_device() +{ + unsigned long flags; + int st_p; + char propb[64]; + char *p; + + switch(prom_vers) { + case PROM_V0: + case PROM_V2: + default: + switch(*romvec->pv_stdin) { + case PROMDEV_KBD: return PROMDEV_IKBD; + case PROMDEV_TTYA: return PROMDEV_ITTYA; + case PROMDEV_TTYB: return PROMDEV_ITTYB; + default: + return PROMDEV_I_UNK; + }; + case PROM_V3: + case PROM_P1275: + save_flags(flags); cli(); + st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin); + __asm__ __volatile__("ld [%0], %%g6\n\t" : : + "r" (¤t_set[smp_processor_id()]) : + "memory"); + restore_flags(flags); + if(prom_node_has_property(st_p, "keyboard")) + return PROMDEV_IKBD; + prom_getproperty(st_p, "device_type", propb, sizeof(propb)); + if(strncmp(propb, "serial", sizeof("serial"))) + return PROMDEV_I_UNK; + prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb)); + p = propb; + while(*p) p++; p -= 2; + if(p[0] == ':') { + if(p[1] == 'a') + return PROMDEV_ITTYA; + else if(p[1] == 'b') + return PROMDEV_ITTYB; + } + return PROMDEV_I_UNK; + case PROM_AP1000: + return PROMDEV_I_UNK; + }; +} +#endif + +/* Query for output device type */ + +#if 0 +enum prom_output_device +prom_query_output_device() +{ + unsigned long flags; + int st_p; + char propb[64]; + char *p; + int propl; + + switch(prom_vers) { + case PROM_V0: + switch(*romvec->pv_stdin) { + case PROMDEV_SCREEN: return PROMDEV_OSCREEN; + case PROMDEV_TTYA: return PROMDEV_OTTYA; + case PROMDEV_TTYB: return PROMDEV_OTTYB; + }; + break; + case PROM_V2: + case PROM_V3: + case PROM_P1275: + save_flags(flags); cli(); + st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout); + __asm__ __volatile__("ld [%0], %%g6\n\t" : : + "r" (¤t_set[smp_processor_id()]) : + "memory"); + restore_flags(flags); + propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); + if (propl >= 0 && propl == sizeof("display") && + strncmp("display", propb, sizeof("display")) == 0) + { + return PROMDEV_OSCREEN; + } + if(prom_vers == PROM_V3) { + if(strncmp("serial", propb, sizeof("serial"))) + return PROMDEV_O_UNK; + prom_getproperty(prom_root_node, "stdout-path", propb, sizeof(propb)); + p = propb; + while(*p) p++; p -= 2; + if(p[0]==':') { + if(p[1] == 'a') + return PROMDEV_OTTYA; + else if(p[1] == 'b') + return PROMDEV_OTTYB; + } + return PROMDEV_O_UNK; + } else { + /* This works on SS-2 (an early OpenFirmware) still. */ + switch(*romvec->pv_stdin) { + case PROMDEV_TTYA: return PROMDEV_OTTYA; + case PROMDEV_TTYB: return PROMDEV_OTTYB; + }; + } + break; + case PROM_AP1000: + return PROMDEV_I_UNK; + }; + return PROMDEV_O_UNK; +} +#endif diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/prom/init.c linux/arch/m68k/sun3/prom/init.c --- v2.3.16/linux/arch/m68k/sun3/prom/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/prom/init.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,89 @@ +/* $Id: init.c,v 1.9 1996/12/18 06:46:55 tridge Exp $ + * init.c: Initialize internal variables used by the PROM + * library functions. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include + +#include +#include + +struct linux_romvec *romvec; +enum prom_major_version prom_vers; +unsigned int prom_rev, prom_prev; + +/* The root node of the prom device tree. */ +int prom_root_node; + +/* Pointer to the device tree operations structure. */ +struct linux_nodeops *prom_nodeops; + +/* You must call prom_init() before you attempt to use any of the + * routines in the prom library. It returns 0 on success, 1 on + * failure. It gets passed the pointer to the PROM vector. + */ + +extern void prom_meminit(void); +extern void prom_ranges_init(void); + +__initfunc(void prom_init(struct linux_romvec *rp)) +{ +#if CONFIG_AP1000 + extern struct linux_romvec *ap_prom_init(void); + rp = ap_prom_init(); +#endif + + romvec = rp; +#ifndef CONFIG_SUN3 + switch(romvec->pv_romvers) { + case 0: + prom_vers = PROM_V0; + break; + case 2: + prom_vers = PROM_V2; + break; + case 3: + prom_vers = PROM_V3; + break; + case 4: + prom_vers = PROM_P1275; + prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n"); + prom_halt(); + break; + case 42: /* why not :-) */ + prom_vers = PROM_AP1000; + break; + + default: + prom_printf("PROMLIB: Bad PROM version %d\n", + romvec->pv_romvers); + prom_halt(); + break; + }; + + prom_rev = romvec->pv_plugin_revision; + prom_prev = romvec->pv_printrev; + prom_nodeops = romvec->pv_nodeops; + + prom_root_node = prom_getsibling(0); + if((prom_root_node == 0) || (prom_root_node == -1)) + prom_halt(); + + if((((unsigned long) prom_nodeops) == 0) || + (((unsigned long) prom_nodeops) == -1)) + prom_halt(); + + prom_meminit(); + + prom_ranges_init(); +#endif +// printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n", +// romvec->pv_romvers, prom_rev); + + /* Initialization successful. */ + return; +} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/prom/misc.c linux/arch/m68k/sun3/prom/misc.c --- v2.3.16/linux/arch/m68k/sun3/prom/misc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/prom/misc.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,95 @@ +/* $Id: misc.c,v 1.15 1997/05/14 20:45:00 davem Exp $ + * misc.c: Miscellaneous prom functions that don't belong + * anywhere else. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Reset and reboot the machine with the command 'bcommand'. */ +void +prom_reboot(char *bcommand) +{ + unsigned long flags; + save_flags(flags); cli(); + (*(romvec->pv_reboot))(bcommand); + restore_flags(flags); +} + +/* Drop into the prom, with the chance to continue with the 'go' + * prom command. + */ +void +prom_cmdline(void) +{ +} + +/* Drop into the prom, but completely terminate the program. + * No chance of continuing. + */ +void +prom_halt(void) +{ + unsigned long flags; +again: + save_flags(flags); cli(); + (*(romvec->pv_halt))(); + restore_flags(flags); + goto again; /* PROM is out to get me -DaveM */ +} + +typedef void (*sfunc_t)(void); + +/* Get the idprom and stuff it into buffer 'idbuf'. Returns the + * format type. 'num_bytes' is the number of bytes that your idbuf + * has space for. Returns 0xff on error. + */ +unsigned char +prom_get_idprom(char *idbuf, int num_bytes) +{ + int i, oldsfc; + GET_SFC(oldsfc); + SET_SFC(FC_CONTROL); + for(i=0;ipv_romvers; +} + +/* Get the prom plugin-revision. */ +int +prom_getrev(void) +{ + return prom_rev; +} + +/* Get the prom firmware print revision. */ +int +prom_getprev(void) +{ + return prom_prev; +} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/prom/printf.c linux/arch/m68k/sun3/prom/printf.c --- v2.3.16/linux/arch/m68k/sun3/prom/printf.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/prom/printf.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,61 @@ +/* $Id: printf.c,v 1.5 1996/04/04 16:31:07 tridge Exp $ + * printf.c: Internal prom library printf facility. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +/* This routine is internal to the prom library, no one else should know + * about or use it! It's simple and smelly anyway.... + */ + +#include +#include + +#include +#include + +#ifdef CONFIG_KGDB +extern int kgdb_initialized; +#endif + +static char ppbuf[1024]; + +void +prom_printf(char *fmt, ...) +{ + va_list args; + char ch, *bptr; + int i; + + va_start(args, fmt); + +#ifdef CONFIG_KGDB + ppbuf[0] = 'O'; + i = vsprintf(ppbuf + 1, fmt, args) + 1; +#else + i = vsprintf(ppbuf, fmt, args); +#endif + + bptr = ppbuf; + +#if CONFIG_AP1000 + ap_write(1,bptr,strlen(bptr)); +#else + +#ifdef CONFIG_KGDB + if (kgdb_initialized) { + printk("kgdb_initialized = %d\n", kgdb_initialized); + putpacket(bptr, 1); + } else +#else + while((ch = *(bptr++)) != 0) { + if(ch == '\n') + prom_putchar('\r'); + + prom_putchar(ch); + } +#endif +#endif + va_end(args); + return; +} diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/sbus.c linux/arch/m68k/sun3/sbus.c --- v2.3.16/linux/arch/m68k/sun3/sbus.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/sbus.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,25 @@ +/* + * SBus helper functions + * + * Sun3 don't have a sbus, but many of the used devices are also + * used on Sparc machines with sbus. To avoid having a lot of + * duplicate code, we provide necessary glue stuff to make using + * of the sbus driver code possible. + * + * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + */ + +#include +#include + +__initfunc(void sbus_init(void)) +{ + +} + +void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, + u32 bus_type, int rdonly) +{ + return (void *)address; +} + diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/sun3ints.c linux/arch/m68k/sun3/sun3ints.c --- v2.3.16/linux/arch/m68k/sun3/sun3ints.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/sun3/sun3ints.c Sat Sep 4 13:06:41 1999 @@ -0,0 +1,132 @@ + /* + * linux/arch/m68k/sun3/sun3ints.c -- Sun-3 Linux interrupt handling code + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void sun3_leds (unsigned char); + +void sun3_disable_interrupts(void) +{ + sun3_disable_irq(0); +} + +void sun3_enable_interrupts(void) +{ + sun3_enable_irq(0); +} + +int led_pattern[8] = { + ~(0x80), ~(0x01), + ~(0x40), ~(0x02), + ~(0x20), ~(0x04), + ~(0x10), ~(0x08) +}; + +unsigned char* sun3_intreg; + +void sun3_init_IRQ(void) +{ +} + +void sun3_insert_irq(irq_node_t **list, irq_node_t *node) +{ +} + +void sun3_delete_irq(irq_node_t **list, void *dev_id) +{ +} + +void sun3_free_irq(unsigned int irq, void *dev_id) +{ +} + +void sun3_enable_irq(unsigned int irq) +{ + *sun3_intreg |= (1< -#include +#include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/ppc/kernel/gemini_prom.S linux/arch/ppc/kernel/gemini_prom.S --- v2.3.16/linux/arch/ppc/kernel/gemini_prom.S Tue Aug 31 17:29:12 1999 +++ linux/arch/ppc/kernel/gemini_prom.S Wed Sep 1 15:34:01 1999 @@ -10,7 +10,6 @@ #include "ppc_asm.tmpl" #include "ppc_defs.h" -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c --- v2.3.16/linux/arch/ppc/kernel/gemini_setup.c Tue Aug 31 17:29:12 1999 +++ linux/arch/ppc/kernel/gemini_setup.c Wed Sep 1 15:34:01 1999 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sh/kernel/irq_onchip.c linux/arch/sh/kernel/irq_onchip.c --- v2.3.16/linux/arch/sh/kernel/irq_onchip.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/irq_onchip.c Wed Sep 1 15:34:01 1999 @@ -7,7 +7,6 @@ * */ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c --- v2.3.16/linux/arch/sh/kernel/process.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/process.c Wed Sep 1 15:34:01 1999 @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sh/kernel/ptrace.c linux/arch/sh/kernel/ptrace.c --- v2.3.16/linux/arch/sh/kernel/ptrace.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/ptrace.c Wed Sep 1 15:34:01 1999 @@ -3,7 +3,6 @@ * linux/arch/sh/kernel/ptrace.c */ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c --- v2.3.16/linux/arch/sh/kernel/time.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/time.c Wed Sep 1 15:34:01 1999 @@ -26,7 +26,6 @@ #include #include -#include #include #define TMU_TOCR 0xfffffe90 /* Byte access */ diff -u --recursive --new-file v2.3.16/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c --- v2.3.16/linux/arch/sh/kernel/traps.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/traps.c Wed Sep 1 15:34:01 1999 @@ -8,7 +8,6 @@ * 'Traps.c' handles hardware traps and faults after we have saved some * state in 'entry.S'. */ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c --- v2.3.16/linux/arch/sh/mm/fault.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/mm/fault.c Wed Sep 1 15:34:01 1999 @@ -23,7 +23,6 @@ #include #include #include -#include /* to get __m() macro */ #include extern void die(const char *,struct pt_regs *,long); diff -u --recursive --new-file v2.3.16/linux/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S --- v2.3.16/linux/arch/sh/vmlinux.lds.S Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/vmlinux.lds.S Wed Sep 1 15:34:01 1999 @@ -1,6 +1,7 @@ /* ld script to make SuperH Linux kernel * Written by Niibe Yutaka */ +#include #ifdef CONFIG_LITTLE_ENDIAN OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") #else diff -u --recursive --new-file v2.3.16/linux/arch/sparc/ap1000/msc.c linux/arch/sparc/ap1000/msc.c --- v2.3.16/linux/arch/sparc/ap1000/msc.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/ap1000/msc.c Wed Sep 1 14:12:09 1999 @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sparc/ap1000/sync.c linux/arch/sparc/ap1000/sync.c --- v2.3.16/linux/arch/sparc/ap1000/sync.c Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/ap1000/sync.c Wed Sep 1 14:12:09 1999 @@ -10,7 +10,7 @@ #include #include #include -#include +#include extern int cap_cid0; extern unsigned _ncel, _ncelx, _ncely, _cid; diff -u --recursive --new-file v2.3.16/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c --- v2.3.16/linux/arch/sparc/kernel/smp.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/kernel/smp.c Wed Sep 1 14:12:09 1999 @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c --- v2.3.16/linux/arch/sparc/kernel/sun4d_smp.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/kernel/sun4d_smp.c Wed Sep 1 14:12:09 1999 @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c --- v2.3.16/linux/arch/sparc/kernel/sun4m_smp.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/kernel/sun4m_smp.c Wed Sep 1 14:12:09 1999 @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c --- v2.3.16/linux/arch/sparc64/kernel/devices.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc64/kernel/devices.c Wed Sep 1 14:12:09 1999 @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c --- v2.3.16/linux/arch/sparc64/kernel/pci.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc64/kernel/pci.c Wed Sep 1 15:34:01 1999 @@ -6,6 +6,7 @@ * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) */ +#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.3.16/linux/arch/sparc64/kernel/smp.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc64/kernel/smp.c Wed Sep 1 14:12:09 1999 @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/drivers/Makefile linux/drivers/Makefile --- v2.3.16/linux/drivers/Makefile Thu Aug 26 13:05:34 1999 +++ linux/drivers/Makefile Fri Sep 3 12:43:54 1999 @@ -22,6 +22,10 @@ SUB_DIRS += pci endif +ifdef CONFIG_PCMCIA +SUB_DIRS += pcmcia +endif + ifdef CONFIG_SBUS SUB_DIRS += sbus MOD_SUB_DIRS += sbus diff -u --recursive --new-file v2.3.16/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.3.16/linux/drivers/block/Config.in Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/Config.in Tue Sep 7 11:23:40 1999 @@ -11,6 +11,11 @@ if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY fi +if [ "$CONFIG_MAC" = "y" ]; then + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP + fi +fi tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE comment 'Please see Documentation/ide.txt for help/info on IDE drives' diff -u --recursive --new-file v2.3.16/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.3.16/linux/drivers/block/Makefile Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/Makefile Tue Sep 7 11:23:40 1999 @@ -54,6 +54,10 @@ endif endif +ifeq ($(CONFIG_BLK_DEV_SWIM_IOP),y) + L_OBJS += swim_iop.o +endif + ifeq ($(CONFIG_ATARI_ACSI),y) LX_OBJS += acsi.o else @@ -136,6 +140,10 @@ ifeq ($(CONFIG_BLK_DEV_GAYLE),y) IDE_OBJS += gayle.o +endif + +ifeq ($(CONFIG_BLK_DEV_Q40IDE),y) +IDE_OBJS += q40ide.o endif ifeq ($(CONFIG_BLK_DEV_HD),y) diff -u --recursive --new-file v2.3.16/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v2.3.16/linux/drivers/block/amiflop.c Tue Jul 6 19:05:48 1999 +++ linux/drivers/block/amiflop.c Sat Sep 4 13:07:19 1999 @@ -135,10 +135,10 @@ static struct fd_drive_type drive_types[] = { /* code name tr he rdsz wrsz sm pc1 pc2 sd st st*/ /* warning: times are now in milliseconds (ms) */ - { FD_DD_3, "DD 3.5", 80, 2, 14716, 13630, 1, 80,161, 3, 18, 1}, - { FD_HD_3, "HD 3.5", 80, 2, 28344, 27258, 2, 80,161, 3, 18, 1}, - { FD_DD_5, "DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2}, - { FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +{ FD_DD_3, "DD 3.5", 80, 2, 14716, 13630, 1, 80,161, 3, 18, 1}, +{ FD_HD_3, "HD 3.5", 80, 2, 28344, 27258, 2, 80,161, 3, 18, 1}, +{ FD_DD_5, "DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2}, +{ FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]); @@ -150,8 +150,8 @@ static int amiga_read(int), dos_read(int); static void amiga_write(int), dos_write(int); static struct fd_data_type data_types[] = { - { "Amiga", 11 , amiga_read, amiga_write}, - { "MS-Dos", 9, dos_read, dos_write} + { "Amiga", 11 , amiga_read, amiga_write}, + { "MS-Dos", 9, dos_read, dos_write} }; /* current info on each unit */ @@ -189,8 +189,8 @@ /* MS-Dos MFM Coding tables (should go quick and easy) */ static unsigned char mfmencode[16]={ - 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, - 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 + 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 }; static unsigned char mfmdecode[128]; @@ -231,29 +231,29 @@ static void ms_isr(int irq, void *dummy, struct pt_regs *fp) { -ms_busy = -1; -wake_up(&ms_wait); + ms_busy = -1; + wake_up(&ms_wait); } /* all waits are queued up A more generic routine would do a schedule a la timer.device */ static void ms_delay(int ms) { - unsigned long flags; - int ticks; - if (ms > 0) { - save_flags(flags); - cli(); - while (ms_busy == 0) - sleep_on(&ms_wait); - ms_busy = 0; - restore_flags(flags); - ticks = MS_TICKS*ms-1; - ciaa.tblo=ticks%256; - ciaa.tbhi=ticks/256; - ciaa.crb=0x19; /*count eclock, force load, one-shoot, start */ - sleep_on(&ms_wait); - } + unsigned long flags; + int ticks; + if (ms > 0) { + save_flags(flags); + cli(); + while (ms_busy == 0) + sleep_on(&ms_wait); + ms_busy = 0; + restore_flags(flags); + ticks = MS_TICKS*ms-1; + ciaa.tblo=ticks%256; + ciaa.tbhi=ticks/256; + ciaa.crb=0x19; /*count eclock, force load, one-shoot, start */ + sleep_on(&ms_wait); + } } /* Hardware semaphore */ @@ -267,33 +267,33 @@ static void get_fdc(int drive) { -unsigned long flags; + unsigned long flags; - drive &= 3; + drive &= 3; #ifdef DEBUG - printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested); + printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested); #endif - save_flags(flags); - cli(); - while (!try_fdc(drive)) - sleep_on(&fdc_wait); - fdc_busy = drive; - fdc_nested++; - restore_flags(flags); + save_flags(flags); + cli(); + while (!try_fdc(drive)) + sleep_on(&fdc_wait); + fdc_busy = drive; + fdc_nested++; + restore_flags(flags); } static inline void rel_fdc(void) { #ifdef DEBUG - if (fdc_nested == 0) - printk("fd: unmatched rel_fdc\n"); - printk("rel_fdc: fdc_busy %d fdc_nested %d\n",fdc_busy,fdc_nested); -#endif - fdc_nested--; - if (fdc_nested == 0) { - fdc_busy = -1; - wake_up(&fdc_wait); - } + if (fdc_nested == 0) + printk("fd: unmatched rel_fdc\n"); + printk("rel_fdc: fdc_busy %d fdc_nested %d\n",fdc_busy,fdc_nested); +#endif + fdc_nested--; + if (fdc_nested == 0) { + fdc_busy = -1; + wake_up(&fdc_wait); + } } static void fd_select (int drive) @@ -395,9 +395,9 @@ static void fd_motor_off(unsigned long drive) { -long calledfromint; + long calledfromint; #ifdef MODULE -long decusecount; + long decusecount; decusecount = drive & 0x40000000; #endif @@ -416,18 +416,18 @@ #ifdef MODULE /* -this is the last interrupt for any drive access, happens after -release (from floppy_off). So we have to wait until now to decrease -the use count. + this is the last interrupt for any drive access, happens after + release (from floppy_off). So we have to wait until now to decrease + the use count. */ - if (decusecount) - MOD_DEC_USE_COUNT; + if (decusecount) + MOD_DEC_USE_COUNT; #endif } static void floppy_off (unsigned int nr) { -int drive; + int drive; drive = nr & 3; del_timer(motor_off_timer + drive); @@ -588,29 +588,29 @@ * type. */ if(drive == 0 && id == FD_NODRIVE) - { + { id = fd_def_df0; printk(KERN_NOTICE "fd: drive 0 didn't identify, setting default %08lx\n", (ulong)fd_def_df0); - } + } /* return the ID value */ return (id); } static void fd_block_done(int irq, void *dummy, struct pt_regs *fp) { - if (block_flag) - custom.dsklen = 0x4000; + if (block_flag) + custom.dsklen = 0x4000; - if (block_flag == 2) { /* writing */ - writepending = 2; - post_write_timer.expires = jiffies + 1; /* at least 2 ms */ - post_write_timer.data = selected; - add_timer(&post_write_timer); - } - else { /* reading */ - block_flag = 0; - wake_up (&wait_fd_block); - } + if (block_flag == 2) { /* writing */ + writepending = 2; + post_write_timer.expires = jiffies + 1; /* at least 2 ms */ + post_write_timer.data = selected; + add_timer(&post_write_timer); + } + else { /* reading */ + block_flag = 0; + wake_up (&wait_fd_block); + } } static void raw_read(int drive) @@ -680,17 +680,17 @@ static void post_write (unsigned long drive) { #ifdef DEBUG - printk("post_write for drive %ld\n",drive); + printk("post_write for drive %ld\n",drive); #endif - drive &= 3; - custom.dsklen = 0; - block_flag = 0; - writepending = 0; - writefromint = 0; - unit[drive].dirty = 0; - wake_up(&wait_fd_block); - fd_deselect(drive); - rel_fdc(); /* corresponds to get_fdc() in raw_write */ + drive &= 3; + custom.dsklen = 0; + block_flag = 0; + writepending = 0; + writefromint = 0; + unit[drive].dirty = 0; + wake_up(&wait_fd_block); + fd_deselect(drive); + rel_fdc(); /* corresponds to get_fdc() in raw_write */ } @@ -727,7 +727,7 @@ } static unsigned long decode (unsigned long *data, unsigned long *raw, - int len) + int len) { ulong *odd, *even; @@ -822,34 +822,34 @@ static void encode(unsigned long data, unsigned long *dest) { - unsigned long data2; + unsigned long data2; - data &= 0x55555555; - data2 = data ^ 0x55555555; - data |= ((data2 >> 1) | 0x80000000) & (data2 << 1); + data &= 0x55555555; + data2 = data ^ 0x55555555; + data |= ((data2 >> 1) | 0x80000000) & (data2 << 1); - if (*(dest - 1) & 0x00000001) - data &= 0x7FFFFFFF; + if (*(dest - 1) & 0x00000001) + data &= 0x7FFFFFFF; - *dest = data; + *dest = data; } static void encode_block(unsigned long *dest, unsigned long *src, int len) { - int cnt, to_cnt = 0; - unsigned long data; + int cnt, to_cnt = 0; + unsigned long data; + + /* odd bits */ + for (cnt = 0; cnt < len / 4; cnt++) { + data = src[cnt] >> 1; + encode(data, dest + to_cnt++); + } - /* odd bits */ - for (cnt = 0; cnt < len / 4; cnt++) { - data = src[cnt] >> 1; - encode(data, dest + to_cnt++); - } - - /* even bits */ - for (cnt = 0; cnt < len / 4; cnt++) { - data = src[cnt]; - encode(data, dest + to_cnt++); - } + /* even bits */ + for (cnt = 0; cnt < len / 4; cnt++) { + data = src[cnt]; + encode(data, dest + to_cnt++); + } } static unsigned long *putsec(int disk, unsigned long *raw, int cnt) @@ -904,15 +904,15 @@ struct dos_header { -unsigned char track, /* 0-80 */ - side, /* 0-1 */ - sec, /* 0-...*/ - len_desc;/* 2 */ -unsigned short crc; /* on 68000 we got an alignment problem, - but this compiler solves it by adding silently - adding a pad byte so data won't fit - and this took about 3h to discover.... */ -unsigned char gap1[22]; /* for longword-alignedness (0x4e) */ + unsigned char track, /* 0-80 */ + side, /* 0-1 */ + sec, /* 0-...*/ + len_desc;/* 2 */ + unsigned short crc; /* on 68000 we got an alignment problem, + but this compiler solves it by adding silently + adding a pad byte so data won't fit + and this took about 3h to discover.... */ + unsigned char gap1[22]; /* for longword-alignedness (0x4e) */ }; /* crc routines are borrowed from the messydos-handler */ @@ -972,299 +972,308 @@ static ushort dos_crc(void * data_a3, int data_d0, int data_d1, int data_d3) { -static unsigned char CRCTable1[] = { - 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1, - 0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62,0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3, - 0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54,0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5, - 0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46,0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7, - 0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38,0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9, - 0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a,0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab, - 0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c,0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d, - 0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e,0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f, - 0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1,0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60, - 0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72, - 0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5,0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44, - 0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7,0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56, - 0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9,0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28, - 0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb,0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a, - 0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d,0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c, - 0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f,0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e -}; - -static unsigned char CRCTable2[] = { - 0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef, - 0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6,0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde, - 0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85,0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d, - 0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4,0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc, - 0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23,0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b, - 0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12,0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a, - 0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41,0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49, - 0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70,0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78, - 0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f,0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67, - 0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e,0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56, - 0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d,0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05, - 0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c,0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34, - 0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab,0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3, - 0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a,0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92, - 0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9,0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1, - 0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8,0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0 -}; + static unsigned char CRCTable1[] = { + 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1, + 0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62,0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3, + 0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54,0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5, + 0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46,0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7, + 0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38,0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9, + 0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a,0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab, + 0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c,0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d, + 0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e,0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f, + 0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1,0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60, + 0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72, + 0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5,0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44, + 0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7,0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56, + 0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9,0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28, + 0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb,0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a, + 0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d,0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c, + 0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f,0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e + }; + + static unsigned char CRCTable2[] = { + 0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef, + 0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6,0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde, + 0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85,0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d, + 0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4,0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc, + 0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23,0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b, + 0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12,0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a, + 0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41,0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49, + 0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70,0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78, + 0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f,0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67, + 0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e,0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56, + 0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d,0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05, + 0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c,0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34, + 0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab,0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3, + 0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a,0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92, + 0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9,0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1, + 0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8,0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0 + }; /* look at the asm-code - what looks in C a bit strange is almost as good as handmade */ -register int i; -register unsigned char *CRCT1, *CRCT2, *data, c, crch, crcl; + register int i; + register unsigned char *CRCT1, *CRCT2, *data, c, crch, crcl; -CRCT1=CRCTable1; -CRCT2=CRCTable2; -data=data_a3; -crcl=data_d1; -crch=data_d0; -for (i=data_d3; i>=0; i--) { - c = (*data++) ^ crch; - crch = CRCT1[c] ^ crcl; - crcl = CRCT2[c]; -} -return (crch<<8)|crcl; + CRCT1=CRCTable1; + CRCT2=CRCTable2; + data=data_a3; + crcl=data_d1; + crch=data_d0; + for (i=data_d3; i>=0; i--) { + c = (*data++) ^ crch; + crch = CRCT1[c] ^ crcl; + crcl = CRCT2[c]; + } + return (crch<<8)|crcl; } static inline ushort dos_hdr_crc (struct dos_header *hdr) { -return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */ + return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */ } static inline ushort dos_data_crc(unsigned char *data) { -return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */ + return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */ } static inline unsigned char dos_decode_byte(ushort word) { -register ushort w2; -register unsigned char byte; -register unsigned char *dec = mfmdecode; - -w2=word; -w2>>=8; -w2&=127; -byte = dec[w2]; -byte <<= 4; -w2 = word & 127; -byte |= dec[w2]; -return byte; + register ushort w2; + register unsigned char byte; + register unsigned char *dec = mfmdecode; + + w2=word; + w2>>=8; + w2&=127; + byte = dec[w2]; + byte <<= 4; + w2 = word & 127; + byte |= dec[w2]; + return byte; } static unsigned long dos_decode(unsigned char *data, unsigned short *raw, int len) { -int i; + int i; -for (i = 0; i < len; i++) - *data++=dos_decode_byte(*raw++); -return ((ulong)raw); + for (i = 0; i < len; i++) + *data++=dos_decode_byte(*raw++); + return ((ulong)raw); } #ifdef DEBUG static void dbg(unsigned long ptr) { - printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n",ptr, - ((ulong *)ptr)[0],((ulong *)ptr)[1],((ulong *)ptr)[2],((ulong *)ptr)[3]); + printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n", ptr, + ((ulong *)ptr)[0], ((ulong *)ptr)[1], + ((ulong *)ptr)[2], ((ulong *)ptr)[3]); } #endif static int dos_read(int drive) { - unsigned long end; - unsigned long raw; - int scnt; - unsigned short crc,data_crc[2]; - struct dos_header hdr; - - drive&=3; - raw = (long) raw_buf; - end = raw + unit[drive].type->read_size; - - for (scnt=0; scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) { - do { /* search for the right sync of each sec-hdr */ - if (!(raw = scan_sync (raw, end))) { - printk(KERN_INFO "dos_read: no hdr sync on track %d, unit %d for sector %d\n", - unit[drive].track,drive,scnt); - return MFM_NOSYNC; - } + unsigned long end; + unsigned long raw; + int scnt; + unsigned short crc,data_crc[2]; + struct dos_header hdr; + + drive&=3; + raw = (long) raw_buf; + end = raw + unit[drive].type->read_size; + + for (scnt=0; scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) { + do { /* search for the right sync of each sec-hdr */ + if (!(raw = scan_sync (raw, end))) { + printk(KERN_INFO "dos_read: no hdr sync on " + "track %d, unit %d for sector %d\n", + unit[drive].track,drive,scnt); + return MFM_NOSYNC; + } #ifdef DEBUG - dbg(raw); + dbg(raw); #endif - } while (*((ushort *)raw)!=0x5554); /* loop usually only once done */ - raw+=2; /* skip over headermark */ - raw = dos_decode((unsigned char *)&hdr,(ushort *) raw,8); - crc = dos_hdr_crc(&hdr); + } while (*((ushort *)raw)!=0x5554); /* loop usually only once done */ + raw+=2; /* skip over headermark */ + raw = dos_decode((unsigned char *)&hdr,(ushort *) raw,8); + crc = dos_hdr_crc(&hdr); #ifdef DEBUG - printk("(%3d,%d,%2d,%d) %x\n", hdr.track, hdr.side, - hdr.sec, hdr.len_desc, hdr.crc); + printk("(%3d,%d,%2d,%d) %x\n", hdr.track, hdr.side, + hdr.sec, hdr.len_desc, hdr.crc); #endif - if (crc != hdr.crc) { - printk(KERN_INFO "dos_read: MFM_HEADER %04x,%04x\n", hdr.crc, crc); - return MFM_HEADER; - } - if (hdr.track != unit[drive].track/unit[drive].type->heads) { - printk(KERN_INFO "dos_read: MFM_TRACK %d, %d\n", hdr.track, - unit[drive].track/unit[drive].type->heads); - return MFM_TRACK; - } - - if (hdr.side != unit[drive].track%unit[drive].type->heads) { - printk(KERN_INFO "dos_read: MFM_SIDE %d, %d\n", hdr.side, - unit[drive].track%unit[drive].type->heads); - return MFM_TRACK; - } - - if (hdr.len_desc != 2) { - printk(KERN_INFO "dos_read: unknown sector len descriptor %d\n", hdr.len_desc); - return MFM_DATA; - } + if (crc != hdr.crc) { + printk(KERN_INFO "dos_read: MFM_HEADER %04x,%04x\n", + hdr.crc, crc); + return MFM_HEADER; + } + if (hdr.track != unit[drive].track/unit[drive].type->heads) { + printk(KERN_INFO "dos_read: MFM_TRACK %d, %d\n", + hdr.track, + unit[drive].track/unit[drive].type->heads); + return MFM_TRACK; + } + + if (hdr.side != unit[drive].track%unit[drive].type->heads) { + printk(KERN_INFO "dos_read: MFM_SIDE %d, %d\n", + hdr.side, + unit[drive].track%unit[drive].type->heads); + return MFM_TRACK; + } + + if (hdr.len_desc != 2) { + printk(KERN_INFO "dos_read: unknown sector len " + "descriptor %d\n", hdr.len_desc); + return MFM_DATA; + } #ifdef DEBUG - printk("hdr accepted\n"); + printk("hdr accepted\n"); #endif - if (!(raw = scan_sync (raw, end))) { - printk(KERN_INFO "dos_read: no data sync on track %d, unit %d for sector%d, disk sector %d\n", - unit[drive].track, drive, scnt, hdr.sec); - return MFM_NOSYNC; - } + if (!(raw = scan_sync (raw, end))) { + printk(KERN_INFO "dos_read: no data sync on track " + "%d, unit %d for sector%d, disk sector %d\n", + unit[drive].track, drive, scnt, hdr.sec); + return MFM_NOSYNC; + } #ifdef DEBUG - dbg(raw); + dbg(raw); #endif - if (*((ushort *)raw)!=0x5545) { - printk(KERN_INFO "dos_read: no data mark after sync (%d,%d,%d,%d) sc=%d\n", - hdr.track,hdr.side,hdr.sec,hdr.len_desc,scnt); - return MFM_NOSYNC; - } - - raw+=2; /* skip data mark (included in checksum) */ - raw = dos_decode((unsigned char *)(unit[drive].trackbuf + (hdr.sec - 1) * 512), (ushort *) raw, 512); - raw = dos_decode((unsigned char *)data_crc,(ushort *) raw,4); - crc = dos_data_crc(unit[drive].trackbuf + (hdr.sec - 1) * 512); - - if (crc != data_crc[0]) { - printk(KERN_INFO "dos_read: MFM_DATA (%d,%d,%d,%d) sc=%d, %x %x\n", - hdr.track, hdr.side, hdr.sec, hdr.len_desc, - scnt,data_crc[0], crc); - printk(KERN_INFO "data=(%lx,%lx,%lx,%lx,...)\n", - ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[0], - ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[1], - ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[2], - ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[3]); - return MFM_DATA; - } - } - return 0; + if (*((ushort *)raw)!=0x5545) { + printk(KERN_INFO "dos_read: no data mark after " + "sync (%d,%d,%d,%d) sc=%d\n", + hdr.track,hdr.side,hdr.sec,hdr.len_desc,scnt); + return MFM_NOSYNC; + } + + raw+=2; /* skip data mark (included in checksum) */ + raw = dos_decode((unsigned char *)(unit[drive].trackbuf + (hdr.sec - 1) * 512), (ushort *) raw, 512); + raw = dos_decode((unsigned char *)data_crc,(ushort *) raw,4); + crc = dos_data_crc(unit[drive].trackbuf + (hdr.sec - 1) * 512); + + if (crc != data_crc[0]) { + printk(KERN_INFO "dos_read: MFM_DATA (%d,%d,%d,%d) " + "sc=%d, %x %x\n", hdr.track, hdr.side, + hdr.sec, hdr.len_desc, scnt,data_crc[0], crc); + printk(KERN_INFO "data=(%lx,%lx,%lx,%lx,...)\n", + ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[0], + ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[1], + ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[2], + ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[3]); + return MFM_DATA; + } + } + return 0; } static inline ushort dos_encode_byte(unsigned char byte) { -register unsigned char *enc, b2, b1; -register ushort word; + register unsigned char *enc, b2, b1; + register ushort word; -enc=mfmencode; -b1=byte; -b2=b1>>4; -b1&=15; -word=enc[b2] <<8 | enc [b1]; -return (word|((word&(256|64)) ? 0: 128)); + enc=mfmencode; + b1=byte; + b2=b1>>4; + b1&=15; + word=enc[b2] <<8 | enc [b1]; + return (word|((word&(256|64)) ? 0: 128)); } static void dos_encode_block(ushort *dest, unsigned char *src, int len) { -int i; + int i; -for (i = 0; i < len; i++) { - *dest=dos_encode_byte(*src++); - *dest|=((dest[-1]&1)||(*dest&0x4000))? 0: 0x8000; - dest++; -} + for (i = 0; i < len; i++) { + *dest=dos_encode_byte(*src++); + *dest|=((dest[-1]&1)||(*dest&0x4000))? 0: 0x8000; + dest++; + } } static unsigned long *ms_putsec(int drive, unsigned long *raw, int cnt) { -static struct dos_header hdr={0,0,0,2,0, - {78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}}; -int i; -static ushort crc[2]={0,0x4e4e}; + static struct dos_header hdr={0,0,0,2,0, + {78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}}; + int i; + static ushort crc[2]={0,0x4e4e}; -drive&=3; + drive&=3; /* id gap 1 */ /* the MFM word before is always 9254 */ -for(i=0;i<6;i++) - *raw++=0xaaaaaaaa; + for(i=0;i<6;i++) + *raw++=0xaaaaaaaa; /* 3 sync + 1 headermark */ -*raw++=0x44894489; -*raw++=0x44895554; + *raw++=0x44894489; + *raw++=0x44895554; /* fill in the variable parts of the header */ -hdr.track=unit[drive].track/unit[drive].type->heads; -hdr.side=unit[drive].track%unit[drive].type->heads; -hdr.sec=cnt+1; -hdr.crc=dos_hdr_crc(&hdr); + hdr.track=unit[drive].track/unit[drive].type->heads; + hdr.side=unit[drive].track%unit[drive].type->heads; + hdr.sec=cnt+1; + hdr.crc=dos_hdr_crc(&hdr); /* header (without "magic") and id gap 2*/ -dos_encode_block((ushort *)raw,(unsigned char *) &hdr.track,28); -raw+=14; + dos_encode_block((ushort *)raw,(unsigned char *) &hdr.track,28); + raw+=14; /*id gap 3 */ -for(i=0;i<6;i++) - *raw++=0xaaaaaaaa; + for(i=0;i<6;i++) + *raw++=0xaaaaaaaa; /* 3 syncs and 1 datamark */ -*raw++=0x44894489; -*raw++=0x44895545; + *raw++=0x44894489; + *raw++=0x44895545; /* data */ -dos_encode_block((ushort *)raw,(unsigned char *)unit[drive].trackbuf+cnt*512,512); -raw+=256; + dos_encode_block((ushort *)raw, + (unsigned char *)unit[drive].trackbuf+cnt*512,512); + raw+=256; /*data crc + jd's special gap (long words :-/) */ -crc[0]=dos_data_crc(unit[drive].trackbuf+cnt*512); -dos_encode_block((ushort *) raw,(unsigned char *)crc,4); -raw+=2; + crc[0]=dos_data_crc(unit[drive].trackbuf+cnt*512); + dos_encode_block((ushort *) raw,(unsigned char *)crc,4); + raw+=2; /* data gap */ -for(i=0;i<38;i++) - *raw++=0x92549254; + for(i=0;i<38;i++) + *raw++=0x92549254; -return raw; /* wrote 652 MFM words */ + return raw; /* wrote 652 MFM words */ } static void dos_write(int disk) { -int cnt; -unsigned long raw = (unsigned long) raw_buf; -unsigned long *ptr=(unsigned long *)raw; + int cnt; + unsigned long raw = (unsigned long) raw_buf; + unsigned long *ptr=(unsigned long *)raw; -disk&=3; + disk&=3; /* really gap4 + indexgap , but we write it first and round it up */ -for (cnt=0;cnt<425;cnt++) - *ptr++=0x92549254; + for (cnt=0;cnt<425;cnt++) + *ptr++=0x92549254; /* the following is just guessed */ -if (unit[disk].type->sect_mult==2) /* check for HD-Disks */ - for(cnt=0;cnt<473;cnt++) - *ptr++=0x92549254; + if (unit[disk].type->sect_mult==2) /* check for HD-Disks */ + for(cnt=0;cnt<473;cnt++) + *ptr++=0x92549254; /* now the index marks...*/ -for (cnt=0;cnt<20;cnt++) - *ptr++=0x92549254; -for (cnt=0;cnt<6;cnt++) - *ptr++=0xaaaaaaaa; -*ptr++=0x52245224; -*ptr++=0x52245552; -for (cnt=0;cnt<20;cnt++) - *ptr++=0x92549254; + for (cnt=0;cnt<20;cnt++) + *ptr++=0x92549254; + for (cnt=0;cnt<6;cnt++) + *ptr++=0xaaaaaaaa; + *ptr++=0x52245224; + *ptr++=0x52245552; + for (cnt=0;cnt<20;cnt++) + *ptr++=0x92549254; /* sectors */ -for(cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++) - ptr=ms_putsec(disk,ptr,cnt); + for(cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++) + ptr=ms_putsec(disk,ptr,cnt); -*(ushort *)ptr = 0xaaa8; /* MFM word before is always 0x9254 */ + *(ushort *)ptr = 0xaaa8; /* MFM word before is always 0x9254 */ } /* @@ -1299,37 +1308,38 @@ static int non_int_flush_track (unsigned long nr) { -unsigned long flags; + unsigned long flags; - nr&=3; - writefromint = 0; - del_timer(&post_write_timer); - get_fdc(nr); - if (!fd_motor_on(nr)) { - writepending = 0; - rel_fdc(); - return 0; - } - save_flags(flags); - cli(); - if (writepending != 2) { - restore_flags(flags); - (*unit[nr].dtype->write_fkt)(nr); - if (!raw_write(nr)) { - printk (KERN_NOTICE "floppy disk write protected in write!\n"); - writepending = 0; - return 0; - } - while (block_flag == 2) - sleep_on (&wait_fd_block); - } - else { - restore_flags(flags); - ms_delay(2); /* 2 ms post_write delay */ - post_write(nr); - } - rel_fdc(); - return 1; + nr&=3; + writefromint = 0; + del_timer(&post_write_timer); + get_fdc(nr); + if (!fd_motor_on(nr)) { + writepending = 0; + rel_fdc(); + return 0; + } + save_flags(flags); + cli(); + if (writepending != 2) { + restore_flags(flags); + (*unit[nr].dtype->write_fkt)(nr); + if (!raw_write(nr)) { + printk (KERN_NOTICE "floppy disk write protected " + "in write!\n"); + writepending = 0; + return 0; + } + while (block_flag == 2) + sleep_on (&wait_fd_block); + } + else { + restore_flags(flags); + ms_delay(2); /* 2 ms post_write delay */ + post_write(nr); + } + rel_fdc(); + return 1; } static int get_track(int drive, int track) @@ -1379,7 +1389,7 @@ return; } - repeat: + repeat: if (!CURRENT) { /* Nothing left to do */ return; @@ -1406,11 +1416,12 @@ floppy = unit + drive; } - /* Here someone could investigate to be more efficient */ + /* Here someone could investigate to be more efficient */ for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) { #ifdef DEBUG - printk("fd: sector %ld + %d requested for %s\n",CURRENT->sector,cnt, - (CURRENT->cmd==READ)?"read":"write"); + printk("fd: sector %ld + %d requested for %s\n", + CURRENT->sector,cnt, + (CURRENT->cmd==READ)?"read":"write"); #endif block = CURRENT->sector + cnt; if ((int)block > floppy->blocks) { @@ -1422,8 +1433,8 @@ sector = block % (floppy->dtype->sects * floppy->type->sect_mult); data = CURRENT->buffer + 512 * cnt; #ifdef DEBUG - printk("access to track %d, sector %d, with buffer at 0x%08lx\n", - track, sector, data); + printk("access to track %d, sector %d, with buffer at " + "0x%08lx\n", track, sector, data); #endif if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) { @@ -1437,11 +1448,11 @@ } switch (CURRENT->cmd) { - case READ: + case READ: memcpy(data, unit[drive].trackbuf + sector * 512, 512); break; - case WRITE: + case WRITE: memcpy(unit[drive].trackbuf + sector * 512, data, 512); /* keep the drive spinning while writes are scheduled */ @@ -1494,7 +1505,7 @@ loc.cylinders = unit[drive].type->tracks; loc.start = 0; if (copy_to_user((void *)param, (void *)&loc, - sizeof(struct hd_geometry))) + sizeof(struct hd_geometry))) return -EFAULT; break; } @@ -1545,10 +1556,10 @@ getprm.sect=unit[drive].dtype->sects * unit[drive].type->sect_mult; getprm.size=unit[drive].blocks; if (copy_to_user((void *)param, - (void *)&getprm, - sizeof(struct floppy_struct))) + (void *)&getprm, + sizeof(struct floppy_struct))) return -EFAULT; - break; + break; case BLKGETSIZE: return put_user(unit[drive].blocks,(long *)param); break; @@ -1562,13 +1573,14 @@ #ifdef RAW_IOCTL case IOCTL_RAW_TRACK: if (copy_to_user((void *)param, raw_buf, - unit[drive].type->read_size)) + unit[drive].type->read_size)) return -EFAULT; else return unit[drive].type->read_size; #endif default: - printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.",cmd,drive); + printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.", + cmd, drive); return -ENOSYS; } return 0; @@ -1589,8 +1601,8 @@ break; if (type >= num_dr_types) { - printk(KERN_WARNING "fd_probe: unsupported drive type %08lx found\n", - code); + printk(KERN_WARNING "fd_probe: unsupported drive type " + "%08lx found\n", code); unit[drive].type = &drive_types[num_dr_types-1]; /* FD_NODRIVE */ return; } @@ -1611,93 +1623,93 @@ */ static int floppy_open(struct inode *inode, struct file *filp) { - int drive; - int old_dev; - int system; - unsigned long flags; - - drive = MINOR(inode->i_rdev) & 3; - old_dev = fd_device[drive]; - - if (fd_ref[drive]) - if (old_dev != inode->i_rdev) - return -EBUSY; - - if (unit[drive].type->code == FD_NODRIVE) - return -ENODEV; - - if (filp && filp->f_mode & 3) { - check_disk_change(inode->i_rdev); - if (filp->f_mode & 2 ) { - int wrprot; - - get_fdc(drive); - fd_select (drive); - wrprot = !(ciaa.pra & DSKPROT); - fd_deselect (drive); - rel_fdc(); - - if (wrprot) - return -EROFS; - } - } - - save_flags(flags); - cli(); - fd_ref[drive]++; - fd_device[drive] = inode->i_rdev; + int drive; + int old_dev; + int system; + unsigned long flags; + + drive = MINOR(inode->i_rdev) & 3; + old_dev = fd_device[drive]; + + if (fd_ref[drive]) + if (old_dev != inode->i_rdev) + return -EBUSY; + + if (unit[drive].type->code == FD_NODRIVE) + return -ENODEV; + + if (filp && filp->f_mode & 3) { + check_disk_change(inode->i_rdev); + if (filp->f_mode & 2 ) { + int wrprot; + + get_fdc(drive); + fd_select (drive); + wrprot = !(ciaa.pra & DSKPROT); + fd_deselect (drive); + rel_fdc(); + + if (wrprot) + return -EROFS; + } + } + + save_flags(flags); + cli(); + fd_ref[drive]++; + fd_device[drive] = inode->i_rdev; #ifdef MODULE - if (unit[drive].motor == 0) - MOD_INC_USE_COUNT; + if (unit[drive].motor == 0) + MOD_INC_USE_COUNT; #endif - restore_flags(flags); + restore_flags(flags); - if (old_dev && old_dev != inode->i_rdev) - invalidate_buffers(old_dev); + if (old_dev && old_dev != inode->i_rdev) + invalidate_buffers(old_dev); - system=(inode->i_rdev & 4)>>2; - unit[drive].dtype=&data_types[system]; - unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks* + system=(inode->i_rdev & 4)>>2; + unit[drive].dtype=&data_types[system]; + unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks* data_types[system].sects*unit[drive].type->sect_mult; - floppy_sizes[MINOR(inode->i_rdev)] = unit[drive].blocks >> 1; + floppy_sizes[MINOR(inode->i_rdev)] = unit[drive].blocks >> 1; - printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive, - unit[drive].type->name, data_types[system].name); + printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive, + unit[drive].type->name, data_types[system].name); - return 0; + return 0; } static int floppy_release(struct inode * inode, struct file * filp) { #ifdef DEBUG - struct super_block * sb; + struct super_block * sb; #endif - int drive = MINOR(inode->i_rdev) & 3; + int drive = MINOR(inode->i_rdev) & 3; - fsync_dev(inode->i_rdev); + fsync_dev(inode->i_rdev); #ifdef DEBUG - /* This is now handled in floppy_change, but still useful for debugging */ - sb = get_super(inode->i_rdev); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(inode->i_rdev); + /* This is now handled in floppy_change, but still useful for debugging */ + sb = get_super(inode->i_rdev); + if (sb) + invalidate_inodes(sb); + invalidate_buffers(inode->i_rdev); #endif - if (unit[drive].dirty == 1) { - del_timer (flush_track_timer + drive); - non_int_flush_track (drive); - } + if (unit[drive].dirty == 1) { + del_timer (flush_track_timer + drive); + non_int_flush_track (drive); + } - if (!fd_ref[drive]--) { - printk(KERN_CRIT "floppy_release with fd_ref == 0"); - fd_ref[drive] = 0; - } + if (!fd_ref[drive]--) { + printk(KERN_CRIT "floppy_release with fd_ref == 0"); + fd_ref[drive] = 0; + } #ifdef MODULE /* the mod_use counter is handled this way */ - floppy_off (drive | 0x40000000); + floppy_off (drive | 0x40000000); #endif - return 0; + return 0; } /* @@ -1769,23 +1781,23 @@ drives=0; nomem=0; for(drive=0;drivecode != FD_NODRIVE) { - drives++; - if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) { - printk("no mem for "); - unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */ - drives--; - nomem = 1; - } - printk("fd%d ",drive); - } + fd_probe(drive); + if (unit[drive].type->code != FD_NODRIVE) { + drives++; + if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) { + printk("no mem for "); + unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */ + drives--; + nomem = 1; + } + printk("fd%d ",drive); + } } if ((drives > 0) || (nomem == 0)) { - if (drives == 0) - printk("no drives"); - printk("\n"); - return drives; + if (drives == 0) + printk("no drives"); + printk("\n"); + return drives; } printk("\n"); return -ENOMEM; @@ -1793,85 +1805,87 @@ int __init amiga_floppy_init(void) { - int i; + int i; + + if (!AMIGAHW_PRESENT(AMI_FLOPPY)) + return -ENXIO; - if (!AMIGAHW_PRESENT(AMI_FLOPPY)) - return -ENXIO; - if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { - printk("fd: Unable to get major %d for floppy\n",MAJOR_NR); - return -EBUSY; - } - if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE)) == NULL) { - printk("fd: cannot get chip mem buffer\n"); - unregister_blkdev(MAJOR_NR,"fd"); - return -ENOMEM; - } - - if (request_irq(IRQ_FLOPPY, fd_block_done, 0, "floppy_dma", NULL) != 0) { - printk("fd: cannot get irq for dma\n"); - amiga_chip_free(raw_buf); - unregister_blkdev(MAJOR_NR,"fd"); - return -EBUSY; - } - if (request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL) != 0) { - printk("fd: cannot get irq for timer\n"); - free_irq(IRQ_FLOPPY, NULL); - amiga_chip_free(raw_buf); - unregister_blkdev(MAJOR_NR,"fd"); - return -EBUSY; - } - if (fd_probe_drives() < 1) { /* No usable drives */ - free_irq(IRQ_AMIGA_CIAA_TB, NULL); - free_irq(IRQ_FLOPPY, NULL); - amiga_chip_free(raw_buf); - unregister_blkdev(MAJOR_NR,"fd"); - return -ENXIO; - } - - /* initialize variables */ - motor_on_timer.next = NULL; - motor_on_timer.prev = NULL; - motor_on_timer.expires = 0; - motor_on_timer.data = 0; - motor_on_timer.function = motor_on_callback; - for (i = 0; i < FD_MAX_UNITS; i++) { - motor_off_timer[i].next = NULL; - motor_off_timer[i].prev = NULL; - motor_off_timer[i].expires = 0; - motor_off_timer[i].data = i|0x80000000; - motor_off_timer[i].function = fd_motor_off; - flush_track_timer[i].next = NULL; - flush_track_timer[i].prev = NULL; - flush_track_timer[i].expires = 0; - flush_track_timer[i].data = i; - flush_track_timer[i].function = flush_track_callback; - - unit[i].track = -1; - } - - post_write_timer.next = NULL; - post_write_timer.prev = NULL; - post_write_timer.expires = 0; - post_write_timer.data = 0; - post_write_timer.function = post_write; + if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { + printk("fd: Unable to get major %d for floppy\n",MAJOR_NR); + return -EBUSY; + } + + if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE)) == NULL) { + printk("fd: cannot get chip mem buffer\n"); + unregister_blkdev(MAJOR_NR,"fd"); + return -ENOMEM; + } + + if (!request_irq(IRQ_AMIGA_DSKBLK, fd_block_done, 0, "floppy_dma", NULL)) { + printk("fd: cannot get irq for dma\n"); + amiga_chip_free(raw_buf); + unregister_blkdev(MAJOR_NR,"fd"); + return -EBUSY; + } + if (!request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL)) { + printk("fd: cannot get irq for timer\n"); + free_irq(IRQ_AMIGA_DSKBLK, NULL); + amiga_chip_free(raw_buf); + unregister_blkdev(MAJOR_NR,"fd"); + return -EBUSY; + } + if (fd_probe_drives() < 1) { /* No usable drives */ + free_irq(IRQ_AMIGA_CIAA_TB, NULL); + free_irq(IRQ_AMIGA_DSKBLK, NULL); + amiga_chip_free(raw_buf); + unregister_blkdev(MAJOR_NR,"fd"); + return -ENXIO; + } + + /* initialize variables */ + motor_on_timer.next = NULL; + motor_on_timer.prev = NULL; + motor_on_timer.expires = 0; + motor_on_timer.data = 0; + motor_on_timer.function = motor_on_callback; + for (i = 0; i < FD_MAX_UNITS; i++) { + motor_off_timer[i].next = NULL; + motor_off_timer[i].prev = NULL; + motor_off_timer[i].expires = 0; + motor_off_timer[i].data = i|0x80000000; + motor_off_timer[i].function = fd_motor_off; + flush_track_timer[i].next = NULL; + flush_track_timer[i].prev = NULL; + flush_track_timer[i].expires = 0; + flush_track_timer[i].data = i; + flush_track_timer[i].function = flush_track_callback; + + unit[i].track = -1; + } + + post_write_timer.next = NULL; + post_write_timer.prev = NULL; + post_write_timer.expires = 0; + post_write_timer.data = 0; + post_write_timer.function = post_write; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_size[MAJOR_NR] = floppy_sizes; - - for (i = 0; i < 128; i++) - mfmdecode[i]=255; - for (i = 0; i < 16; i++) - mfmdecode[mfmencode[i]]=i; + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_size[MAJOR_NR] = floppy_sizes; + + for (i = 0; i < 128; i++) + mfmdecode[i]=255; + for (i = 0; i < 16; i++) + mfmdecode[mfmencode[i]]=i; - /* make sure that disk DMA is enabled */ - custom.dmacon = DMAF_SETCLR | DMAF_DISK; + /* make sure that disk DMA is enabled */ + custom.dmacon = DMAF_SETCLR | DMAF_DISK; - /* init ms timer */ - ciaa.crb = 8; /* one-shot, stop */ + /* init ms timer */ + ciaa.crb = 8; /* one-shot, stop */ - (void)do_floppy; /* avoid warning about unused variable */ - return 0; + (void)do_floppy; /* avoid warning about unused variable */ + return 0; } #ifdef MODULE @@ -1879,25 +1893,25 @@ int init_module(void) { - if (!MACH_IS_AMIGA) - return -ENXIO; - return amiga_floppy_init(); + if (!MACH_IS_AMIGA) + return -ENXIO; + return amiga_floppy_init(); } void cleanup_module(void) { -int i; + int i; -for( i = 0; i < FD_MAX_UNITS; i++) - if (unit[i].type->code != FD_NODRIVE) - kfree(unit[i].trackbuf); -free_irq(IRQ_AMIGA_CIAA_TB, NULL); -free_irq(IRQ_FLOPPY, NULL); -custom.dmacon = DMAF_DISK; /* disable DMA */ -amiga_chip_free(raw_buf); -blk_size[MAJOR_NR] = NULL; -blksize_size[MAJOR_NR] = NULL; -blk_dev[MAJOR_NR].request_fn = NULL; -unregister_blkdev(MAJOR_NR, "fd"); + for( i = 0; i < FD_MAX_UNITS; i++) + if (unit[i].type->code != FD_NODRIVE) + kfree(unit[i].trackbuf); + free_irq(IRQ_AMIGA_CIAA_TB, NULL); + free_irq(IRQ_AMIGA_DSKBLK, NULL); + custom.dmacon = DMAF_DISK; /* disable DMA */ + amiga_chip_free(raw_buf); + blk_size[MAJOR_NR] = NULL; + blksize_size[MAJOR_NR] = NULL; + blk_dev[MAJOR_NR].request_fn = NULL; + unregister_blkdev(MAJOR_NR, "fd"); } #endif diff -u --recursive --new-file v2.3.16/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.3.16/linux/drivers/block/floppy.c Tue Aug 17 10:48:20 1999 +++ linux/drivers/block/floppy.c Wed Sep 1 15:34:51 1999 @@ -4384,7 +4384,7 @@ } } -static void __init mod_setup(char *pattern, void (*setup)(char *)) +static void __init mod_setup(char *pattern, int (*setup)(char *)) { unsigned long i; char c; diff -u --recursive --new-file v2.3.16/linux/drivers/block/hpt366.c linux/drivers/block/hpt366.c --- v2.3.16/linux/drivers/block/hpt366.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/hpt366.c Tue Sep 7 11:23:40 1999 @@ -466,8 +466,8 @@ byte ata66 = 0; pci_read_config_byte(dev, 0x5a, &ata66); - if (dev->rom_address) - pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); + if (dev->resource[PCI_ROM_RESOURCE].start) + pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk("%s: reg5ah=0x%02x ATA-%s Cable Port%d\n", name, ata66, (ata66 & 0x02) ? "33" : "66", PCI_FUNC(dev->devfn)); return dev->irq; } diff -u --recursive --new-file v2.3.16/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.3.16/linux/drivers/block/ide-cd.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/ide-cd.c Thu Sep 2 13:08:19 1999 @@ -1247,20 +1247,10 @@ /* Figure out how much data to transfer. */ thislen = pc->buflen; - if (thislen < 0) thislen = -thislen; if (thislen > len) thislen = len; /* The drive wants to be written to. */ if ((ireason & 3) == 0) { - /* Check that we want to write. */ - if (pc->buflen > 0) { - printk ("%s: cdrom_pc_intr: Drive wants " - "to transfer data the wrong way!\n", - drive->name); - pc->stat = 1; - thislen = 0; - } - /* Transfer the data. */ atapi_output_bytes (drive, pc->buffer, thislen); @@ -1274,19 +1264,11 @@ /* Keep count of how much data we've moved. */ pc->buffer += thislen; - pc->buflen += thislen; + pc->buflen -= thislen; } /* Same drill for reading. */ else if ((ireason & 3) == 2) { - /* Check that we want to read. */ - if (pc->buflen < 0) { - printk ("%s: cdrom_pc_intr: Drive wants to " - "transfer data the wrong way!\n", - drive->name); - pc->stat = 1; - thislen = 0; - } /* Transfer the data. */ atapi_input_bytes (drive, pc->buffer, thislen); @@ -1333,11 +1315,8 @@ struct cdrom_info *info = drive->driver_data; info->dma = 0; - - len = pc->buflen; - if (len < 0) len = -len; - pc->stat = 0; + len = pc->buflen; /* Start sending the command to the drive. */ cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation); @@ -1794,10 +1773,13 @@ toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track); /* Now try to get the total cdrom capacity. */ +#if 0 stat = cdrom_get_last_written(MKDEV(HWIF(drive)->major, drive->select.b.unit << PARTN_BITS), (long *)&toc->capacity); - if (stat) stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf); + if (stat) +#endif + stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf); if (stat) toc->capacity = 0x1fffff; HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] @@ -1863,7 +1845,7 @@ pc.sense_data = reqbuf; pc.buffer = buf; - pc.buflen = - buflen; + pc.buflen = buflen; pc.c[0] = GPCMD_MODE_SELECT_10; pc.c[1] = 0x10; pc.c[2] = pageno; @@ -2048,7 +2030,6 @@ return cgc->stat; } - static int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi, unsigned int cmd, unsigned long arg) @@ -2977,11 +2958,3 @@ MOD_DEC_USE_COUNT; return 0; } - - -/*==========================================================================*/ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.3.16/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.3.16/linux/drivers/block/ll_rw_blk.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/ll_rw_blk.c Sat Sep 4 13:07:19 1999 @@ -26,6 +26,14 @@ #include /* + * MAC Floppy IWM hooks + */ + +#ifdef CONFIG_MAC_FLOPPY_IWM +extern int mac_floppy_init(void); +#endif + +/* * The request-struct contains all necessary data * to load a nr of sectors into memory */ @@ -809,6 +817,9 @@ #endif #ifdef CONFIG_MAC_FLOPPY swim3_init(); +#endif +#ifdef CONFIG_BLK_DEV_SWIM_IOP + swimiop_init(); #endif #ifdef CONFIG_AMIGA_FLOPPY amiga_floppy_init(); diff -u --recursive --new-file v2.3.16/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.3.16/linux/drivers/block/loop.c Mon Jul 12 07:49:36 1999 +++ linux/drivers/block/loop.c Wed Sep 1 15:12:31 1999 @@ -21,6 +21,10 @@ * Make real block number available to downstream transfer functions, enables * CBC (and relatives) mode encryption requiring unique IVs per data block. * Reed H. Petty, rhp@draper.net + * + * Maximum number of loop devices now dynamic via max_loop module parameter. + * Still fixed at 8 devices when compiled into the kernel normally. + * Russell Kroll 19990701 * * Still To Fix: * - Advisory locking is ignored here. @@ -61,10 +65,11 @@ #define TIMEOUT_VALUE (6 * HZ) #include -#define MAX_LOOP 8 -static struct loop_device loop_dev[MAX_LOOP]; -static int loop_sizes[MAX_LOOP]; -static int loop_blksizes[MAX_LOOP]; +#include +static int max_loop = 8; +static struct loop_device *loop_dev; +static int *loop_sizes; +static int *loop_blksizes; #define FALSE 0 #define TRUE (!FALSE) @@ -169,7 +174,7 @@ INIT_REQUEST; current_request=CURRENT; CURRENT=current_request->next; - if (MINOR(current_request->rq_dev) >= MAX_LOOP) + if (MINOR(current_request->rq_dev) >= max_loop) goto error_out; lo = &loop_dev[MINOR(current_request->rq_dev)]; if (!lo->lo_dentry || !lo->transfer) @@ -578,7 +583,7 @@ return -ENODEV; } dev = MINOR(inode->i_rdev); - if (dev >= MAX_LOOP) + if (dev >= max_loop) return -ENODEV; lo = &loop_dev[dev]; switch (cmd) { @@ -615,7 +620,7 @@ return -ENODEV; } dev = MINOR(inode->i_rdev); - if (dev >= MAX_LOOP) { + if (dev >= max_loop) { return -ENODEV; } lo = &loop_dev[dev]; @@ -640,7 +645,7 @@ return 0; } dev = MINOR(inode->i_rdev); - if (dev >= MAX_LOOP) + if (dev >= max_loop) return 0; err = fsync_dev(inode->i_rdev); lo = &loop_dev[dev]; @@ -674,6 +679,8 @@ */ #ifdef MODULE #define loop_init init_module +MODULE_PARM(max_loop, "i"); +MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)"); #endif int loop_register_transfer(struct loop_func_table *funcs) @@ -690,7 +697,7 @@ if ((unsigned)number >= MAX_LO_CRYPT) return -EINVAL; - for (lo = &loop_dev[0]; lo < &loop_dev[MAX_LOOP]; lo++) { + for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) { int type = lo->lo_encrypt_type; if (type == number) { xfer_funcs[type]->release(lo); @@ -714,17 +721,46 @@ MAJOR_NR); return -EIO; } + + if ((max_loop < 1) || (max_loop > 255)) { + printk (KERN_WARNING "loop: max_loop must be between 1 and 255\n"); + return -EINVAL; + } + #ifndef MODULE printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR); +#else + printk(KERN_INFO "loop: enabling %d loop devices\n", max_loop); #endif + loop_dev = kmalloc (max_loop * sizeof(struct loop_device), GFP_KERNEL); + if (!loop_dev) { + printk (KERN_ERR "loop: Unable to create loop_dev\n"); + return -ENOMEM; + } + + loop_sizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL); + if (!loop_sizes) { + printk (KERN_ERR "loop: Unable to create loop_sizes\n"); + kfree (loop_dev); + return -ENOMEM; + } + + loop_blksizes = kmalloc (max_loop * sizeof(int), GFP_KERNEL); + if (!loop_blksizes) { + printk (KERN_ERR "loop: Unable to create loop_blksizes\n"); + kfree (loop_dev); + kfree (loop_sizes); + return -ENOMEM; + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - for (i=0; i < MAX_LOOP; i++) { + for (i=0; i < max_loop; i++) { memset(&loop_dev[i], 0, sizeof(struct loop_device)); loop_dev[i].lo_number = i; } - memset(&loop_sizes, 0, sizeof(loop_sizes)); - memset(&loop_blksizes, 0, sizeof(loop_blksizes)); + memset(loop_sizes, 0, max_loop * sizeof(int)); + memset(loop_blksizes, 0, max_loop * sizeof(int)); blk_size[MAJOR_NR] = loop_sizes; blksize_size[MAJOR_NR] = loop_blksizes; @@ -736,5 +772,9 @@ { if (unregister_blkdev(MAJOR_NR, "loop") != 0) printk(KERN_WARNING "loop: cannot unregister blkdev\n"); + + kfree (loop_dev); + kfree (loop_sizes); + kfree (loop_blksizes); } #endif diff -u --recursive --new-file v2.3.16/linux/drivers/block/macide.c linux/drivers/block/macide.c --- v2.3.16/linux/drivers/block/macide.c Thu May 13 11:04:54 1999 +++ linux/drivers/block/macide.c Sat Sep 4 13:07:19 1999 @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -68,64 +68,16 @@ #define MAC_HD_ISR 0x101 - /* - * IDE interrupt glue - seems to be wired to Nubus, Slot C? - * (ROM code disassembly again) - * First try: just use Nubus interrupt for Slot C. Have Nubus code call - * a wrapper to ide_intr that checks the ISR (see above). - * Need to #define IDE_IRQ_NUBUS though. - * Alternative method: set a mac_ide_hook function pointer to the wrapper - * here and have via_do_nubus call that hook if set. - * - * Quadra needs the hook, Powerbook can use Nubus slot C. - * Checking the ISR on Quadra is done by mac_ack_intr (see Amiga code). mac_ide_intr - * mac_ide_intr is obsolete except for providing the hwgroup argument. - */ - - /* The Mac hwif data, for passing hwgroup to ide_intr */ -static ide_hwif_t *mac_hwif = NULL; - - /* The function pointer used in the Nubus handler */ -void (*mac_ide_intr_hook)(int, void *, struct pt_regs *) = NULL; - - /* - * Only purpose: feeds the hwgroup to the main IDE handler. - * Obsolete as soon as Nubus code is fixed WRT pseudo slot C int. - * (should be the case on Powerbooks) - * Alas, second purpose: feed correct irq to IDE handler (I know, - * that's cheating) :-((( - * Fix needed for interrupt code: accept Nubus ints in the regular - * request_irq code, then register Powerbook IDE as Nubus slot C, - * Quadra as slot F (F for fictious). - */ -void mac_ide_intr(int irq, void *dev_id, struct pt_regs *regs) -{ - ide_intr(mac_hwif->irq, mac_hwif->hwgroup, regs); -} - - /* - * Check the interrupt status - * - * Note: In 2.0 kernels, there have been timing problems with the - * Powerbook IDE interface (BUSY was asserted too long after the - * interrupt triggered). Result: repeated errors, recalibrate etc. - * Adding a wait loop to read_intr, write_intr and set_geom_intr - * fixed the problem (waits in read/write_intr were present for Amiga - * already). - * Powerbooks were not tested with 2.1 due to lack of FPU emulation - * (thanks Apple for using LC040). If the BUSY problem resurfaces in - * 2.1, my best bet would be to add the wait loop right here, afterr - * checking the interrupt register. - */ - -static int mac_ack_intr(ide_hwif_t *hwif) +static int mac_ack_intr(ide_hwif_t* hwif) { - unsigned char ch; + unsigned char isr; + isr = readb(MAC_HD_BASE + MAC_HD_ISR); + if (isr & (1<<5)) { + writeb(isr & ~(1<<5), MAC_HD_BASE + MAC_HD_ISR); + return 1; + } - ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]); - if (!(ch & 0x20)) return 0; - return 1; } /* @@ -134,34 +86,31 @@ void macide_init(void) { - hw_regs_t hw; - int index = -1; + hw_regs_t hw; + int index = -1; - if (MACH_IS_MAC) { - switch(macintosh_config->ide_type) { - case 0: - break; + if (!MACH_IS_MAC || macintosh_config->ide_type == 0) + return; + switch (macintosh_config->ide_type) { case MAC_IDE_QUADRA: - ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets, - 0, (ide_ioreg_t)(MAC_HD_BASE+MAC_HD_ISR), - mac_ack_intr, IRQ_MAC_NUBUS); - index = ide_register_hw(&hw, &mac_hwif); - mac_ide_intr_hook = mac_ide_intr; - break; + ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets, + 0, (ide_ioreg_t)(MAC_HD_BASE+MAC_HD_ISR), + mac_ack_intr, IRQ_NUBUS_F); + index = ide_register_hw(&hw, NULL); + break; default: ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets, - 0, 0, NULL, IRQ_MAC_NUBUS); - index = ide_register_hw(&hw, &mac_hwif); + 0, 0, NULL, IRQ_NUBUS_C); + index = ide_register_hw(&hw, NULL); break; } if (index != -1) { - if (macintosh_config->ide_type == MAC_IDE_QUADRA) - printk("ide%d: Macintosh Quadra IDE interface\n", index); - else - printk("ide%d: Macintosh Powerbook IDE interface\n", index); + if (macintosh_config->ide_type == MAC_IDE_QUADRA) + printk("ide%d: Macintosh Quadra IDE interface\n", index); + else + printk("ide%d: Macintosh Powerbook IDE interface\n", index); } - } } diff -u --recursive --new-file v2.3.16/linux/drivers/block/swim_iop.c linux/drivers/block/swim_iop.c --- v2.3.16/linux/drivers/block/swim_iop.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/swim_iop.c Sat Sep 4 13:07:19 1999 @@ -0,0 +1,674 @@ +/* + * Driver for the SWIM (Super Woz Integrated Machine) IOP + * floppy controller on the Macintosh IIfx and Quadra 900/950 + * + * Written by Joshua M. Thompson (funaho@jurai.org) + * based on the SWIM3 driver (c) 1996 by Paul Mackerras. + * + * 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. + * + * 1999-06-12 (jmt) - Initial implementation. + */ + +/* + * ------------------- + * Theory of Operation + * ------------------- + * + * Since the SWIM IOP is message-driven we implement a simple request queue + * system. One outstanding request may be queued at any given time (this is + * an IOP limitation); only when that request has completed can a new request + * be sent. + */ + +/* This has to be defined before some of the #includes below */ + +#define MAJOR_NR FLOPPY_MAJOR + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "Version 0.1 (1999-06-12)" + +#define MAX_FLOPPIES 4 + +#define IOCTL_MODE_BIT 8 +#define OPEN_WRITE_BIT 16 + +enum swim_state { + idle, + available, + revalidating, + transferring, + ejecting +}; + +struct floppy_state { + enum swim_state state; + int drive_num; /* device number */ + int secpercyl; /* disk geometry information */ + int secpertrack; + int total_secs; + int write_prot; /* 1 if write-protected, 0 if not, -1 dunno */ + int ref_count; + struct timer_list timeout; + int ejected; + struct wait_queue *wait; + int wanted; + int timeout_pending; +}; + +struct swim_iop_req { + int sent; + int complete; + __u8 command[32]; + struct floppy_state *fs; + void (*done)(struct swim_iop_req *); +}; + +static struct swim_iop_req *current_req; +static int floppy_count; + +static struct floppy_state floppy_states[MAX_FLOPPIES]; + +static int floppy_blocksizes[2] = {512,512}; +static int floppy_sizes[2] = {2880,2880}; + +static char *drive_names[7] = { + "not installed", /* DRV_NONE */ + "unknown (1)", /* DRV_UNKNOWN */ + "a 400K drive", /* DRV_400K */ + "an 800K drive" /* DRV_800K */ + "unknown (4)", /* ???? */ + "an FDHD", /* DRV_FDHD */ + "unknown (6)", /* ???? */ + "an Apple HD20" /* DRV_HD20 */ +}; + +int swimiop_init(void); +static void swimiop_init_request(struct swim_iop_req *); +static int swimiop_send_request(struct swim_iop_req *); +static void swimiop_receive(struct iop_msg *, struct pt_regs *); +static void swimiop_status_update(int, struct swim_drvstatus *); +static int swimiop_eject(struct floppy_state *fs); + +static ssize_t floppy_read(struct file *filp, char *buf, + size_t count, loff_t *ppos); +static ssize_t floppy_write(struct file *filp, const char *buf, + size_t count, loff_t *ppos); +static int floppy_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param); +static int floppy_open(struct inode *inode, struct file *filp); +static int floppy_release(struct inode *inode, struct file *filp); +static int floppy_check_change(kdev_t dev); +static int floppy_revalidate(kdev_t dev); +static int grab_drive(struct floppy_state *fs, enum swim_state state, + int interruptible); +static void release_drive(struct floppy_state *fs); +static void set_timeout(struct floppy_state *fs, int nticks, + void (*proc)(unsigned long)); +static void fd_request_timeout(unsigned long); +static void do_fd_request(void); +static void start_request(struct floppy_state *fs); + +static struct file_operations floppy_fops = { + NULL, /* lseek */ + floppy_read, /* read */ + floppy_write, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + floppy_ioctl, /* ioctl */ + NULL, /* mmap */ + floppy_open, /* open */ + NULL, /* flush */ + floppy_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + floppy_check_change, /* check_media_change */ + floppy_revalidate, /* revalidate */ +}; + +/* + * SWIM IOP initialization + */ + +int swimiop_init(void) +{ + volatile struct swim_iop_req req; + struct swimcmd_status *cmd = (struct swimcmd_status *) &req.command[0]; + struct swim_drvstatus *ds = &cmd->status; + struct floppy_state *fs; + int i; + + current_req = NULL; + floppy_count = 0; + + if (!iop_ism_present) return -ENODEV; + + if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { + printk(KERN_ERR "SWIM-IOP: Unable to get major %d for floppy\n", + MAJOR_NR); + return -EBUSY; + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_size[MAJOR_NR] = floppy_sizes; + + printk("SWIM-IOP: %s by Joshua M. Thompson (funaho@jurai.org)\n", + DRIVER_VERSION); + + if (iop_listen(SWIM_IOP, SWIM_CHAN, swimiop_receive, "SWIM") != 0) { + printk(KERN_ERR "SWIM-IOP: IOP channel already in use; can't initialize.\n"); + return -EBUSY; + } + + printk(KERN_ERR "SWIM_IOP: probing for installed drives.\n"); + + for (i = 0 ; i < MAX_FLOPPIES ; i++) { + memset(&floppy_states[i], 0, sizeof(struct floppy_state)); + fs = &floppy_states[floppy_count]; + + swimiop_init_request(&req); + cmd->code = CMD_STATUS; + cmd->drive_num = i + 1; + if (swimiop_send_request(&req) != 0) continue; + while (!req.complete); + if (cmd->error != 0) { + printk(KERN_ERR "SWIM-IOP: probe on drive %d returned error %d\n", i, (uint) cmd->error); + continue; + } + if (ds->installed != 0x01) continue; + printk("SWIM-IOP: drive %d is %s (%s, %s, %s, %s)\n", i, + drive_names[ds->info.type], + ds->info.external? "ext" : "int", + ds->info.scsi? "scsi" : "floppy", + ds->info.fixed? "fixed" : "removable", + ds->info.secondary? "secondary" : "primary"); + swimiop_status_update(floppy_count, ds); + fs->state = idle; + + init_timer(&fs->timeout); + floppy_count++; + } + printk("SWIM-IOP: detected %d installed drives.\n", floppy_count); + + do_floppy = NULL; + + return 0; +} + +static void swimiop_init_request(struct swim_iop_req *req) +{ + req->sent = 0; + req->complete = 0; + req->done = NULL; +} + +static int swimiop_send_request(struct swim_iop_req *req) +{ + unsigned long cpu_flags; + int err; + + /* It's doubtful an interrupt routine would try to send */ + /* a SWIM request, but I'd rather play it safe here. */ + + save_flags(cpu_flags); + cli(); + + if (current_req != NULL) { + restore_flags(cpu_flags); + return -ENOMEM; + } + + current_req = req; + + /* Interrupts should be back on for iop_send_message() */ + + restore_flags(cpu_flags); + + err = iop_send_message(SWIM_IOP, SWIM_CHAN, (void *) req, + sizeof(req->command), (__u8 *) &req->command[0], + swimiop_receive); + + /* No race condition here; we own current_req at this point */ + + if (err) { + current_req = NULL; + } else { + req->sent = 1; + } + return err; +} + +/* + * Receive a SWIM message from the IOP. + * + * This will be called in two cases: + * + * 1. A message has been successfully sent to the IOP. + * 2. An unsolicited message was received from the IOP. + */ + +void swimiop_receive(struct iop_msg *msg, struct pt_regs *regs) +{ + struct swim_iop_req *req; + struct swimmsg_status *sm; + struct swim_drvstatus *ds; + + req = current_req; + + switch(msg->status) { + case IOP_MSGSTATUS_COMPLETE: + memcpy(&req->command[0], &msg->reply[0], sizeof(req->command)); + req->complete = 1; + if (req->done) (*req->done)(req); + current_req = NULL; + break; + case IOP_MSGSTATUS_UNSOL: + sm = (struct swimmsg_status *) &msg->message[0]; + ds = &sm->status; + swimiop_status_update(sm->drive_num, ds); + iop_complete_message(msg); + break; + } +} + +static void swimiop_status_update(int drive_num, struct swim_drvstatus *ds) +{ + struct floppy_state *fs = &floppy_states[drive_num]; + + fs->write_prot = (ds->write_prot == 0x80); + if ((ds->disk_in_drive != 0x01) && (ds->disk_in_drive != 0x02)) { + fs->ejected = 1; + } else { + fs->ejected = 0; + } + switch(ds->info.type) { + case DRV_400K: + fs->secpercyl = 10; + fs->secpertrack = 10; + fs->total_secs = 800; + break; + case DRV_800K: + fs->secpercyl = 20; + fs->secpertrack = 10; + fs->total_secs = 1600; + break; + case DRV_FDHD: + fs->secpercyl = 36; + fs->secpertrack = 18; + fs->total_secs = 2880; + break; + default: + fs->secpercyl = 0; + fs->secpertrack = 0; + fs->total_secs = 0; + break; + } +} + +static int swimiop_eject(struct floppy_state *fs) +{ + int err, n; + struct swim_iop_req req; + struct swimcmd_eject *cmd = (struct swimcmd_eject *) &req.command[0]; + + err = grab_drive(fs, ejecting, 1); + if (err) return err; + + swimiop_init_request(&req); + cmd->code = CMD_EJECT; + cmd->drive_num = fs->drive_num; + err = swimiop_send_request(&req); + if (err) { + release_drive(fs); + return err; + } + for (n = 2*HZ; n > 0; --n) { + if (req.complete) break; + if (signal_pending(current)) { + err = -EINTR; + break; + } + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + release_drive(fs); + return cmd->error; +} + +static ssize_t floppy_read(struct file *filp, char *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + fs = &floppy_states[devnum]; + if (fs->ejected) + return -ENXIO; + return block_read(filp, buf, count, ppos); +} + +static ssize_t floppy_write(struct file * filp, const char * buf, + size_t count, loff_t *ppos) +{ + struct inode * inode = filp->f_dentry->d_inode; + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + check_disk_change(inode->i_rdev); + fs = &floppy_states[devnum]; + if (fs->ejected) + return -ENXIO; + if (fs->write_prot) + return -EROFS; + return block_write(filp, buf, count, ppos); +} + +static struct floppy_struct floppy_type = + { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */ + +static int floppy_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param) +{ + struct floppy_state *fs; + int err; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) || + ((cmd & 0x80) && !suser())) + return -EPERM; + + fs = &floppy_states[devnum]; + + switch (cmd) { + case FDEJECT: + if (fs->ref_count != 1) + return -EBUSY; + err = swimiop_eject(fs); + return err; + case FDGETPRM: + err = copy_to_user((void *) param, (void *) &floppy_type, + sizeof(struct floppy_struct)); + return err; + } + return -ENOIOCTLCMD; +} + +static int floppy_open(struct inode *inode, struct file *filp) +{ + struct floppy_state *fs; + int err; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + if (filp == 0) + return -EIO; + + fs = &floppy_states[devnum]; + err = 0; + if (fs->ref_count == -1 || filp->f_flags & O_EXCL) return -EBUSY; + + if (err == 0 && (filp->f_flags & O_NDELAY) == 0 + && (filp->f_mode & 3)) { + check_disk_change(inode->i_rdev); + if (fs->ejected) + err = -ENXIO; + } + + if (err == 0 && (filp->f_mode & 2)) { + if (fs->write_prot) + err = -EROFS; + } + + if (err) return err; + + if (filp->f_flags & O_EXCL) + fs->ref_count = -1; + else + ++fs->ref_count; + + /* Allow ioctls if we have write-permissions even if read-only open */ + if ((filp->f_mode & 2) || (permission(inode, 2) == 0)) + filp->f_mode |= IOCTL_MODE_BIT; + if (filp->f_mode & 2) + filp->f_mode |= OPEN_WRITE_BIT; + + return 0; +} + +static int floppy_release(struct inode *inode, struct file *filp) +{ + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + /* + * If filp is NULL, we're being called from blkdev_release + * or after a failed mount attempt. In the former case the + * device has already been sync'ed, and in the latter no + * sync is required. Otherwise, sync if filp is writable. + */ + if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT))) + block_fsync (filp, filp->f_dentry); + + fs = &floppy_states[devnum]; + if (fs->ref_count > 0) fs->ref_count--; + return 0; +} + +static int floppy_check_change(kdev_t dev) +{ + struct floppy_state *fs; + int devnum = MINOR(dev); + + if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) + return 0; + + fs = &floppy_states[devnum]; + return fs->ejected; +} + +static int floppy_revalidate(kdev_t dev) +{ + struct floppy_state *fs; + int devnum = MINOR(dev); + + if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) + return 0; + + fs = &floppy_states[devnum]; + + grab_drive(fs, revalidating, 0); + /* yadda, yadda */ + release_drive(fs); + + return 0; +} + +static void floppy_off(unsigned int nr) +{ +} + +static int grab_drive(struct floppy_state *fs, enum swim_state state, + int interruptible) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (fs->state != idle) { + ++fs->wanted; + while (fs->state != available) { + if (interruptible && signal_pending(current)) { + --fs->wanted; + restore_flags(flags); + return -EINTR; + } + interruptible_sleep_on(&fs->wait); + } + --fs->wanted; + } + fs->state = state; + restore_flags(flags); + return 0; +} + +static void release_drive(struct floppy_state *fs) +{ + unsigned long flags; + + save_flags(flags); + cli(); + fs->state = idle; + start_request(fs); + restore_flags(flags); +} + +static void set_timeout(struct floppy_state *fs, int nticks, + void (*proc)(unsigned long)) +{ + unsigned long flags; + + save_flags(flags); cli(); + if (fs->timeout_pending) + del_timer(&fs->timeout); + fs->timeout.expires = jiffies + nticks; + fs->timeout.function = proc; + fs->timeout.data = (unsigned long) fs; + add_timer(&fs->timeout); + fs->timeout_pending = 1; + restore_flags(flags); +} + +static void do_fd_request(void) +{ + int i; + + for (i = 0 ; i < floppy_count ; i++) { + start_request(&floppy_states[i]); + } +} + +static void fd_request_complete(struct swim_iop_req *req) +{ + struct floppy_state *fs = req->fs; + struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req->command[0]; + + del_timer(&fs->timeout); + fs->timeout_pending = 0; + fs->state = idle; + if (cmd->error) { + printk(KERN_ERR "SWIM-IOP: error %d on read/write request.\n", cmd->error); + end_request(0); + } else { + CURRENT->sector += cmd->num_blocks; + CURRENT->current_nr_sectors -= cmd->num_blocks; + if (CURRENT->current_nr_sectors <= 0) { + end_request(1); + return; + } + } + start_request(fs); +} + +static void fd_request_timeout(unsigned long data) +{ + struct floppy_state *fs = (struct floppy_state *) data; + + fs->timeout_pending = 0; + end_request(0); + fs->state = idle; +} + +static void start_request(struct floppy_state *fs) +{ + volatile struct swim_iop_req req; + struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req.command[0]; + + if (fs->state == idle && fs->wanted) { + fs->state = available; + wake_up(&fs->wait); + return; + } + while (CURRENT && fs->state == idle) { + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic(DEVICE_NAME ": request list destroyed"); + if (CURRENT->bh && !buffer_locked(CURRENT->bh)) + panic(DEVICE_NAME ": block not locked"); +#if 0 + printk("do_fd_req: dev=%x cmd=%d sec=%ld nr_sec=%ld buf=%p\n", + kdev_t_to_nr(CURRENT->rq_dev), CURRENT->cmd, + CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer); + printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n", + CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors); +#endif + + if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) { + end_request(0); + continue; + } + if (CURRENT->current_nr_sectors == 0) { + end_request(1); + continue; + } + if (fs->ejected) { + end_request(0); + continue; + } + + swimiop_init_request(&req); + req.fs = fs; + req.done = fd_request_complete; + + if (CURRENT->cmd == WRITE) { + if (fs->write_prot) { + end_request(0); + continue; + } + cmd->code = CMD_WRITE; + } else { + cmd->code = CMD_READ; + + } + cmd->drive_num = fs->drive_num; + cmd->buffer = CURRENT->buffer; + cmd->first_block = CURRENT->sector; + cmd->num_blocks = CURRENT->current_nr_sectors; + + if (swimiop_send_request(&req)) { + end_request(0); + continue; + } + + set_timeout(fs, HZ*CURRENT->current_nr_sectors, + fd_request_timeout); + + fs->state = transferring; + } +} diff -u --recursive --new-file v2.3.16/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.3.16/linux/drivers/cdrom/cdrom.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/cdrom/cdrom.c Thu Sep 2 13:08:19 1999 @@ -473,7 +473,8 @@ /* give people a warning shot, now that CDO_CHECK_TYPE is the default case! */ cdinfo(CD_OPEN, "bummer. wrong media type.\n"); - cdinfo(CD_WARNING, "pid %d is buggy!\n", (unsigned int)current->pid); + cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n", + (unsigned int)current->pid); ret=-EMEDIUMTYPE; goto clean_up_and_return; } @@ -835,7 +836,7 @@ case DVD_HOST_SEND_CHALLENGE: cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_CHALLENGE\n"); setup_send_key (&cgc, ai->hsc.agid, 1); - cgc.buflen = -(cgc.cmd[9] = 16); + cgc.buflen = cgc.cmd[9] = 16; buf[1] = 14; copy_chal (&buf[4], ai->hsc.chal); @@ -848,7 +849,7 @@ case DVD_HOST_SEND_KEY2: cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_KEY2\n"); setup_send_key (&cgc, ai->hsk.agid, 3); - cgc.buflen = -(cgc.cmd[9] = 12); + cgc.buflen = cgc.cmd[9] = 12; buf[1] = 10; copy_key (&buf[4], ai->hsk.key); @@ -1080,13 +1081,8 @@ cgc->cmd[0] = GPCMD_MODE_SELECT_10; cgc->cmd[1] = 0x10; /* PF */ - - /* generic_packet() wants the length as seen from the drive, i.e. - it will transfer data _to_ us. The CD-ROM wants the absolute - value, however. */ - cgc->cmd[7] = (-cgc->buflen) >> 8; - cgc->cmd[8] = (-cgc->buflen) & 0xff; - + cgc->cmd[7] = cgc->buflen >> 8; + cgc->cmd[8] = cgc->buflen & 0xff; return cdo->generic_packet(cdi, cgc); } @@ -1734,7 +1730,6 @@ memset(buffer, 0, 3); /* set volume */ - cgc.buflen = -cgc.buflen; cgc.buffer = buffer; return cdrom_mode_select(cdi, &cgc); } @@ -2234,12 +2229,3 @@ } #endif /* endif MODULE */ - - - -/* - * Local variables: - * comment-column: 40 - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cdrom.o cdrom.c" - * End: - */ diff -u --recursive --new-file v2.3.16/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.3.16/linux/drivers/char/Config.in Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/Config.in Thu Sep 2 10:02:32 1999 @@ -69,7 +69,9 @@ dep_tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE dep_tristate 'Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE dep_tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE - dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE + if [ "$CONFIG_PPC" = "y" ; then + dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE + fi fi tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE diff -u --recursive --new-file v2.3.16/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c --- v2.3.16/linux/drivers/char/amigamouse.c Mon Aug 2 09:54:29 1999 +++ linux/drivers/char/amigamouse.c Sat Sep 4 13:08:32 1999 @@ -58,7 +58,7 @@ #include "busmouse.h" -#if 0 +#if AMIGA_OLD_INT #define AMI_MSE_INT_ON() mouseint_allowed = 1 #define AMI_MSE_INT_OFF() mouseint_allowed = 0 static int mouseint_allowed; @@ -75,7 +75,7 @@ unsigned short joy0dat, potgor; -#if 0 +#if AMIGA_OLD_INT if(!mouseint_allowed) return; AMI_MSE_INT_OFF(); @@ -136,7 +136,7 @@ busmouse_add_movementbuttons(msedev, dx, -dy, buttons); -#if 0 +#if AMIGA_OLD_INT AMI_MSE_INT_ON(); #endif } @@ -148,7 +148,7 @@ static int release_mouse(struct inode * inode, struct file * file) { free_irq(IRQ_AMIGA_VERTB, mouse_interrupt); -#if 0 +#if AMIGA_OLD_INT AMI_MSE_INT_OFF(); #endif MOD_DEC_USE_COUNT; @@ -173,7 +173,7 @@ } MOD_INC_USE_COUNT; -#if 0 +#if AMIGA_OLD_INT AMI_MSE_INT_ON(); #endif return 0; @@ -189,7 +189,7 @@ return -ENODEV; custom.joytest = 0; /* reset counters */ -#if 0 +#if AMIGA_OLD_INT AMI_MSE_INT_OFF(); #endif msedev = register_busmouse(&amigamouse); @@ -200,15 +200,12 @@ return msedev < 0 ? msedev : 0; } -#ifdef MODULE - -int init_module(void) +void __exit amiga_mouse_exit(void) { - return amiga_mouse_init(); + unregister_busmouse(msedev); } -void cleanup_module(void) -{ - unregsiter_busmouse(msedev); -} +#ifdef MODULE +module_init(amiga_mouse_init) +module_exit(amiga_mouse_exit) #endif diff -u --recursive --new-file v2.3.16/linux/drivers/char/applicom.c linux/drivers/char/applicom.c --- v2.3.16/linux/drivers/char/applicom.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/applicom.c Thu Sep 2 10:19:06 1999 @@ -182,7 +182,7 @@ #endif /* MODULE */ -__initfunc(int applicom_init(void)) +int __init applicom_init(void) { int i, numisa=0; struct pci_dev *dev = NULL; diff -u --recursive --new-file v2.3.16/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c --- v2.3.16/linux/drivers/char/atarimouse.c Mon Aug 2 09:54:29 1999 +++ linux/drivers/char/atarimouse.c Sat Sep 4 13:08:32 1999 @@ -43,12 +43,12 @@ /* ikbd_mouse_disable(); */ - buttons = ((buf[0] & 1 ? 1 : 0) - | (buf[0] & 2 ? 4 : 0) + buttons = ((buf[0] & 1) + | ((buf[0] & 2) << 1) | (atari_mouse_buttons & 2)); atari_mouse_buttons = buttons; - busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons); + busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons ^ 7); /* ikbd_mouse_rel_pos(); */ } diff -u --recursive --new-file v2.3.16/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.3.16/linux/drivers/char/istallion.c Mon Aug 9 10:23:09 1999 +++ linux/drivers/char/istallion.c Thu Sep 2 11:22:40 1999 @@ -4,7 +4,7 @@ * istallion.c -- stallion intelligent multiport serial driver. * * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au). - * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). + * Copyright (C) 1994-1996 Greg Ungerer. * * This code is loosely based on the Linux serial driver, written by * Linus Torvalds, Theodore T'so and others. @@ -167,7 +167,7 @@ */ static char *stli_drvtitle = "Stallion Intelligent Multiport Serial Driver"; static char *stli_drvname = "istallion"; -static char *stli_drvversion = "5.5.1"; +static char *stli_drvversion = "5.6.0"; static char *stli_serialname = "ttyE"; static char *stli_calloutname = "cue"; @@ -186,7 +186,7 @@ * is already swapping a shared buffer won't make things any worse. */ static char *stli_tmpwritebuf = (char *) NULL; -static struct semaphore stli_tmpwritesem = MUTEX; +static DECLARE_MUTEX(stli_tmpwritesem); #define STLI_TXBUFSIZE 4096 @@ -3375,6 +3375,9 @@ portp->closing_wait = 30 * HZ; portp->tqhangup.routine = stli_dohangup; portp->tqhangup.data = portp; + init_waitqueue_head(&portp->open_wait); + init_waitqueue_head(&portp->close_wait); + init_waitqueue_head(&portp->raw_wait); portp->normaltermios = stli_deftermios; portp->callouttermios = stli_deftermios; panelport++; @@ -4671,16 +4674,16 @@ #if DEBUG printk("%s(%d): BAR[]=%x,%x,%x,%x\n", __FILE__, __LINE__, - devp->base_address[0], devp->base_address[1], - devp->base_address[2], devp->base_address[3]); + devp->resource[0].start, devp->resource[1].start, + devp->resource[2].start, devp->resource[3].start); #endif /* * We have all resources from the board, so lets setup the actual * board structure now. */ - brdp->iobase = (devp->base_address[3] & PCI_BASE_ADDRESS_IO_MASK); - brdp->memaddr = (devp->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK); + brdp->iobase = (devp->resource[3].start & PCI_BASE_ADDRESS_IO_MASK); + brdp->memaddr = (devp->resource[2].start & PCI_BASE_ADDRESS_MEM_MASK); stli_brdinit(brdp); return(0); diff -u --recursive --new-file v2.3.16/linux/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c --- v2.3.16/linux/drivers/char/n_r3964.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/n_r3964.c Thu Sep 2 09:24:11 1999 @@ -52,7 +52,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ #include @@ -221,7 +220,7 @@ #endif /* MODULE */ -__initfunc(static int r3964_init(void)) +static int __init r3964_init(void) { int status; diff -u --recursive --new-file v2.3.16/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.3.16/linux/drivers/char/serial.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/serial.c Wed Sep 1 15:34:01 1999 @@ -146,13 +146,12 @@ #ifdef MODVERSIONS #include #endif -#include #else /* !NEW_MODULES */ #ifdef MODVERSIONS #define MODULE #endif -#include #endif /* NEW_MODULES */ +#include #ifdef LOCAL_HEADERS #include "serial_local.h" diff -u --recursive --new-file v2.3.16/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.3.16/linux/drivers/char/stallion.c Thu Aug 5 14:34:02 1999 +++ linux/drivers/char/stallion.c Thu Sep 2 11:22:40 1999 @@ -4,7 +4,7 @@ * stallion.c -- stallion multiport serial driver. * * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au). - * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). + * Copyright (C) 1994-1996 Greg Ungerer. * * This code is loosely based on the Linux serial driver, written by * Linus Torvalds, Theodore T'so and others. @@ -135,7 +135,7 @@ */ static char *stl_drvtitle = "Stallion Multiport Serial Driver"; static char *stl_drvname = "stallion"; -static char *stl_drvversion = "5.5.1"; +static char *stl_drvversion = "5.6.0"; static char *stl_serialname = "ttyE"; static char *stl_calloutname = "cue"; @@ -2294,7 +2294,7 @@ break; } if (i >= stl_numintrs) { - if (request_irq(irq, stl_intr, SA_INTERRUPT, name, NULL) != 0) { + if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) { printk("STALLION: failed to register interrupt " "routine for %s irq=%d\n", name, irq); rc = -ENODEV; @@ -2348,6 +2348,8 @@ portp->callouttermios = stl_deftermios; portp->tqueue.routine = stl_offintr; portp->tqueue.data = portp; + init_waitqueue_head(&portp->open_wait); + init_waitqueue_head(&portp->close_wait); portp->stats.brd = portp->brdnr; portp->stats.panel = portp->panelnr; portp->stats.port = portp->portnr; @@ -2780,7 +2782,7 @@ #if DEBUG printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype, - dev->bus->number, dev->devfn); + devp->bus->number, devp->devfn); #endif if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) @@ -2798,8 +2800,8 @@ */ #if DEBUG printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__, - devp->base_address[0], devp->base_address[1], - devp->base_address[2], devp->base_address[3], devp->irq); + devp->resource[0].start, devp->resource[1].start, + devp->resource[2].start, devp->resource[3].start, devp->irq); #endif /* @@ -2808,21 +2810,21 @@ */ switch (brdtype) { case BRD_ECHPCI: - brdp->ioaddr2 = (devp->base_address[0] & + brdp->ioaddr2 = (devp->resource[0].start & PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr1 = (devp->base_address[1] & + brdp->ioaddr1 = (devp->resource[1].start & PCI_BASE_ADDRESS_IO_MASK); break; case BRD_ECH64PCI: - brdp->ioaddr2 = (devp->base_address[2] & + brdp->ioaddr2 = (devp->resource[2].start & PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr1 = (devp->base_address[1] & + brdp->ioaddr1 = (devp->resource[1].start & PCI_BASE_ADDRESS_IO_MASK); break; case BRD_EASYIOPCI: - brdp->ioaddr1 = (devp->base_address[2] & + brdp->ioaddr1 = (devp->resource[2].start & PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr2 = (devp->base_address[1] & + brdp->ioaddr2 = (devp->resource[1].start & PCI_BASE_ADDRESS_IO_MASK); break; default: @@ -4209,6 +4211,7 @@ if ((tty == (struct tty_struct *) NULL) || (tty->flip.char_buf_ptr == (char *) NULL) || ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { + len = MIN(len, sizeof(stl_unwanted)); outb((RDSR + portp->uartaddr), ioaddr); insb((ioaddr + EREG_DATA), &stl_unwanted[0], len); portp->stats.rxlost += len; @@ -5175,6 +5178,7 @@ if ((tty == (struct tty_struct *) NULL) || (tty->flip.char_buf_ptr == (char *) NULL) || ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { + len = MIN(len, sizeof(stl_unwanted)); outb(GRXFIFO, (ioaddr + XP_ADDR)); insb((ioaddr + XP_DATA), &stl_unwanted[0], len); portp->stats.rxlost += len; diff -u --recursive --new-file v2.3.16/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c --- v2.3.16/linux/drivers/i2o/i2o_block.c Thu Aug 5 15:04:52 1999 +++ linux/drivers/i2o/i2o_block.c Tue Sep 7 10:22:12 1999 @@ -17,10 +17,14 @@ * Fixes: * Steve Ralston: Multiple device handling error fixes, * Added a queue depth. - * - * Todo: - * 64bit cleanness. - * Remove the queue walk. We can do that better. + * 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 @@ -52,7 +56,7 @@ #define MAX_I2OB 16 -#define MAX_I2OB_DEPTH 8 +#define MAX_I2OB_DEPTH 32 /* * Some of these can be made smaller later @@ -80,6 +84,20 @@ }; /* + * FIXME: + * 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; +}; + + +/* * Each I2O disk is one of these. */ @@ -89,6 +107,8 @@ 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; #define DEBUG( s ) /* #define DEBUG( s ) printk( s ) @@ -112,13 +132,14 @@ * Turn a Linux block request into an I2O block read/write. */ -static int i2ob_send(u32 m, struct i2ob_device *dev, struct request *req, u32 base, int unit) +static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, u32 base, int unit) { struct i2o_controller *c = dev->controller; int tid = dev->tid; u32 *msg; u32 *mptr; u64 offset; + struct request *req = ireq->req; struct buffer_head *bh = req->bh; static int old_qd = 2; int count = req->nr_sectors<<9; @@ -130,7 +151,7 @@ msg = bus_to_virt(c->mem_offset + m); msg[2] = i2ob_context|(unit<<8); - msg[3] = (u32)req; /* 64bit issue again here */ + msg[3] = ireq->num; msg[5] = req->nr_sectors << 9; /* This can be optimised later - just want to be sure its right for @@ -147,7 +168,16 @@ msg[4] = 1<<16; while(bh!=NULL) { - *mptr++ = 0x10000000|(bh->b_size); + /* + * 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) + *mptr++ = 0x10000000|(bh->b_size); + else + *mptr++ = 0xD0000000|(bh->b_size); + *mptr++ = virt_to_bus(bh->b_data); count -= bh->b_size; bh = bh->b_reqnext; @@ -159,13 +189,15 @@ msg[4] = 1<<16; while(bh!=NULL) { - *mptr++ = 0x14000000|(bh->b_size); + if(bh->b_reqnext) + *mptr++ = 0x14000000|(bh->b_size); + else + *mptr++ = 0xD4000000|(bh->b_size); count -= bh->b_size; *mptr++ = virt_to_bus(bh->b_data); bh = bh->b_reqnext; } } - mptr[-2]|= 0xC0000000; msg[0] = I2O_MESSAGE_SIZE(mptr-msg) | SGL_OFFSET_8; if(req->current_nr_sectors > 8) @@ -187,29 +219,14 @@ /* * Remove a request from the _locked_ request list. We update both the - * list chain and if this is the last item the tail pointer. + * list chain and if this is the last item the tail pointer. Caller + * must hold the lock. */ -static void i2ob_unhook_request(struct i2ob_device *dev, struct request *req) +static inline void i2ob_unhook_request(struct i2ob_request *ireq) { - struct request **p = &dev->head; - struct request *nt = NULL; - static int crap = 0; - - while(*p!=NULL) - { - if(*p==req) - { - if(dev->tail==req) - dev->tail = nt; - *p=req->next; - return; - } - nt=*p; - p=&(nt->next); - } - if(!crap++) - printk("i2o_block: request queue corrupt!\n"); + ireq->next = i2ob_qhead; + i2ob_qhead = ireq; } /* @@ -223,12 +240,20 @@ * to this request have been marked updated and * unlocked. */ - while (end_that_request_first( req, !req->errors, "i2o block" )); + +// printk("ending request %p: ", req); + while (end_that_request_first( req, !req->errors, "i2o block" )) + { +// printk(" +\n"); + } /* * It is now ok to complete the request. */ + +// printk("finishing "); end_that_request_last( req ); +// printk("done\n"); } @@ -238,7 +263,7 @@ static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) { - struct request *req; + struct i2ob_request *ireq; u8 st; u32 *m = (u32 *)msg; u8 unit = (m[2]>>8)&0xF0; /* low 4 bits are partition */ @@ -265,7 +290,7 @@ /* We need to up the request failure count here and maybe abort it */ - req=(struct request *)m[3]; + ireq=&i2ob_queue[m[3]]; /* Now flush the message by making it a NOP */ m[0]&=0x00FFFFFF; m[0]|=(I2O_CMD_UTIL_NOP)<<24; @@ -288,7 +313,7 @@ * request in the context. */ - req=(struct request *)m[3]; + ireq=&i2ob_queue[m[3]]; st=m[4]>>24; if(st!=0) @@ -297,7 +322,7 @@ /* * Now error out the request block */ - req->errors++; + ireq->req->errors++; } } /* @@ -306,8 +331,8 @@ spin_lock(&io_request_lock); spin_lock(&i2ob_lock); - i2ob_unhook_request(&i2ob_dev[unit], req); - i2ob_end_request(req); + i2ob_unhook_request(ireq); + i2ob_end_request(ireq->req); /* * We may be able to do more I/O @@ -329,30 +354,6 @@ /* - * Flush all pending requests as errors. Must call with the queue - * locked. - */ - -#if 0 -static void i2ob_clear_queue(struct i2ob_device *dev) -{ - struct request *req; - - while (1) { - req = dev->tail; - if (!req) - return; - req->errors++; - i2ob_end_request(req); - - if (dev->tail == dev->head) - dev->head = NULL; - dev->tail = dev->tail->next; - } -} -#endif - -/* * The I2O block driver is listed as one of those that pulls the * front entry off the queue before processing it. This is important * to remember here. If we drop the io lock then CURRENT will change @@ -363,6 +364,7 @@ static void do_i2ob_request(void) { struct request *req; + struct i2ob_request *ireq; int unit; struct i2ob_device *dev; u32 m; @@ -400,15 +402,13 @@ req->errors = 0; CURRENT = CURRENT->next; req->next = NULL; + req->sem = NULL; + + ireq = i2ob_qhead; + i2ob_qhead = ireq->next; + ireq->req = req; - if (dev->head == NULL) { - dev->head = req; - dev->tail = req; - } else { - dev->tail->next = req; - dev->tail = req; - } - i2ob_send(m, dev, req, i2ob[unit].start_sect, (unit&0xF0)); + i2ob_send(m, dev, ireq, i2ob[unit].start_sect, (unit&0xF0)); } } @@ -727,8 +727,6 @@ i2ob_hardsizes[unit] = blocksize; i2ob_gendisk.part[unit].nr_sects = i2ob_sizes[unit]; - /* Setting this higher than 1024 breaks the symbios for some reason */ - limit=4096; /* 8 deep scatter gather */ printk("Byte limit is %d.\n", limit); @@ -962,7 +960,7 @@ { int i; - printk(KERN_INFO "I2O block device OSM v0.06. (C) 1999 Red Hat Software.\n"); + printk(KERN_INFO "I2O block device OSM v0.07. (C) 1999 Red Hat Software.\n"); /* * Register the block device interfaces @@ -1000,6 +998,20 @@ } /* + * Set up the queue + */ + + for(i = 0; i< MAX_I2OB_DEPTH; i++) + { + i2ob_queue[i].next = &i2ob_queue[i+1]; + i2ob_queue[i].num = i; + } + + /* Queue is MAX_I2OB + 1... */ + i2ob_queue[i].next = NULL; + i2ob_qhead = &i2ob_queue[0]; + + /* * Register the OSM handler as we will need this to probe for * drives, geometry and other goodies. */ @@ -1045,8 +1057,6 @@ */ if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0) printk("i2o_block: cleanup_module failed\n"); - else - printk("i2o_block: module cleaned up.\n"); /* * Why isnt register/unregister gendisk in the kernel ??? diff -u --recursive --new-file v2.3.16/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c --- v2.3.16/linux/drivers/i2o/i2o_core.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/i2o/i2o_core.c Tue Sep 7 10:22:12 1999 @@ -265,7 +265,7 @@ spin_lock(&i2o_configuration_lock); if(atomic_read(&c->users)) { - printk("Someones using controller iop%d\n", c->unit); + printk("Someone is using controller iop%d\n", c->unit); spin_unlock(&i2o_configuration_lock); return -EBUSY; } @@ -1058,7 +1058,7 @@ /* Wait for a reply */ time=jiffies; - + while(status_block[87]!=0xFF) { if((jiffies-time)>=5*HZ) diff -u --recursive --new-file v2.3.16/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c --- v2.3.16/linux/drivers/i2o/i2o_pci.c Fri Aug 6 11:16:54 1999 +++ linux/drivers/i2o/i2o_pci.c Tue Sep 7 10:22:12 1999 @@ -105,7 +105,7 @@ /* Skip I/O spaces */ if(!(dev->resource[i].flags&PCI_BASE_ADDRESS_SPACE)) { - memptr=dev->resource[i].flags; + memptr=dev->resource[i].start; break; } } @@ -113,14 +113,21 @@ if(i==6) { printk(KERN_ERR "i2o_pci: I2O controller has no memory regions defined.\n"); - return -ENOMEM; + kfree(c); + return -EINVAL; } size = dev->resource[i].end-dev->resource[i].start+1; /* Map the I2O controller */ - printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, -size); - mem = ioremap(memptr, -size); + printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, size); + mem = ioremap(memptr, size); + if(mem==NULL) + { + printk(KERN_ERR "i2o_pci: Unable to map controller.\n"); + kfree(c); + return -EINVAL; + } c->bus.pci.irq = -1; @@ -148,6 +155,8 @@ if(i<0) { printk(KERN_ERR "i2o: unable to install controller.\n"); + kfree(c); + iounmap(mem); return i; } @@ -165,7 +174,9 @@ core->delete(c); #else i2o_delete_controller(c); -#endif /* MODULE */ +#endif /* MODULE */ + kfree(c); + iounmap(mem); return -EBUSY; } } @@ -190,8 +201,7 @@ } printk(KERN_INFO "I2O controller on bus %d at %d.\n", dev->bus->number, dev->devfn); - if(!dev->master) - printk(KERN_WARNING "Controller not master enabled.\n"); + pci_set_master(dev); if(i2o_pci_install(dev)==0) count++; } @@ -247,6 +257,7 @@ if(c==NULL) continue; + if(c->type == I2O_TYPE_PCI) { #ifdef MODULE @@ -265,7 +276,6 @@ #endif continue; } - I2O_IRQ_WRITE32(c,0); } #ifdef MODULE diff -u --recursive --new-file v2.3.16/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c --- v2.3.16/linux/drivers/i2o/i2o_scsi.c Thu Aug 5 15:04:52 1999 +++ linux/drivers/i2o/i2o_scsi.c Thu Sep 2 10:02:32 1999 @@ -317,7 +317,7 @@ return 0; } -static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt) +void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt) { struct i2o_device *unit; struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata; diff -u --recursive --new-file v2.3.16/linux/drivers/i2o/i2o_scsi.h linux/drivers/i2o/i2o_scsi.h --- v2.3.16/linux/drivers/i2o/i2o_scsi.h Wed Jun 2 14:40:22 1999 +++ linux/drivers/i2o/i2o_scsi.h Tue Sep 7 10:22:12 1999 @@ -11,7 +11,7 @@ #include #define I2O_SCSI_ID 15 -#define I2O_SCSI_CAN_QUEUE 8 +#define I2O_SCSI_CAN_QUEUE 4 #define I2O_SCSI_CMD_PER_LUN 6 extern struct proc_dir_entry proc_scsi_i2o_scsi; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c --- v2.3.16/linux/drivers/isdn/eicon/eicon_mod.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/isdn/eicon/eicon_mod.c Wed Sep 1 15:35:22 1999 @@ -1275,8 +1275,8 @@ #define eicon_init init_module #endif -__initfunc(int -eicon_init(void)) +int __init +eicon_init(void) { int card_count = 0; int release = 0; @@ -1392,8 +1392,8 @@ str = get_options(line, 4, ints); #else -__initfunc(void -eicon_setup(char *str, int *ints)) +void __init +eicon_setup(char *str, int *ints) { int i, argc; #endif diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/amd7930.c linux/drivers/isdn/hisax/amd7930.c --- v2.3.16/linux/drivers/isdn/hisax/amd7930.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/amd7930.c Sat Sep 4 13:12:51 1999 @@ -749,8 +749,8 @@ return(0); } -__initfunc(int -setup_amd7930(struct IsdnCard *card)) +int __init +setup_amd7930(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c --- v2.3.16/linux/drivers/isdn/hisax/asuscom.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/asuscom.c Sat Sep 4 13:12:51 1999 @@ -326,8 +326,8 @@ return(0); } -__initfunc(int -setup_asuscom(struct IsdnCard *card)) +int __init +setup_asuscom(struct IsdnCard *card) { int bytecnt; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c --- v2.3.16/linux/drivers/isdn/hisax/avm_a1.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/avm_a1.c Sat Sep 4 13:12:51 1999 @@ -227,8 +227,8 @@ return(0); } -__initfunc(int -setup_avm_a1(struct IsdnCard *card)) +int __init +setup_avm_a1(struct IsdnCard *card) { u_char val; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/avm_a1p.c linux/drivers/isdn/hisax/avm_a1p.c --- v2.3.16/linux/drivers/isdn/hisax/avm_a1p.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/avm_a1p.c Sat Sep 4 13:12:51 1999 @@ -262,8 +262,8 @@ return 0; } -__initfunc(int -setup_avm_a1_pcmcia(struct IsdnCard *card)) +int __init +setup_avm_a1_pcmcia(struct IsdnCard *card) { u_char model, vers; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c --- v2.3.16/linux/drivers/isdn/hisax/avm_pci.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/avm_pci.c Sat Sep 4 13:12:51 1999 @@ -779,8 +779,8 @@ static int pci_index __initdata = 0; #endif -__initfunc(int -setup_avm_pcipnp(struct IsdnCard *card)) +int __init +setup_avm_pcipnp(struct IsdnCard *card) { u_int val, ver; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c --- v2.3.16/linux/drivers/isdn/hisax/bkm_a4t.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/isdn/hisax/bkm_a4t.c Sat Sep 4 13:12:51 1999 @@ -294,8 +294,8 @@ static int pci_index __initdata = 0; #endif -__initfunc(int - setup_bkm_a4t(struct IsdnCard *card)) +int __init + setup_bkm_a4t(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c --- v2.3.16/linux/drivers/isdn/hisax/bkm_a8.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/isdn/hisax/bkm_a8.c Sat Sep 4 13:12:51 1999 @@ -347,8 +347,8 @@ static int pci_index __initdata = 0; #endif -__initfunc(int - setup_sct_quadro(struct IsdnCard *card)) +int __init + setup_sct_quadro(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.3.16/linux/drivers/isdn/hisax/config.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/isdn/hisax/config.c Sat Sep 4 13:12:51 1999 @@ -571,8 +571,8 @@ str = get_options(line, MAX_ARG, ints); #else -__initfunc(void -HiSax_setup(char *str, int *ints)) +void __init +HiSax_setup(char *str, int *ints) { int i, j, argc; #endif @@ -1442,8 +1442,8 @@ } -__initfunc(int -HiSax_init(void)) +int __init +HiSax_init(void) { int i; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c --- v2.3.16/linux/drivers/isdn/hisax/diva.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/diva.c Sat Sep 4 13:12:51 1999 @@ -888,8 +888,8 @@ static int pci_index __initdata = 0; #endif -__initfunc(int -setup_diva(struct IsdnCard *card)) +int __init +setup_diva(struct IsdnCard *card) { int bytecnt; u_char val; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c --- v2.3.16/linux/drivers/isdn/hisax/gazel.c Thu Aug 26 13:05:35 1999 +++ linux/drivers/isdn/hisax/gazel.c Sat Sep 4 13:12:51 1999 @@ -690,8 +690,8 @@ return (0); } -__initfunc(int - setup_gazel(struct IsdnCard *card)) +int __init + setup_gazel(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c --- v2.3.16/linux/drivers/isdn/hisax/hfc_2bds0.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/hfc_2bds0.c Sat Sep 4 13:12:51 1999 @@ -1172,8 +1172,8 @@ #endif } -__initfunc(unsigned int -*init_send_hfcd(int cnt)) +unsigned int * __init +init_send_hfcd(int cnt) { int i, *send; @@ -1187,8 +1187,8 @@ return(send); } -__initfunc(void -init2bds0(struct IsdnCardState *cs)) +void __init +init2bds0(struct IsdnCardState *cs) { cs->setstack_d = setstack_hfcd; cs->dbusytimer.function = (void *) hfc_dbusy_timer; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c --- v2.3.16/linux/drivers/isdn/hisax/hfc_2bs0.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/hfc_2bs0.c Sat Sep 4 13:12:51 1999 @@ -559,8 +559,8 @@ return (0); } -__initfunc(void -init_send(struct BCState *bcs)) +void __init +init_send(struct BCState *bcs) { int i; @@ -573,8 +573,8 @@ bcs->hw.hfc.send[i] = 0x1fff; } -__initfunc(void -inithfc(struct IsdnCardState *cs)) +void __init +inithfc(struct IsdnCardState *cs) { init_send(&cs->bcs[0]); init_send(&cs->bcs[1]); diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.3.16/linux/drivers/isdn/hisax/hfc_pci.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/isdn/hisax/hfc_pci.c Sat Sep 4 13:12:51 1999 @@ -1513,8 +1513,8 @@ /*************************************/ /* Alloc memory send data for queues */ /*************************************/ -__initfunc(unsigned int - *init_send_hfcpci(int cnt)) +unsigned int * __init + init_send_hfcpci(int cnt) { int i, *send; @@ -1531,8 +1531,8 @@ /********************************/ /* called for card init message */ /********************************/ -__initfunc(void - inithfcpci(struct IsdnCardState *cs)) +void __init + inithfcpci(struct IsdnCardState *cs) { cs->setstack_d = setstack_hfcpci; cs->dbusytimer.function = (void *) hfcpci_dbusy_timer; @@ -1604,8 +1604,8 @@ #endif /* CONFIG_PCI */ -__initfunc(int - setup_hfcpci(struct IsdnCard *card)) +int __init + setup_hfcpci(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/hfcscard.c linux/drivers/isdn/hisax/hfcscard.c --- v2.3.16/linux/drivers/isdn/hisax/hfcscard.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/hfcscard.c Sat Sep 4 13:12:51 1999 @@ -148,8 +148,8 @@ return(0); } -__initfunc(int -setup_hfcs(struct IsdnCard *card)) +int __init +setup_hfcs(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.3.16/linux/drivers/isdn/hisax/hisax.h Thu Aug 26 13:05:35 1999 +++ linux/drivers/isdn/hisax/hisax.h Wed Sep 1 15:35:22 1999 @@ -1007,6 +1007,10 @@ #define __initdata #endif +#ifndef __init +#define __init +#endif + #define HISAX_INITFUNC(__arginit) __initfunc(__arginit) #define HISAX_INITDATA __initdata diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/isurf.c linux/drivers/isdn/hisax/isurf.c --- v2.3.16/linux/drivers/isdn/hisax/isurf.c Thu Aug 26 13:05:36 1999 +++ linux/drivers/isdn/hisax/isurf.c Sat Sep 4 13:12:51 1999 @@ -206,8 +206,8 @@ return(isar_auxcmd(cs, ic)); } -__initfunc(int -setup_isurf(struct IsdnCard *card)) +int __init +setup_isurf(struct IsdnCard *card) { int ver; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c --- v2.3.16/linux/drivers/isdn/hisax/ix1_micro.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/ix1_micro.c Sat Sep 4 13:12:51 1999 @@ -282,8 +282,8 @@ } -__initfunc(int -setup_ix1micro(struct IsdnCard *card)) +int __init +setup_ix1micro(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/mic.c linux/drivers/isdn/hisax/mic.c --- v2.3.16/linux/drivers/isdn/hisax/mic.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/mic.c Sat Sep 4 13:12:51 1999 @@ -224,8 +224,8 @@ return(0); } -__initfunc(int -setup_mic(struct IsdnCard *card)) +int __init +setup_mic(struct IsdnCard *card) { int bytecnt; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c --- v2.3.16/linux/drivers/isdn/hisax/netjet.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/netjet.c Sat Sep 4 13:12:51 1999 @@ -889,8 +889,8 @@ } -__initfunc(void -inittiger(struct IsdnCardState *cs)) +void __init +inittiger(struct IsdnCardState *cs) { if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int), GFP_KERNEL | GFP_DMA))) { @@ -1080,8 +1080,8 @@ static int pci_index __initdata = 0; #endif -__initfunc(int -setup_netjet(struct IsdnCard *card)) +int __init +setup_netjet(struct IsdnCard *card) { int bytecnt; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c --- v2.3.16/linux/drivers/isdn/hisax/niccy.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/niccy.c Sat Sep 4 13:12:51 1999 @@ -265,8 +265,8 @@ static int pci_index __initdata = 0; #endif -__initfunc(int -setup_niccy(struct IsdnCard *card)) +int __init +setup_niccy(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/s0box.c linux/drivers/isdn/hisax/s0box.c --- v2.3.16/linux/drivers/isdn/hisax/s0box.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/s0box.c Sat Sep 4 13:12:51 1999 @@ -212,8 +212,8 @@ return(0); } -__initfunc(int -setup_s0box(struct IsdnCard *card)) +int __init +setup_s0box(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/saphir.c linux/drivers/isdn/hisax/saphir.c --- v2.3.16/linux/drivers/isdn/hisax/saphir.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/saphir.c Sat Sep 4 13:12:51 1999 @@ -265,8 +265,8 @@ } -__initfunc(int -setup_saphir(struct IsdnCard *card)) +int __init +setup_saphir(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.3.16/linux/drivers/isdn/hisax/sedlbauer.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/isdn/hisax/sedlbauer.c Sat Sep 4 13:12:51 1999 @@ -549,8 +549,8 @@ #endif #endif -__initfunc(int -setup_sedlbauer(struct IsdnCard *card)) +int __init +setup_sedlbauer(struct IsdnCard *card) { int bytecnt, ver, val; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c --- v2.3.16/linux/drivers/isdn/hisax/sportster.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/sportster.c Sat Sep 4 13:12:51 1999 @@ -208,8 +208,8 @@ return(0); } -__initfunc(int -get_io_range(struct IsdnCardState *cs)) +int __init +get_io_range(struct IsdnCardState *cs) { int i, j, adr; @@ -234,8 +234,8 @@ } } -__initfunc(int -setup_sportster(struct IsdnCard *card)) +int __init +setup_sportster(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c --- v2.3.16/linux/drivers/isdn/hisax/teleint.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/teleint.c Sat Sep 4 13:12:51 1999 @@ -289,8 +289,8 @@ return(0); } -__initfunc(int -setup_TeleInt(struct IsdnCard *card)) +int __init +setup_TeleInt(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c --- v2.3.16/linux/drivers/isdn/hisax/teles0.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/teles0.c Sat Sep 4 13:12:51 1999 @@ -295,8 +295,8 @@ return(0); } -__initfunc(int -setup_teles0(struct IsdnCard *card)) +int __init +setup_teles0(struct IsdnCard *card) { u_char val; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c --- v2.3.16/linux/drivers/isdn/hisax/teles3.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/isdn/hisax/teles3.c Sat Sep 4 13:12:51 1999 @@ -321,8 +321,8 @@ return(0); } -__initfunc(int -setup_teles3(struct IsdnCard *card)) +int __init +setup_teles3(struct IsdnCard *card) { u_char val; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/telespci.c linux/drivers/isdn/hisax/telespci.c --- v2.3.16/linux/drivers/isdn/hisax/telespci.c Thu Aug 12 09:42:33 1999 +++ linux/drivers/isdn/hisax/telespci.c Sat Sep 4 13:12:51 1999 @@ -310,8 +310,8 @@ static int pci_index __initdata = 0; #endif -__initfunc(int -setup_telespci(struct IsdnCard *card)) +int __init +setup_telespci(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.16/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.16/linux/drivers/net/Config.in Thu Aug 26 13:05:37 1999 +++ linux/drivers/net/Config.in Sat Sep 4 13:11:36 1999 @@ -95,6 +95,10 @@ tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900 tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN + tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC + if [ "$CONFIG_ACENIC" != "n" ]; then + bool 'Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I + fi fi bool 'Other ISA cards' CONFIG_NET_ISA if [ "$CONFIG_NET_ISA" = "y" ]; then @@ -125,7 +129,6 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi diff -u --recursive --new-file v2.3.16/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.16/linux/drivers/net/Makefile Thu Aug 26 13:05:37 1999 +++ linux/drivers/net/Makefile Sat Sep 4 13:08:32 1999 @@ -412,6 +412,10 @@ endif endif +ifeq ($(CONFIG_SUN3LANCE),y) +L_OBJS += sun3lance.o +endif + ifeq ($(CONFIG_PCNET32),y) L_OBJS += pcnet32.o else diff -u --recursive --new-file v2.3.16/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.3.16/linux/drivers/net/Space.c Thu Aug 26 13:05:37 1999 +++ linux/drivers/net/Space.c Sat Sep 4 13:08:32 1999 @@ -93,6 +93,7 @@ extern int myri_sbus_probe(struct net_device *); extern int sgiseeq_probe(struct net_device *); extern int atarilance_probe(struct net_device *); +extern int sun3lance_probe(struct net_device *); extern int a2065_probe(struct net_device *); extern int ariadne_probe(struct net_device *); extern int ariadne2_probe(struct net_device *); @@ -409,6 +410,9 @@ struct devprobe m68k_probes[] __initdata = { #ifdef CONFIG_ATARILANCE /* Lance-based Atari ethernet boards */ {atarilance_probe, 0}, +#endif +#ifdef CONFIG_SUN3LANCE /* sun3 onboard Lance chip */ + {sun3lance_probe, 0}, #endif #ifdef CONFIG_A2065 /* Commodore/Ameristar A2065 Ethernet Board */ {a2065_probe, 0}, diff -u --recursive --new-file v2.3.16/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.3.16/linux/drivers/net/acenic.c Thu Aug 26 13:05:37 1999 +++ linux/drivers/net/acenic.c Sat Sep 4 13:11:36 1999 @@ -18,13 +18,12 @@ * (at your option) any later version. * * Additional work by Pete Wyckoff for initial - * Alpha and trace dump support. + * Alpha and trace dump support. The trace dump support has not been + * integrated yet however. */ -#define PKT_COPY_THRESHOLD 300 - +#include #include - #include #include #include @@ -36,6 +35,9 @@ #include #include #include +#ifdef ETHTOOL +#include +#endif #include #include @@ -45,16 +47,12 @@ #include #include -#include "acenic.h" - -/* - * These must be defined before the firmware is included. - */ -#define MAX_TEXT_LEN 96*1024 -#define MAX_RODATA_LEN 8*1024 -#define MAX_DATA_LEN 2*1024 -#include "acenic_firmware.h" +#ifdef CONFIG_ACENIC_OMIT_TIGON_I +#define ACE_IS_TIGON_I(ap) 0 +#else +#define ACE_IS_TIGON_I(ap) (ap->version == 1) +#endif #ifndef PCI_VENDOR_ID_ALTEON #define PCI_VENDOR_ID_ALTEON 0x12ae @@ -73,10 +71,32 @@ #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX #define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a #endif -#ifndef PCI_VENDOR_ID_SGI_ACENIC +#ifndef PCI_VENDOR_ID_SGI +#define PCI_VENDOR_ID_SGI 0x10a9 +#endif +#ifndef PCI_DEVICE_ID_SGI_ACENIC #define PCI_DEVICE_ID_SGI_ACENIC 0x0009 #endif +#ifndef wmb +#define wmb() mb() +#endif + +#if (LINUX_VERSION_CODE < 0x02030e) +#define net_device device +#endif + +#include "acenic.h" + +/* + * These must be defined before the firmware is included. + */ +#define MAX_TEXT_LEN 96*1024 +#define MAX_RODATA_LEN 8*1024 +#define MAX_DATA_LEN 2*1024 + +#include "acenic_firmware.h" + /* * This driver currently supports Tigon I and Tigon II based cards * including the Alteon AceNIC and the 3Com 3C985. The driver should @@ -146,6 +166,12 @@ * is available, on the 1/2MB NIC app. 300KB is available. * 68KB will always be available as a minimum for both * directions. The default value is a 50/50 split. + * dis_pci_mem_inval= - disable PCI memory write and invalidate + * operations, default (1) is to always disable this as + * that is what Alteon does on NT. I have not been able + * to measure any real performance differences with + * this on my systems. Set =0 if you want to + * enable these operations. * * If you use more than one NIC, specify the parameters for the * individual NICs with a comma, ie. trace=0,0x00001fff,0 you want to @@ -159,18 +185,98 @@ * * The mini ring is not used under Linux and I am not sure it makes sense * to actually use it. + * + * New interrupt handler strategy: + * + * The old interrupt handler worked using the traditional method of + * replacing an skbuff with a new one when a packet arrives. However + * the rx rings do not need to contain a static number of buffer + * descriptors, thus it makes sense to move the memory allocation out + * of the main interrupt handler and do it in a bottom half handler + * and only allocate new buffers when the number of buffers in the + * ring is below a certain threshold. In order to avoid starving the + * NIC under heavy load it is however necessary to force allocation + * when hitting a minimum threshold. The strategy for alloction is as + * follows: + * + * RX_LOW_BUF_THRES - allocate buffers in the bottom half + * RX_PANIC_LOW_THRES - we are very low on buffers, allocate + * the buffers in the interrupt handler + * RX_RING_THRES - maximum number of buffers in the rx ring + * RX_MINI_THRES - maximum number of buffers in the mini ring + * RX_JUMBO_THRES - maximum number of buffers in the jumbo ring + * + * One advantagous side effect of this allocation approach is that the + * entire rx processing can be done without holding any spin lock + * since the rx rings and registers are totally independant of the tx + * ring and its registers. This of course includes the kmalloc's of + * new skb's. Thus start_xmit can run in parallel with rx processing + * and the memory allocation on SMP systems. + * + * Note that running the skb reallocation in a bottom half opens up + * another can of races which needs to be handled properly. In + * particular it can happen that the interrupt handler tries to run + * the reallocation while the bottom half is either running on another + * CPU or was interrupted on the same CPU. To get around this the + * driver uses bitops to prevent the reallocation routines from being + * reentered. + * + * TX handling can also be done without holding any spin lock, wheee + * this is fun! since tx_ret_csm is only written to by the interrupt + * handler. The case to be aware of is when shutting down the device + * and cleaning up where it is necessary to make sure that + * start_xmit() is not running while this is happening. Well DaveM + * informs me that this case is already protected against ... bye bye + * Mr. Spin Lock, it was nice to know you. + * + * TX interrupts are now partly disabled so the NIC will only generate + * TX interrupts for the number of coal ticks, not for the number of + * TX packets in the queue. This should reduce the number of TX only, + * ie. when no RX processing is done, interrupts seen. */ /* - * Default values for tuning parameters + * Threshold values for RX buffer allocation - the low water marks for + * when to start refilling the rings are set to 75% of the ring + * sizes. It seems to make sense to refill the rings entirely from the + * intrrupt handler once it gets below the panic threshold, that way + * we don't risk that the refilling is moved to another CPU when the + * one running the interrupt handler just got the slab code hot in its + * cache. */ -#define DEF_TX_RATIO 31 -#define DEF_TX_COAL 1000 -#define DEF_TX_MAX_DESC 40 -#define DEF_RX_COAL 1000 -#define DEF_RX_MAX_DESC 20 -#define DEF_TRACE 0 -#define DEF_STAT 2 * TICKS_PER_SEC +#define RX_RING_SIZE 72 +#define RX_MINI_SIZE 64 +#define RX_JUMBO_SIZE 48 + +#define RX_PANIC_STD_THRES 16 +#define RX_PANIC_STD_REFILL (3*RX_PANIC_STD_THRES)/2 +#define RX_LOW_STD_THRES (3*RX_RING_SIZE)/4 +#define RX_PANIC_MINI_THRES 12 +#define RX_PANIC_MINI_REFILL (3*RX_PANIC_MINI_THRES)/2 +#define RX_LOW_MINI_THRES (3*RX_MINI_SIZE)/4 +#define RX_PANIC_JUMBO_THRES 6 +#define RX_PANIC_JUMBO_REFILL (3*RX_PANIC_JUMBO_THRES)/2 +#define RX_LOW_JUMBO_THRES (3*RX_JUMBO_SIZE)/4 + + +/* + * Size of the mini ring entries, basically these just should be big + * enough to take TCP ACKs + */ +#define ACE_MINI_SIZE 100 + +#define ACE_MINI_BUFSIZE (ACE_MINI_SIZE + 2 + 16) +#define ACE_STD_BUFSIZE (ACE_STD_MTU + ETH_HLEN + 2+4+16) +#define ACE_JUMBO_BUFSIZE (ACE_JUMBO_MTU + ETH_HLEN + 2+4+16) + +#define DEF_TX_RATIO 24 +#define DEF_TX_COAL 1000 +#define DEF_TX_MAX_DESC 40 +#define DEF_RX_COAL 1000 +#define DEF_RX_MAX_DESC 20 +#define TX_COAL_INTS_ONLY 0 /* seems not worth it */ +#define DEF_TRACE 0 +#define DEF_STAT 2 * TICKS_PER_SEC static int link[8] = {0, }; static int trace[8] = {0, }; @@ -179,25 +285,20 @@ static int max_tx_desc[8] = {0, }; static int max_rx_desc[8] = {0, }; static int tx_ratio[8] = {0, }; +static int dis_pci_mem_inval[8] = {1, 1, 1, 1, 1, 1, 1, 1}; -static const char __initdata *version = "acenic.c: v0.33a 08/16/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; +static const char __initdata *version = "acenic.c: v0.34 09/03/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; static struct net_device *root_dev = NULL; static int probed __initdata = 0; + int __init acenic_probe (struct net_device *dev) { int boards_found = 0; int version_disp; struct ace_private *ap; - u8 pci_latency; -#if 0 - u16 vendor, device; - u8 pci_bus; - u8 pci_dev_fun; - u8 irq; -#endif struct pci_dev *pdev = NULL; if (probed) @@ -243,29 +344,18 @@ ap = dev->priv; ap->pdev = pdev; - ap->vendor = pdev->vendor; dev->irq = pdev->irq; -#ifdef __SMP__ - spin_lock_init(&ap->lock); -#endif dev->open = &ace_open; dev->hard_start_xmit = &ace_start_xmit; dev->stop = &ace_close; dev->get_stats = &ace_get_stats; dev->set_multicast_list = &ace_set_multicast_list; -#if 0 dev->do_ioctl = &ace_ioctl; -#endif dev->set_mac_address = &ace_set_mac_addr; dev->change_mtu = &ace_change_mtu; - /* - * Dummy value. - */ - dev->base_addr = 42; - /* display version info if adapter is found */ if (!version_disp) { @@ -277,16 +367,36 @@ pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command); - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency <= 0x40){ - pci_latency = 0x40; + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, + &ap->pci_latency); + if (ap->pci_latency <= 0x40){ + ap->pci_latency = 0x40; pci_write_config_byte(pdev, PCI_LATENCY_TIMER, - pci_latency); + ap->pci_latency); } pci_set_master(pdev); - switch(ap->vendor){ + /* + * Remap the regs into kernel space - this is abuse of + * dev->base_addr since it was means for I/O port + * addresses but who gives a damn. + */ +#if (LINUX_VERSION_CODE < 0x02030d) + dev->base_addr = pdev->base_address[0]; +#else + dev->base_addr = pdev->resource[0].start; +#endif + + ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000); + if (!ap->regs){ + printk(KERN_ERR "%s: Unable to map I/O register, " + "AceNIC %i will be disabled.\n", + dev->name, boards_found); + break; + } + + switch(pdev->vendor){ case PCI_VENDOR_ID_ALTEON: sprintf(ap->name, "AceNIC Gigabit Ethernet"); printk(KERN_INFO "%s: Alteon AceNIC ", dev->name); @@ -316,21 +426,18 @@ printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); break; } - printk("Gigabit Ethernet at 0x%08lx, irq %i, PCI latency %i " - "clks\n", pdev->resource[0].start, dev->irq, pci_latency); + printk("Gigabit Ethernet at 0x%08lx, irq %i\n", + dev->base_addr, dev->irq); - /* - * Remap the regs into kernel space. - */ - - ap->regs = (struct ace_regs *)ioremap(pdev->resource[0].start, - 0x4000); - if (!ap->regs){ - printk(KERN_ERR "%s: Unable to map I/O register, " - "AceNIC %i will be disabled.\n", - dev->name, boards_found); - break; +#ifdef CONFIG_ACENIC_OMIT_TIGON_I + if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { + printk(KERN_ERR "%s: Driver compiled without Tigon I" + " support - NIC disabled\n", dev->name); + iounmap(ap->regs); + unregister_netdev(dev); + continue; } +#endif #ifdef MODULE if (ace_init(dev, boards_found)) @@ -341,12 +448,6 @@ #endif boards_found++; - - /* - * This is bollocks, but we need to tell the net-init - * code that it shall go for the next device. - */ - dev->base_addr = 0; } /* @@ -378,6 +479,7 @@ MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i"); #endif + int init_module(void) { int cards; @@ -388,37 +490,54 @@ return cards ? 0 : -ENODEV; } + void cleanup_module(void) { struct ace_private *ap; struct ace_regs *regs; struct net_device *next; short i; - unsigned long flags; while (root_dev){ next = ((struct ace_private *)root_dev->priv)->next; ap = (struct ace_private *)root_dev->priv; regs = ap->regs; - spin_lock_irqsave(&ap->lock, flags); writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); - if (ap->version == 2) + if (ap->version >= 2) writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); + /* + * This clears any pending interrupts + */ writel(0, ®s->Mb0Lo); - spin_unlock_irqrestore(&ap->lock, flags); - /* - * Release the RX buffers. + * Make sure no other CPUs are processing interrupts + * on the card before the buffers are being released. + * Otherwise one might experience some `interesting' + * effects. + * + * Then release the RX buffers - jumbo buffers were + * already released in ace_close(). */ + synchronize_irq(); + for (i = 0; i < RX_STD_RING_ENTRIES; i++) { - if (ap->rx_std_skbuff[i]) { + if (ap->skb->rx_std_skbuff[i]) { ap->rx_std_ring[i].size = 0; set_aceaddr_bus(&ap->rx_std_ring[i].addr, 0); - dev_kfree_skb(ap->rx_std_skbuff[i]); + dev_kfree_skb(ap->skb->rx_std_skbuff[i]); + } + } + if (ap->version >= 2) { + for (i = 0; i < RX_MINI_RING_ENTRIES; i++) { + if (ap->skb->rx_mini_skbuff[i]) { + ap->rx_mini_ring[i].size = 0; + set_aceaddr_bus(&ap->rx_mini_ring[i].addr, 0); + dev_kfree_skb(ap->skb->rx_mini_skbuff[i]); + } } } @@ -426,6 +545,7 @@ if(ap->trace_buf) kfree(ap->trace_buf); kfree(ap->info); + kfree(ap->skb); free_irq(root_dev->irq, root_dev); unregister_netdev(root_dev); kfree(root_dev); @@ -452,13 +572,13 @@ } -static int __init ace_init(struct net_device *dev, int board_idx) +static __init int ace_init(struct net_device *dev, int board_idx) { struct ace_private *ap; struct ace_regs *regs; struct ace_info *info; - u32 tig_ver, mac1, mac2, tmp; unsigned long tmp_ptr, myjif; + u32 tig_ver, mac1, mac2, tmp, pci_state; short i; ap = dev->priv; @@ -486,6 +606,7 @@ tig_ver = readl(®s->HostCtrl) >> 28; switch(tig_ver){ +#ifndef CONFIG_ACENIC_OMIT_TIGON_I case 4: printk(KERN_INFO" Tigon I (Rev. 4), Firmware: %i.%i.%i, ", tigonFwReleaseMajor, tigonFwReleaseMinor, @@ -493,6 +614,7 @@ writel(0, ®s->LocalCtrl); ap->version = 1; break; +#endif case 6: printk(KERN_INFO" Tigon II (Rev. %i), Firmware: %i.%i.%i, ", tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor, @@ -547,24 +669,38 @@ dev->dev_addr[4] = (mac2 >> 8) & 0xff; dev->dev_addr[5] = mac2 & 0xff; + pci_state = readl(®s->PciState); + printk(KERN_INFO " PCI bus speed: %iMHz, latency: %i clks\n", + (pci_state & PCI_66MHZ) ? 66 : 33, ap->pci_latency); + /* * Set the max DMA transfer size. Seems that for most systems * the performance is better when no MAX parameter is * set. However for systems enabling PCI write and invalidate, * DMA writes must be set to the L1 cache line size to get * optimal performance. + * + * The default is now to turn the PCI write and invalidate off + * - that is what Alteon does for NT. */ tmp = READ_CMD_MEM | WRITE_CMD_MEM; - if (ap->version == 2){ -#if 0 + if (ap->version >= 2){ + tmp |= (MEM_READ_MULTIPLE | (pci_state & PCI_66MHZ)); /* - * According to the documentation this enables writes - * to all PCI regs - NOT good. + * Tuning parameters only supported for 8 cards */ - tmp |= DMA_WRITE_ALL_ALIGN; -#endif - tmp |= MEM_READ_MULTIPLE; - if (ap->pci_command & PCI_COMMAND_INVALIDATE){ + if (board_idx > 7 || dis_pci_mem_inval[board_idx]) { + if (ap->pci_command & PCI_COMMAND_INVALIDATE) { + ap->pci_command &= ~PCI_COMMAND_INVALIDATE; + pci_write_config_word(ap->pdev, PCI_COMMAND, + ap->pci_command); + printk(KERN_INFO "%s: disabling PCI memory " + "write and invalidate\n", dev->name); + } + } else if (ap->pci_command & PCI_COMMAND_INVALIDATE){ + printk(KERN_INFO "%s: PCI memory write & invalidate " + "enabled by BIOS, enabling counter " + "measures\n", dev->name); switch(L1_CACHE_BYTES){ case 16: tmp |= DMA_WRITE_MAX_16; @@ -587,19 +723,23 @@ } writel(tmp, ®s->PciState); - if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) { - printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", - dev->name, dev->irq); - return -EAGAIN; - } - /* * Initialize the generic info block and the command+event rings * and the control blocks for the transmit and receive rings * as they need to be setup once and for all. */ - if (!(info = kmalloc(sizeof(struct ace_info), GFP_KERNEL))){ - free_irq(dev->irq, dev); + if (!(info = kmalloc(sizeof(struct ace_info), GFP_KERNEL))) + return -EAGAIN; + + /* + * Get the memory for the skb rings. + */ + if (!(ap->skb = kmalloc(sizeof(struct ace_skb), GFP_KERNEL))) + return -EAGAIN; + + if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) { + printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", + dev->name, dev->irq); return -EAGAIN; } @@ -612,6 +752,7 @@ ap->info = info; memset(info, 0, sizeof(struct ace_info)); + memset(ap->skb, 0, sizeof(struct ace_skb)); ace_load_firmware(dev); ap->fw_running = 0; @@ -631,10 +772,11 @@ set_aceaddr(&info->evt_prd_ptr, &ap->evt_prd); ap->evt_prd = 0; + wmb(); writel(0, ®s->EvtCsm); - info->cmd_ctrl.flags = 0; set_aceaddr_bus(&info->cmd_ctrl.rngptr, (void *)0x100); + info->cmd_ctrl.flags = 0; info->cmd_ctrl.max_len = 0; for (i = 0; i < CMD_RING_ENTRIES; i++) @@ -645,32 +787,51 @@ set_aceaddr(&info->stats2_ptr, &info->s.stats); - info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4; set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_std_ring); - info->rx_std_ctrl.flags = FLG_RX_TCP_UDP_SUM; + info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4; + info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM; memset(ap->rx_std_ring, 0, RX_STD_RING_ENTRIES * sizeof(struct rx_desc)); - info->rx_jumbo_ctrl.max_len = 0; + for (i = 0; i < RX_STD_RING_ENTRIES; i++) + ap->rx_std_ring[i].flags = BD_FLG_TCP_UDP_SUM; + + ap->rx_std_skbprd = 0; + atomic_set(&ap->cur_rx_bufs, 0); + set_aceaddr(&info->rx_jumbo_ctrl.rngptr, ap->rx_jumbo_ring); - info->rx_jumbo_ctrl.flags = FLG_RX_TCP_UDP_SUM; + info->rx_jumbo_ctrl.max_len = 0; + info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM; memset(ap->rx_jumbo_ring, 0, RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc)); - info->rx_mini_ctrl.max_len = 0; -#if 0 - set_aceaddr(&info->rx_mini_ctrl.rngptr, ap->rx_mini_ring); -#else - set_aceaddr_bus(&info->rx_mini_ctrl.rngptr, 0); -#endif - info->rx_mini_ctrl.flags = FLG_RNG_DISABLED; + for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) + ap->rx_jumbo_ring[i].flags = BD_FLG_TCP_UDP_SUM | BD_FLG_JUMBO; + + ap->rx_jumbo_skbprd = 0; + atomic_set(&ap->cur_jumbo_bufs, 0); -#if 0 memset(ap->rx_mini_ring, 0, RX_MINI_RING_ENTRIES * sizeof(struct rx_desc)); -#endif + + if (ap->version >= 2) { + set_aceaddr(&info->rx_mini_ctrl.rngptr, ap->rx_mini_ring); + info->rx_mini_ctrl.max_len = ACE_MINI_SIZE; + info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM; + + for (i = 0; i < RX_MINI_RING_ENTRIES; i++) + ap->rx_mini_ring[i].flags = + BD_FLG_TCP_UDP_SUM | BD_FLG_MINI; + } else { + set_aceaddr(&info->rx_mini_ctrl.rngptr, 0); + info->rx_mini_ctrl.flags = RCB_FLG_RNG_DISABLE; + info->rx_mini_ctrl.max_len = 0; + } + + ap->rx_mini_skbprd = 0; + atomic_set(&ap->cur_mini_bufs, 0); set_aceaddr(&info->rx_return_ctrl.rngptr, ap->rx_return_ring); info->rx_return_ctrl.flags = 0; @@ -687,9 +848,13 @@ writel(0, (unsigned long)ap->tx_ring + i * 4); } + set_aceaddr_bus(&info->tx_ctrl.rngptr, (void *)TX_RING_BASE); info->tx_ctrl.max_len = TX_RING_ENTRIES; +#if TX_COAL_INTS_ONLY + info->tx_ctrl.flags = RCB_FLG_COAL_INT_ONLY; +#else info->tx_ctrl.flags = 0; - set_aceaddr_bus(&info->tx_ctrl.rngptr, (void *)TX_RING_BASE); +#endif set_aceaddr(&info->tx_csm_ptr, &ap->tx_csm); @@ -743,7 +908,7 @@ */ tmp = LNK_ENABLE | LNK_FULL_DUPLEX | LNK_1000MB | LNK_100MB | LNK_10MB | LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL | LNK_NEGOTIATE; - if(ap->version == 2) + if(ap->version >= 2) tmp |= LNK_TX_FLOW_CTL_Y; /* @@ -780,28 +945,42 @@ "negotiation\n", dev->name); if (option & 0x200) tmp |= LNK_RX_FLOW_CTL_Y; - if ((option & 0x400) && (ap->version == 2)){ + if ((option & 0x400) && (ap->version >= 2)){ printk(KERN_INFO "%s: Enabling TX flow control\n", dev->name); tmp |= LNK_TX_FLOW_CTL_Y; } } + ap->link = tmp; writel(tmp, ®s->TuneLink); - if (ap->version == 2) + if (ap->version >= 2) writel(tmp, ®s->TuneFastLink); - if (ap->version == 1) + if (ACE_IS_TIGON_I(ap)) writel(tigonFwStartAddr, ®s->Pc); - else if (ap->version == 2) + if (ap->version == 2) writel(tigon2FwStartAddr, ®s->Pc); writel(0, ®s->Mb0Lo); /* - * Start the NIC CPU + * Set tx_csm before we start receiving interrupts, otherwise + * the interrupt handler might think it is supposed to process + * tx ints before we are up and running, which may cause a null + * pointer access in the int handler. */ + ap->tx_full = 0; + ap->cur_rx = 0; + ap->tx_prd = ap->tx_csm = ap->tx_ret_csm = 0; + + wmb(); + writel(0, ®s->TxPrd); + writel(0, ®s->RxRetCsm); + /* + * Start the NIC CPU + */ writel(readl(®s->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), ®s->CpuCtrl); /* @@ -820,8 +999,18 @@ * We load the ring here as there seem to be no way to tell the * firmware to wipe the ring without re-initializing it. */ - ace_load_std_rx_ring(dev); - + if (!test_and_set_bit(0, &ap->std_refill_busy)) + ace_load_std_rx_ring(ap, RX_RING_SIZE); + else + printk(KERN_ERR "%s: Someone is busy refilling the RX ring\n", + dev->name); + if (ap->version >= 2) { + if (!test_and_set_bit(0, &ap->mini_refill_busy)) + ace_load_mini_rx_ring(ap, RX_MINI_SIZE); + else + printk(KERN_ERR "%s: Someone is busy refilling " + "the RX mini ring\n", dev->name); + } return 0; } @@ -850,6 +1039,44 @@ } +static void ace_bh(struct net_device *dev) +{ + struct ace_private *ap = dev->priv; + int cur_size; + + cur_size = atomic_read(&ap->cur_rx_bufs); + if ((cur_size < RX_LOW_STD_THRES) && + !test_and_set_bit(0, &ap->std_refill_busy)) { +#if DEBUG + printk("refilling buffers (current %i)\n", cur_size); +#endif + ace_load_std_rx_ring(ap, RX_RING_SIZE - cur_size); + } + + if (ap->version >= 2) { + cur_size = atomic_read(&ap->cur_mini_bufs); + if ((cur_size < RX_LOW_MINI_THRES) && + !test_and_set_bit(0, &ap->mini_refill_busy)) { +#if DEBUG + printk("refilling mini buffers (current %i)\n", + cur_size); +#endif + ace_load_mini_rx_ring(ap, RX_MINI_SIZE - cur_size); + } + } + + cur_size = atomic_read(&ap->cur_jumbo_bufs); + if (ap->jumbo && (cur_size < RX_LOW_JUMBO_THRES) && + !test_and_set_bit(0, &ap->jumbo_refill_busy)) { +#if DEBUG + printk("refilling jumbo buffers (current %i)\n", >cur_size); +#endif + ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE - cur_size); + } + ap->bh_pending = 0; +} + + /* * Copy the contents of the NIC's trace buffer to kernel memory. */ @@ -865,69 +1092,92 @@ /* * Load the standard rx ring. + * + * Loading rings is safe without holding the spin lock since this is + * done only before the device is enabled, thus no interrupts are + * generated and by the interrupt handler/bh handler. */ -static int ace_load_std_rx_ring(struct net_device *dev) +static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs) { - struct ace_private *ap; struct ace_regs *regs; - struct ace_info *info; - unsigned long flags; - struct cmd cmd; - short i; + short i, idx; - ap = (struct ace_private *)dev->priv; regs = ap->regs; - info = ap->info; - - spin_lock_irqsave(&ap->lock, flags); - /* - * Set tx_csm before we start receiving interrupts, otherwise - * the interrupt handler might think it is supposed to process - * tx ints before we are up and running, which may cause a null - * pointer access in the int handler. - */ - ap->tx_full = 0; - ap->cur_rx = ap->dirty_rx = 0; - ap->tx_prd = ap->tx_csm = ap->tx_ret_csm = 0; - writel(0, ®s->RxRetCsm); + idx = ap->rx_std_skbprd; - for (i = 0; i < RX_RING_THRESH; i++) { + for (i = 0; i < nr_bufs; i++) { struct sk_buff *skb; + struct rx_desc *rd; - ap->rx_std_ring[i].flags = 0; - skb = alloc_skb(ACE_STD_MTU + ETH_HLEN + 6, GFP_ATOMIC); - ap->rx_std_skbuff[i] = skb; - + skb = alloc_skb(ACE_STD_BUFSIZE, GFP_ATOMIC); /* - * Make sure the data contents end up on an aligned address + * Make sure IP header starts on a fresh cache line. */ - skb_reserve(skb, 2); + skb_reserve(skb, 2 + 16); + ap->skb->rx_std_skbuff[idx] = skb; - set_aceaddr(&ap->rx_std_ring[i].addr, skb->data); - ap->rx_std_ring[i].size = ACE_STD_MTU + ETH_HLEN + 4; + rd = &ap->rx_std_ring[idx]; + set_aceaddr(&rd->addr, skb->data); + rd->size = ACE_STD_MTU + ETH_HLEN + 4; + rd->idx = idx; + idx = (idx + 1) % RX_STD_RING_ENTRIES; + } + + atomic_add(nr_bufs, &ap->cur_rx_bufs); + ap->rx_std_skbprd = idx; + + if (ACE_IS_TIGON_I(ap)) { + struct cmd cmd; + cmd.evt = C_SET_RX_PRD_IDX; + cmd.code = 0; + cmd.idx = ap->rx_std_skbprd; + ace_issue_cmd(regs, &cmd); + } else { + writel(idx, ®s->RxStdPrd); + wmb(); + } - ap->rx_std_ring[i].flags = 0; - ap->rx_std_ring[i].type = DESC_RX; + clear_bit(0, &ap->std_refill_busy); + return; +} - ap->rx_std_ring[i].idx = i; - } - ap->rx_std_skbprd = i; +static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs) +{ + struct ace_regs *regs; + short i, idx; + + regs = ap->regs; - /* - * The last descriptor needs to be marked as being special. - */ - ap->rx_std_ring[i-1].type = DESC_END; + idx = ap->rx_mini_skbprd; + for (i = 0; i < nr_bufs; i++) { + struct sk_buff *skb; + struct rx_desc *rd; - cmd.evt = C_SET_RX_PRD_IDX; - cmd.code = 0; - cmd.idx = ap->rx_std_skbprd; - ace_issue_cmd(regs, &cmd); + skb = alloc_skb(ACE_MINI_BUFSIZE, GFP_ATOMIC); + /* + * Make sure the IP header ends up on a fresh cache line + */ + skb_reserve(skb, 2 + 16); + ap->skb->rx_mini_skbuff[idx] = skb; - spin_unlock_irqrestore(&ap->lock, flags); + rd = &ap->rx_mini_ring[idx]; + set_aceaddr(&rd->addr, skb->data); + rd->size = ACE_MINI_SIZE; + rd->idx = idx; + idx = (idx + 1) % RX_MINI_RING_ENTRIES; + } - return 0; + atomic_add(nr_bufs, &ap->cur_mini_bufs); + + ap->rx_mini_skbprd = idx; + + writel(idx, ®s->RxMiniPrd); + wmb(); + + clear_bit(0, &ap->mini_refill_busy); + return; } @@ -935,61 +1185,54 @@ * Load the jumbo rx ring, this may happen at any time if the MTU * is changed to a value > 1500. */ -static int ace_load_jumbo_rx_ring(struct net_device *dev) +static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs) { - struct ace_private *ap; struct ace_regs *regs; - struct cmd cmd; - unsigned long flags; - short i; + short i, idx; - ap = (struct ace_private *)dev->priv; regs = ap->regs; - spin_lock_irqsave(&ap->lock, flags); + idx = ap->rx_jumbo_skbprd; - for (i = 0; i < RX_RING_JUMBO_THRESH; i++) { + for (i = 0; i < nr_bufs; i++) { struct sk_buff *skb; + struct rx_desc *rd; - ap->rx_jumbo_ring[i].flags = 0; - skb = alloc_skb(ACE_JUMBO_MTU + ETH_HLEN + 6, GFP_ATOMIC); - ap->rx_jumbo_skbuff[i] = skb; - + skb = alloc_skb(ACE_JUMBO_BUFSIZE, GFP_ATOMIC); /* - * Make sure the data contents end up on an aligned address + * Make sure the IP header ends up on a fresh cache line */ - skb_reserve(skb, 2); - - set_aceaddr(&ap->rx_jumbo_ring[i].addr, skb->data); - ap->rx_jumbo_ring[i].size = ACE_JUMBO_MTU + ETH_HLEN + 4; + skb_reserve(skb, 2 + 16); + ap->skb->rx_jumbo_skbuff[idx] = skb; - ap->rx_jumbo_ring[i].flags = DFLG_RX_JUMBO; - ap->rx_jumbo_ring[i].type = DESC_RX; - - ap->rx_jumbo_ring[i].idx = i; + rd = &ap->rx_jumbo_ring[idx]; + set_aceaddr(&rd->addr, skb->data); + rd->size = ACE_JUMBO_MTU + ETH_HLEN + 4; + rd->idx = idx; + idx = (idx + 1) % RX_JUMBO_RING_ENTRIES; + } + + atomic_add(nr_bufs, &ap->cur_jumbo_bufs); + ap->rx_jumbo_skbprd = idx; + + if (ACE_IS_TIGON_I(ap)) { + struct cmd cmd; + cmd.evt = C_SET_RX_JUMBO_PRD_IDX; + cmd.code = 0; + cmd.idx = ap->rx_jumbo_skbprd; + ace_issue_cmd(regs, &cmd); + } else { + writel(idx, ®s->RxJumboPrd); + wmb(); } - ap->rx_jumbo_skbprd = i; - - /* - * The last descriptor needs to be marked as being special. - */ - ap->rx_jumbo_ring[i-1].type = DESC_END; - - cmd.evt = C_SET_RX_JUMBO_PRD_IDX; - cmd.code = 0; - cmd.idx = ap->rx_jumbo_skbprd; - ace_issue_cmd(regs, &cmd); - - spin_unlock_irqrestore(&ap->lock, flags); - - return 0; + clear_bit(0, &ap->jumbo_refill_busy); + return; } /* * Tell the firmware not to accept jumbos and flush the jumbo ring. - * This function must be called with the spinlock held. */ static int ace_flush_jumbo_rx_ring(struct net_device *dev) { @@ -1008,10 +1251,10 @@ ace_issue_cmd(regs, &cmd); for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { - if (ap->rx_jumbo_skbuff[i]) { + if (ap->skb->rx_jumbo_skbuff[i]) { ap->rx_jumbo_ring[i].size = 0; set_aceaddr_bus(&ap->rx_jumbo_ring[i].addr, 0); - dev_kfree_skb(ap->rx_jumbo_skbuff[i]); + dev_kfree_skb(ap->skb->rx_jumbo_skbuff[i]); } } }else @@ -1046,13 +1289,14 @@ { u16 code = ap->evt_ring[evtcsm].code; if (code == E_C_LINK_UP){ - printk("%s: Optical link UP\n", dev->name); + printk(KERN_WARNING "%s: Optical link UP\n", + dev->name); } else if (code == E_C_LINK_DOWN) - printk(KERN_INFO "%s: Optical link DOWN\n", + printk(KERN_WARNING "%s: Optical link DOWN\n", dev->name); else - printk(KERN_INFO "%s: Unknown optical link " + printk(KERN_ERR "%s: Unknown optical link " "state %02x\n", dev->name, code); break; } @@ -1088,100 +1332,65 @@ } -static int ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) +static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) { struct ace_private *ap = (struct ace_private *)dev->priv; - struct ace_regs *regs = ap->regs; - u32 idx, oldidx; + u32 idx; + int mini_count = 0, std_count = 0; idx = rxretcsm; while (idx != rxretprd){ - struct sk_buff *skb, *newskb, *oldskb; - struct rx_desc *newrxdesc, *oldrxdesc; - u32 prdidx, size; - void *addr; + struct sk_buff *skb, **oldskb_p; + struct rx_desc *rxdesc; + u32 skbidx; + int desc_type; u16 csum; - int jumbo; - - oldidx = ap->rx_return_ring[idx].idx; - jumbo = ap->rx_return_ring[idx].flags & DFLG_RX_JUMBO; - - if (jumbo){ - oldskb = ap->rx_jumbo_skbuff[oldidx]; - prdidx = ap->rx_jumbo_skbprd; - newrxdesc = &ap->rx_jumbo_ring[prdidx]; - oldrxdesc = &ap->rx_jumbo_ring[oldidx]; - }else{ - oldskb = ap->rx_std_skbuff[oldidx]; - prdidx = ap->rx_std_skbprd; - newrxdesc = &ap->rx_std_ring[prdidx]; - oldrxdesc = &ap->rx_std_ring[oldidx]; - } - - size = oldrxdesc->size; - - if (size < PKT_COPY_THRESHOLD) { - skb = alloc_skb(size + 2, GFP_ATOMIC); - if (skb == NULL){ - printk(KERN_ERR "%s: Out of memory\n", - dev->name); - goto error; - } - /* - * Make sure the real data is aligned - */ - skb_reserve(skb, 2); - memcpy(skb_put(skb, size), oldskb->data, size); - addr = get_aceaddr_bus(&oldrxdesc->addr); - newskb = oldskb; - }else{ - skb = oldskb; - - skb_put(skb, size); - - newskb = alloc_skb(size + 2, GFP_ATOMIC); - if (newskb == NULL){ - printk(KERN_ERR "%s: Out of memory\n", - dev->name); - goto error; - } + skbidx = ap->rx_return_ring[idx].idx; + desc_type = ap->rx_return_ring[idx].flags & + (BD_FLG_JUMBO | BD_FLG_MINI); + switch(desc_type) { /* - * Make sure we DMA directly into nicely - * aligned receive buffers + * Normal frames do not have any flags set + * + * Mini and normal frames arrive frequently, + * so use a local counter to avoid doing + * atomic operations for each packet arriving. */ - skb_reserve(newskb, 2); - addr = (void *)virt_to_bus(newskb->data); - } - - set_aceaddr_bus(&newrxdesc->addr, addr); - newrxdesc->size = size; - - newrxdesc->flags = oldrxdesc->flags; - newrxdesc->idx = prdidx; - newrxdesc->type = DESC_RX; -#if (BITS_PER_LONG == 32) - newrxdesc->addr.addrhi = 0; -#endif - - oldrxdesc->size = 0; - set_aceaddr_bus(&oldrxdesc->addr, 0); - - if (jumbo){ - ap->rx_jumbo_skbuff[oldidx] = NULL; - ap->rx_jumbo_skbuff[prdidx] = newskb; - - prdidx = (prdidx + 1) % RX_JUMBO_RING_ENTRIES; - ap->rx_jumbo_skbprd = prdidx; - }else{ - ap->rx_std_skbuff[oldidx] = NULL; - ap->rx_std_skbuff[prdidx] = newskb; - - prdidx = (prdidx + 1) % RX_STD_RING_ENTRIES; - ap->rx_std_skbprd = prdidx; - } + case 0: + oldskb_p = &ap->skb->rx_std_skbuff[skbidx]; + rxdesc = &ap->rx_std_ring[skbidx]; + std_count++; + break; + case BD_FLG_JUMBO: + oldskb_p = &ap->skb->rx_jumbo_skbuff[skbidx]; + rxdesc = &ap->rx_jumbo_ring[skbidx]; + atomic_dec(&ap->cur_jumbo_bufs); + break; + case BD_FLG_MINI: + oldskb_p = &ap->skb->rx_mini_skbuff[skbidx]; + rxdesc = &ap->rx_mini_ring[skbidx]; + mini_count++; + break; + default: + printk(KERN_INFO "%s: unknown frame type (0x%02x) " + "returned by NIC\n", dev->name, + ap->rx_return_ring[idx].flags); + goto error; + } + + skb = *oldskb_p; +#if DEBUG + if (skb == NULL) { + printk("Mayday! illegal skb received! (idx %i)\n", skbidx); + goto error; + } +#endif + *oldskb_p = NULL; + skb_put(skb, rxdesc->size); + rxdesc->size = 0; /* * Fly baby, fly! @@ -1191,12 +1400,6 @@ skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); -#if 0 - /* - * This was never actually enabled in the RX descriptors - * anyway - it requires a bit more testing before enabling - * it again. - */ /* * If the checksum is correct and this is not a * fragment, tell the stack that the data is correct. @@ -1207,34 +1410,31 @@ skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; -#endif + netif_rx(skb); /* send it up */ ap->stats.rx_packets++; ap->stats.rx_bytes += skb->len; - if ((prdidx & 0x7) == 0){ - struct cmd cmd; - if (jumbo) - cmd.evt = C_SET_RX_JUMBO_PRD_IDX; - else - cmd.evt = C_SET_RX_PRD_IDX; - cmd.code = 0; - cmd.idx = prdidx; - ace_issue_cmd(regs, &cmd); - } - idx = (idx + 1) % RX_RETURN_RING_ENTRIES; } + + atomic_sub(std_count, &ap->cur_rx_bufs); + if (!ACE_IS_TIGON_I(ap)) + atomic_sub(mini_count, &ap->cur_mini_bufs); + out: /* * According to the documentation RxRetCsm is obsolete with - * the 12.3.x Firmware - my Tigon I NIC's seem to disagree! + * the 12.3.x Firmware - my Tigon I NICs seem to disagree! */ - writel(idx, ®s->RxRetCsm); + if (ACE_IS_TIGON_I(ap)) { + struct ace_regs *regs = ap->regs; + writel(idx, ®s->RxRetCsm); + } ap->cur_rx = idx; - return idx; + return; error: idx = rxretprd; goto out; @@ -1246,23 +1446,20 @@ struct ace_private *ap; struct ace_regs *regs; struct net_device *dev = (struct net_device *)dev_id; + u32 idx; u32 txcsm, rxretcsm, rxretprd; u32 evtcsm, evtprd; ap = (struct ace_private *)dev->priv; regs = ap->regs; - spin_lock(&ap->lock); - /* * In case of PCI shared interrupts or spurious interrupts, * we want to make sure it is actually our interrupt before * spending any time in here. */ - if (!(readl(®s->HostCtrl) & IN_INT)){ - spin_unlock(&ap->lock); + if (!(readl(®s->HostCtrl) & IN_INT)) return; - } /* * Tell the card not to generate interrupts while we are in here. @@ -1270,25 +1467,35 @@ writel(1, ®s->Mb0Lo); /* - * Service RX ints before TX + * There is no conflict between transmit handling in + * start_xmit and receive processing, thus there is no reason + * to take a spin lock for RX handling. Wait until we start + * working on the other stuff - hey we don't need a spin lock + * anymore. */ rxretprd = ap->rx_ret_prd; rxretcsm = ap->cur_rx; if (rxretprd != rxretcsm) - rxretprd = ace_rx_int(dev, rxretprd, rxretcsm); + ace_rx_int(dev, rxretprd, rxretcsm); txcsm = ap->tx_csm; - if (txcsm != ap->tx_ret_csm) { - u32 idx = ap->tx_ret_csm; + idx = ap->tx_ret_csm; + if (txcsm != idx) { do { ap->stats.tx_packets++; - ap->stats.tx_bytes += ap->tx_skbuff[idx]->len; - dev_kfree_skb(ap->tx_skbuff[idx]); + ap->stats.tx_bytes += ap->skb->tx_skbuff[idx]->len; + dev_kfree_skb(ap->skb->tx_skbuff[idx]); - ap->tx_skbuff[idx] = NULL; + ap->skb->tx_skbuff[idx] = NULL; + /* + * Question here is whether one should not skip + * these writes - I have never seen any errors + * caused by the NIC actually trying to access + * these incorrectly. + */ #if (BITS_PER_LONG == 64) writel(0, &ap->tx_ring[idx].addr.addrhi); #endif @@ -1298,10 +1505,19 @@ idx = (idx + 1) % TX_RING_ENTRIES; } while (idx != txcsm); - if (ap->tx_full && dev->tbusy && - (((ap->tx_prd + 1) % TX_RING_ENTRIES) != txcsm)){ + /* + * Once we actually get to this point the tx ring has + * already been trimmed thus it cannot be full! + * Ie. skip the comparison of the tx producer vs. the + * consumer. + */ + if (ap->tx_full && dev->tbusy) { ap->tx_full = 0; - dev->tbusy = 0; + /* + * This does not need to be atomic (and expensive), + * I've seen cases where it would fail otherwise ;-( + */ + clear_bit(0, &dev->tbusy); mark_bh(NET_BH); /* @@ -1312,19 +1528,80 @@ } ap->tx_ret_csm = txcsm; + wmb(); } evtcsm = readl(®s->EvtCsm); evtprd = ap->evt_prd; - if (evtcsm != evtprd){ + if (evtcsm != evtprd) { evtcsm = ace_handle_event(dev, evtcsm, evtprd); + writel(evtcsm, ®s->EvtCsm); } - writel(evtcsm, ®s->EvtCsm); - writel(0, ®s->Mb0Lo); + /* + * This has to go last in the interrupt handler and run with + * the spin lock released ... what lock? + */ + if (dev->start) { + int cur_size; + int run_bh = 0; - spin_unlock(&ap->lock); + cur_size = atomic_read(&ap->cur_rx_bufs); + if (cur_size < RX_LOW_STD_THRES) { + if ((cur_size < RX_PANIC_STD_THRES) && + !test_and_set_bit(0, &ap->std_refill_busy)) { +#if DEBUG + printk("low on std buffers %i\n", cur_size); +#endif + ace_load_std_rx_ring(ap, + RX_RING_SIZE - cur_size); + } + run_bh = 1; + } + + if (!ACE_IS_TIGON_I(ap)) { + cur_size = atomic_read(&ap->cur_mini_bufs); + if (cur_size < RX_LOW_MINI_THRES) { + if ((cur_size < RX_PANIC_MINI_THRES) && + !test_and_set_bit(0, + &ap->mini_refill_busy)) { +#if DEBUG + printk("low on mini buffers %i\n", + cur_size); +#endif + ace_load_mini_rx_ring(ap, RX_MINI_SIZE - cur_size); + } else + run_bh = 1; + } + } + + if (ap->jumbo) { + cur_size = atomic_read(&ap->cur_jumbo_bufs); + if (cur_size < RX_LOW_JUMBO_THRES) { + if ((cur_size < RX_PANIC_JUMBO_THRES) && + !test_and_set_bit(0, + &ap->jumbo_refill_busy)){ +#if DEBUG + printk("low on jumbo buffers %i\n", + cur_size); +#endif + ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE - cur_size); + } else + run_bh = 1; + } + } + if (run_bh && !ap->bh_pending) { + ap->bh_pending = 1; + queue_task(&ap->immediate, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + } + + /* + * Allow the card to generate interrupts again + */ + writel(0, ®s->Mb0Lo); } @@ -1338,7 +1615,7 @@ regs = ap->regs; if (!(ap->fw_running)){ - printk(KERN_WARNING "%s: firmware not running!\n", dev->name); + printk(KERN_WARNING "%s: Firmware not running!\n", dev->name); return -EBUSY; } @@ -1349,8 +1626,9 @@ cmd.idx = 0; ace_issue_cmd(regs, &cmd); - if (ap->jumbo) - ace_load_jumbo_rx_ring(dev); + if (ap->jumbo && + !test_and_set_bit(0, &ap->jumbo_refill_busy)) + ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE); if (dev->flags & IFF_PROMISC){ cmd.evt = C_SET_PROMISC_MODE; @@ -1364,10 +1642,6 @@ ap->mcast_all = 0; #if 0 - { long myjif = jiffies + HZ; - while (time_before(jiffies, myjif)); - } - cmd.evt = C_LNK_NEGOTIATION; cmd.code = 0; cmd.idx = 0; @@ -1386,6 +1660,15 @@ init_timer(&ap->timer); ap->timer.data = (unsigned long)dev; ap->timer.function = ace_timer; + + /* + * Setup the bottom half rx ring refill handler + */ + ap->immediate.next = NULL; + ap->immediate.sync = 0; + ap->immediate.routine = (void *)(void *)ace_bh; + ap->immediate.data = dev; + return 0; } @@ -1399,7 +1682,7 @@ short i; dev->start = 0; - set_bit(0, (void*)&dev->tbusy); + set_bit(0, &dev->tbusy); ap = (struct ace_private *)dev->priv; regs = ap->regs; @@ -1419,21 +1702,26 @@ cmd.idx = 0; ace_issue_cmd(regs, &cmd); - spin_lock_irqsave(&ap->lock, flags); + /* + * Make sure one CPU is not processing packets while + * buffers are being released by another. + */ + save_flags(flags); + cli(); for (i = 0; i < TX_RING_ENTRIES; i++) { - if (ap->tx_skbuff[i]) { + if (ap->skb->tx_skbuff[i]) { writel(0, &ap->tx_ring[i].addr.addrhi); writel(0, &ap->tx_ring[i].addr.addrlo); writel(0, &ap->tx_ring[i].flagsize); - dev_kfree_skb(ap->tx_skbuff[i]); + dev_kfree_skb(ap->skb->tx_skbuff[i]); } } if (ap->jumbo) ace_flush_jumbo_rx_ring(dev); - spin_unlock_irqrestore(&ap->lock, flags); + restore_flags(flags); MOD_DEC_USE_COUNT; return 0; @@ -1444,31 +1732,44 @@ { struct ace_private *ap = (struct ace_private *)dev->priv; struct ace_regs *regs = ap->regs; - unsigned long flags; unsigned long addr; u32 idx, flagsize; - spin_lock_irqsave(&ap->lock, flags); + if (test_and_set_bit(0, &dev->tbusy)) + return 1; idx = ap->tx_prd; - ap->tx_skbuff[idx] = skb; + if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm) { + ap->tx_full = 1; +#if DEBUG + printk("%s: trying to transmit while the tx ring is full " + "- this should not happen!\n", dev->name); +#endif + return 1; + } + + ap->skb->tx_skbuff[idx] = skb; addr = virt_to_bus(skb->data); #if (BITS_PER_LONG == 64) writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi); #endif writel(addr & 0xffffffff, &ap->tx_ring[idx].addr.addrlo); - flagsize = (skb->len << 16) | (DESC_END) ; + flagsize = (skb->len << 16) | (BD_FLG_END) ; writel(flagsize, &ap->tx_ring[idx].flagsize); - mb(); + wmb(); idx = (idx + 1) % TX_RING_ENTRIES; ap->tx_prd = idx; writel(idx, ®s->TxPrd); + wmb(); - if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm){ + /* + * tx_csm is set by the NIC whereas we set tx_ret_csm which + * is always trying to catch tx_csm + */ + if ((idx + 2) % TX_RING_ENTRIES == ap->tx_ret_csm){ ap->tx_full = 1; - set_bit(0, (void*)&dev->tbusy); /* * Queue is full, add timer to detect whether the * transmitter is stuck. Use mod_timer as we can get @@ -1476,10 +1777,13 @@ * timers. */ mod_timer(&ap->timer, jiffies + (3 * HZ)); + } else { + /* + * No need for it to be atomic - seems it needs to be + */ + clear_bit(0, &dev->tbusy); } - spin_unlock_irqrestore(&ap->lock, flags); - dev->trans_start = jiffies; return 0; } @@ -1501,7 +1805,8 @@ printk(KERN_INFO "%s: Enabling Jumbo frame " "support\n", dev->name); ap->jumbo = 1; - ace_load_jumbo_rx_ring(dev); + if (!test_and_set_bit(0, &ap->jumbo_refill_busy)) + ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE); } ap->jumbo = 1; }else{ @@ -1518,6 +1823,126 @@ } +static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ +#ifdef ETHTOOL + struct ace_private *ap = (struct ace_private *) dev->priv; + struct ace_regs *regs = ap->regs; + struct ethtool_cmd ecmd; + u32 link, speed; + + if (cmd != SIOCETHTOOL) + return -EOPNOTSUPP; + if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd))) + return -EFAULT; + + if (ecmd.cmd == ETH_GSET) { + ecmd.supported = + (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_FIBRE); + + ecmd.port = PORT_FIBRE; + ecmd.transceiver = XCVR_INTERNAL; + ecmd.phy_address = 0; + + link = readl(®s->GigLnkState); + if (link & LNK_1000MB) + ecmd.speed = SPEED_1000; + else { + link = readl(®s->FastLnkState); + if (link & LNK_100MB) + ecmd.speed = SPEED_100; + else if (link & LNK_100MB) + ecmd.speed = SPEED_10; + else + ecmd.speed = 0; + } + if (link & LNK_FULL_DUPLEX) + ecmd.duplex = DUPLEX_FULL; + else + ecmd.duplex = DUPLEX_HALF; + + if (link & LNK_NEGOTIATE) + ecmd.autoneg = AUTONEG_ENABLE; + else + ecmd.autoneg = AUTONEG_DISABLE; + + ecmd.trace = readl(®s->TuneTrace); + + ecmd.txcoal = readl(®s->TuneTxCoalTicks); + ecmd.rxcoal = readl(®s->TuneRxCoalTicks); + ecmd.maxtxpkt = readl(®s->TuneMaxTxDesc); + ecmd.maxrxpkt = readl(®s->TuneMaxRxDesc); + + if(copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } else if (ecmd.cmd == ETH_SSET) { + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + link = readl(®s->GigLnkState); + if (link & LNK_1000MB) + speed = SPEED_1000; + else { + link = readl(®s->FastLnkState); + if (link & LNK_100MB) + speed = SPEED_100; + else if (link & LNK_100MB) + speed = SPEED_10; + else + speed = SPEED_100; + } + + link = LNK_ENABLE | LNK_1000MB | LNK_100MB | LNK_10MB | + LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL; + if (!ACE_IS_TIGON_I(ap)) + link |= LNK_TX_FLOW_CTL_Y; + if (ecmd.autoneg == AUTONEG_ENABLE) + link |= LNK_NEGOTIATE; + if (ecmd.speed != speed) { + link &= ~(LNK_1000MB | LNK_100MB | LNK_10MB); + switch (speed) { + case SPEED_1000: + link |= LNK_1000MB; + break; + case SPEED_100: + link |= LNK_100MB; + break; + case SPEED_10: + link |= LNK_10MB; + break; + } + } + if (ecmd.duplex == DUPLEX_FULL) + link |= LNK_FULL_DUPLEX; + + if (link != ap->link) { + struct cmd cmd; + printk(KERN_INFO "%s: Renegotiating link state\n", + dev->name); + + ap->link = link; + writel(link, ®s->TuneLink); + if (!ACE_IS_TIGON_I(ap)) + writel(link, ®s->TuneFastLink); + wmb(); + + cmd.evt = C_LNK_NEGOTIATION; + cmd.code = 0; + cmd.idx = 0; + ace_issue_cmd(regs, &cmd); + } + return 0; + } +#endif + + return -EOPNOTSUPP; +} + + /* * Set the hardware MAC address. */ @@ -1530,6 +1955,7 @@ if(dev->start) return -EBUSY; + memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); da = (u16 *)dev->dev_addr; @@ -1627,9 +2053,6 @@ #ifdef __BIG_ENDIAN #error "data must be swapped here" #else -/* - * XXX - special memcpy needed here!!! - */ wsrc = src; for (i = 0; i < (tsize / 4); i++){ writel(wsrc[i], tdest + i*4); @@ -1696,7 +2119,7 @@ * funny things on NICs with only 512KB SRAM */ ace_clear(regs, 0x2000, 0x80000-0x2000); - if (ap->version == 1){ + if (ACE_IS_TIGON_I(ap)){ ace_copy(regs, tigonFwText, tigonFwTextAddr, tigonFwTextLen); ace_copy(regs, tigonFwData, tigonFwDataAddr, tigonFwDataLen); ace_copy(regs, tigonFwRodata, tigonFwRodataAddr, @@ -1728,7 +2151,7 @@ * * Oh yes, this is only the beginning! */ -static void eeprom_start(struct ace_regs *regs) +static void __init eeprom_start(struct ace_regs *regs) { u32 local = readl(®s->LocalCtrl); @@ -1751,7 +2174,7 @@ } -static void eeprom_prep(struct ace_regs *regs, u8 magic) +static void __init eeprom_prep(struct ace_regs *regs, u8 magic) { short i; u32 local; @@ -1784,7 +2207,7 @@ } -static int eeprom_check_ack(struct ace_regs *regs) +static int __init eeprom_check_ack(struct ace_regs *regs) { int state; u32 local; @@ -1809,7 +2232,7 @@ } -static void eeprom_stop(struct ace_regs *regs) +static void __init eeprom_stop(struct ace_regs *regs) { u32 local; @@ -1839,7 +2262,7 @@ /* * Read a whole byte from the EEPROM. */ -static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset) +static u8 __init read_eeprom_byte(struct ace_regs *regs, unsigned long offset) { u32 local; short i; @@ -1911,6 +2334,6 @@ /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -D__SMP__ -DMODULE -I/data/home/jes/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include /data/home/jes/linux/include/linux/modversions.h -c -o acenic.o acenic.c" + * 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" * End: */ diff -u --recursive --new-file v2.3.16/linux/drivers/net/acenic.h linux/drivers/net/acenic.h --- v2.3.16/linux/drivers/net/acenic.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/acenic.h Sat Sep 4 13:11:36 1999 @@ -14,7 +14,7 @@ * as some of them are in PCI shared memory and it is necessary to use * readl/writel to access them. * - * The addressing code is derived from Pete Beckman's work, but + * The addressing code is derived from Pete Wyckoff's work, but * modified to deal properly with readl/writel usage. */ @@ -143,11 +143,11 @@ u32 Mb2Hi; u32 TxPrd; u32 Mb3Hi; - u32 Mb3Lo; + u32 RxStdPrd; /* RxStdPrd */ u32 Mb4Hi; - u32 Mb4Lo; + u32 RxJumboPrd; /* RxJumboPrd */ u32 Mb5Hi; - u32 Mb5Lo; + u32 RxMiniPrd; u32 Mb6Hi; u32 Mb6Lo; u32 Mb7Hi; @@ -197,7 +197,7 @@ u32 IfIdx; u32 IfMtu; /* 0x660 */ u32 MaskInt; - u32 LnkState; + u32 GigLnkState; u32 FastLnkState; u32 pad16[4]; /* 0x670 */ u32 RxRetCsm; /* 0x680 */ @@ -279,6 +279,7 @@ #define DMA_WRITE_MAX_256 0xc0 #define DMA_WRITE_MAX_1K 0xe0 #define MEM_READ_MULTIPLE 0x00020000 +#define PCI_66MHZ 0x00080000 #define DMA_WRITE_ALL_ALIGN 0x00800000 #define READ_CMD_MEM 0x06000000 #define WRITE_CMD_MEM 0x70000000 @@ -365,6 +366,7 @@ #define E_LNK_STATE 0x06 #define E_C_LINK_UP 0x01 #define E_C_LINK_DOWN 0x02 +#define E_C_LINK_UP_FAST 0x03 #define E_ERROR 0x07 #define E_C_ERR_INVAL_CMD 0x01 @@ -416,6 +418,10 @@ #define C_C_PROMISC_DISABLE 0x02 #define C_LNK_NEGOTIATION 0x0b +#define C_C_NEGOTIATE_BOTH 0x00 +#define C_C_NEGOTIATE_GIG 0x01 +#define C_C_NEGOTIATE_10_100 0x02 + #define C_SET_MAC_ADDR 0x0c #define C_CLEAR_PROFILE 0x0d @@ -429,33 +435,30 @@ /* - * Descriptor types. + * Descriptor flags */ +#define BD_FLG_TCP_UDP_SUM 0x01 +#define BD_FLG_IP_SUM 0x02 +#define BD_FLG_END 0x04 +#define BD_FLG_JUMBO 0x10 +#define BD_FLG_MINI 0x1000 -#define DESC_TX 0x01 -#define DESC_RX 0x02 -#define DESC_END 0x04 -#define DESC_MORE 0x08 /* - * Control block flags - */ + * Ring Control block flags + */ +#define RCB_FLG_TCP_UDP_SUM 0x01 +#define RCB_FLG_IP_SUM 0x02 +#define RCB_FLG_VLAN_ASSIST 0x10 +#define RCB_FLG_COAL_INT_ONLY 0x20 +#define RCB_FLG_IEEE_SNAP_SUM 0x80 +#define RCB_FLG_EXT_RX_BD 0x100 +#define RCB_FLG_RNG_DISABLE 0x200 -#define FLG_RX_TCP_UDP_SUM 0x01 -#define FLG_RX_IP_SUM 0x02 -#define FLG_RX_SPLIT_HDRS 0x04 -#define FLG_RX_NO_PSDO_HDR_SUM 0x08 -#define FLG_RNG_DISABLED 0x200 - -/* - * Descriptor flags - */ -#define DFLG_RX_JUMBO 0x10 /* * TX ring */ - #define TX_RING_ENTRIES 128 #define TX_RING_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc)) #define TX_RING_BASE 0x3800 @@ -471,12 +474,16 @@ #if __LITTLE_ENDIAN u16 flags; u16 size; + u16 vlan; + u16 reserved; #else u16 size; u16 flags; + u16 reserved; + u16 vlan; #endif #endif - u32 nic_addr; + u32 vlanres; }; @@ -493,9 +500,6 @@ #define RX_RETURN_RING_SIZE (RX_MAX_RETURN_RING_ENTRIES * \ sizeof(struct rx_desc)) -#define RX_RING_THRESH 64 -#define RX_RING_JUMBO_THRESH 48 - struct rx_desc{ aceaddr addr; #ifdef __LITTLE_ENDIAN @@ -520,14 +524,14 @@ u16 tcp_udp_csum; #endif #ifdef __LITTLE_ENDIAN - u16 reserved; + u16 vlan; u16 err_flags; #else u16 err_flags; - u16 reserved; + u16 vlan; #endif - u32 nic_addr; - u32 pad[1]; + u32 reserved; + u32 opague; }; @@ -598,55 +602,72 @@ aceaddr stats2_ptr; }; + /* - * Struct private for the AceNIC. + * struct ace_skb holding the rings of skb's. This is an awful lot of + * pointers, but I don't see any other smart mode to do this in an + * efficient manner ;-( */ +struct ace_skb +{ + struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; + struct sk_buff *rx_std_skbuff[RX_STD_RING_ENTRIES]; + struct sk_buff *rx_mini_skbuff[RX_MINI_RING_ENTRIES]; + struct sk_buff *rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES]; +}; + +/* + * Struct private for the AceNIC. + * + * Elements are grouped so variables used by the tx handling goes + * together, and will go into the same cache lines etc. in order to + * avoid cache line contention between the rx and tx handling on SMP. + * + * Frequently accessed variables are put at the beginning of the + * struct to help the compiler generate better/shorter code. + */ struct ace_private { + struct ace_skb *skb; struct ace_regs *regs; /* register base */ - volatile __u32 *sgt; - struct sk_buff *pkt_buf; /* Receive buffer */ -/* - * The send ring is located in the shared memory window - */ + int version, fw_running, fw_up, link; + int promisc, mcast_all; + /* + * The send ring is located in the shared memory window + */ + struct ace_info *info; struct tx_desc *tx_ring; - struct rx_desc rx_std_ring[RX_STD_RING_ENTRIES]; + u32 tx_prd, tx_full, tx_ret_csm; + struct timer_list timer; + + unsigned long std_refill_busy + __attribute__ ((aligned (L1_CACHE_BYTES))); + unsigned long mini_refill_busy, jumbo_refill_busy; + atomic_t cur_rx_bufs, + cur_mini_bufs, + cur_jumbo_bufs; + u32 rx_std_skbprd, rx_mini_skbprd, rx_jumbo_skbprd; + u32 cur_rx; + struct tq_struct immediate; + int bh_pending, jumbo; + struct rx_desc rx_std_ring[RX_STD_RING_ENTRIES] + __attribute__ ((aligned (L1_CACHE_BYTES))); struct rx_desc rx_jumbo_ring[RX_JUMBO_RING_ENTRIES]; -#if 0 struct rx_desc rx_mini_ring[RX_MINI_RING_ENTRIES]; -#endif struct rx_desc rx_return_ring[RX_RETURN_RING_ENTRIES]; struct event evt_ring[EVT_RING_ENTRIES]; - struct ace_info *info; - struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; - struct sk_buff *rx_std_skbuff[RX_STD_RING_ENTRIES]; - struct sk_buff *rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES]; - spinlock_t lock; - struct timer_list timer; - u32 cur_rx, tx_prd; - u32 dirty_rx, tx_ret_csm, dirty_event; - u32 rx_std_skbprd, rx_jumbo_skbprd; - u32 tx_full; volatile u32 evt_prd __attribute__ ((aligned (L1_CACHE_BYTES))); volatile u32 rx_ret_prd __attribute__ ((aligned (L1_CACHE_BYTES))); volatile u32 tx_csm __attribute__ ((aligned (L1_CACHE_BYTES))); - struct net_device *next - __attribute__ ((aligned (L1_CACHE_BYTES))); unsigned char *trace_buf; - int fw_running, fw_up, jumbo, promisc, mcast_all; - int version; - int flags; - u16 vendor; - u16 pci_command; struct pci_dev *pdev; -#if 0 - u8 pci_bus; - u8 pci_dev_fun; -#endif + struct net_device *next; + u16 pci_command; + u8 pci_latency; char name[24]; struct net_device_stats stats; }; @@ -655,8 +676,9 @@ * Prototypes */ static int ace_init(struct net_device *dev, int board_idx); -static int ace_load_std_rx_ring(struct net_device *dev); -static int ace_load_jumbo_rx_ring(struct net_device *dev); +static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs); +static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs); +static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs); static int ace_flush_jumbo_rx_ring(struct net_device *dev); static void ace_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int ace_load_firmware(struct net_device *dev); @@ -664,9 +686,14 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev); static int ace_close(struct net_device *dev); static void ace_timer(unsigned long data); +static void ace_bh(struct net_device *dev); static void ace_dump_trace(struct ace_private *ap); static void ace_set_multicast_list(struct net_device *dev); static int ace_change_mtu(struct net_device *dev, int new_mtu); +#ifdef SKB_RECYCLE +extern int ace_recycle(struct sk_buff *skb); +#endif +static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int ace_set_mac_addr(struct net_device *dev, void *p); static struct net_device_stats *ace_get_stats(struct net_device *dev); static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset); diff -u --recursive --new-file v2.3.16/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h --- v2.3.16/linux/drivers/net/acenic_firmware.h Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/acenic_firmware.h Sat Sep 4 13:11:36 1999 @@ -1,18 +1,27 @@ +/* + * Declare these here even if Tigon I support is disabled to avoid + * the compiler complaining about undefined symbols. + */ +#define tigonFwReleaseMajor 0xc +#define tigonFwReleaseMinor 0x3 +#define tigonFwReleaseFix 0xd +#define tigonFwStartAddr 0x00004000 +#define tigonFwTextAddr 0x00004000 +#define tigonFwTextLen 0x10920 +#define tigonFwRodataAddr 0x00014920 +#define tigonFwRodataLen 0xaa0 +#define tigonFwDataAddr 0x000153e0 +#define tigonFwDataLen 0x150 +#define tigonFwSbssAddr 0x00015530 +#define tigonFwSbssLen 0x2c +#define tigonFwBssAddr 0x00015560 +#define tigonFwBssLen 0x2080 +u32 tigonFwText[]; +u32 tigonFwData[]; +u32 tigonFwRodata[]; + +#ifndef CONFIG_ACENIC_OMIT_TIGON_I /* Generated by genfw.c */ -int tigonFwReleaseMajor = 0xc; -int tigonFwReleaseMinor = 0x3; -int tigonFwReleaseFix = 0xa; -u32 tigonFwStartAddr = 0x00004000; -u32 tigonFwTextAddr = 0x00004000; -int tigonFwTextLen = 0x10920; -u32 tigonFwRodataAddr = 0x00014920; -int tigonFwRodataLen = 0xaa0; -u32 tigonFwDataAddr = 0x000153e0; -int tigonFwDataLen = 0x150; -u32 tigonFwSbssAddr = 0x00015530; -int tigonFwSbssLen = 0x2c; -u32 tigonFwBssAddr = 0x00015560; -int tigonFwBssLen = 0x2080; u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, @@ -20,13 +29,13 @@ 0xc00100c, 0x0, 0xd, 0x27bdffd8, 0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021, 0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8, -0xafbf0024, 0xc00248c, 0xafb00020, 0xc0023ec, +0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8, 0x0, 0x3c040001, 0x24844984, 0x24050001, 0x2e03021, 0x3821, 0x3c100001, 0x261075e0, -0xafb00010, 0xc002407, 0xafbb0014, 0x3c02000f, +0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f, 0x3442ffff, 0x2021024, 0x362102b, 0x10400009, 0x24050003, 0x3c040001, 0x24844990, 0x2003021, -0x3603821, 0x3c020010, 0xafa20010, 0xc002407, +0x3603821, 0x3c020010, 0xafa20010, 0xc002403, 0xafa00014, 0x2021, 0x3405c000, 0x3c010001, 0x370821, 0xa02083b0, 0x3c010001, 0x370821, 0xa02083b2, 0x3c010001, 0x370821, 0xa02083b3, @@ -64,12 +73,12 @@ 0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d, 0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001, 0x2484499c, 0x3c050001, 0xafa00010, 0xafa00014, -0x8ee704fc, 0x34a5f000, 0xc002407, 0x603021, -0x26e40030, 0xc00248c, 0x24050400, 0x27440080, -0xc00248c, 0x24050080, 0x26e4777c, 0xc00248c, +0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021, +0x26e40030, 0xc002488, 0x24050400, 0x27440080, +0xc002488, 0x24050080, 0x26e4777c, 0xc002488, 0x24050400, 0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260, 0x27450200, 0x24060008, 0xaee20068, -0x24020006, 0xc00249e, 0xaee20064, 0x3c023b9a, +0x24020006, 0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00, 0x2021, 0x24030002, 0xaee30074, 0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104, 0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001, @@ -84,10 +93,10 @@ 0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700, 0x8ee204c0, 0x24030001, 0xa2e34e20, 0x34420e00, 0xaee204c0, 0x8f420218, 0x30420100, 0x10400005, -0x0, 0x3c020001, 0x2442e178, 0x800111d, -0x21100, 0x3c020001, 0x2442d36c, 0x21100, +0x0, 0x3c020001, 0x2442e168, 0x800111d, +0x21100, 0x3c020001, 0x2442d35c, 0x21100, 0x21182, 0x3c030800, 0x431025, 0x3c010001, -0xac221238, 0x3c020001, 0x2442f690, 0x21100, +0xac221238, 0x3c020001, 0x2442f680, 0x21100, 0x21182, 0x3c030800, 0x431025, 0x3c010001, 0xac221278, 0x8ee20000, 0x34424000, 0x8001238, 0xaee20000, 0x34423000, 0xafa20018, 0x8ee20608, @@ -121,7 +130,7 @@ 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, 0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, -0xc002407, 0x34a5f000, 0x8001223, 0x0, +0xc002403, 0x34a5f000, 0x8001223, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, @@ -146,28 +155,28 @@ 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x14c0001b, 0x0, 0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014, -0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, +0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x8001223, 0x8ee201b0, 0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, -0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, +0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001, 0x248449c8, 0x3405f001, 0x24420001, 0xaee20160, 0x8ee20160, 0x3021, 0x3821, 0xafa00010, -0xc002407, 0xafa00014, 0x8001238, 0x0, -0x3c020001, 0x2442f5b8, 0x21100, 0x21182, +0xc002403, 0xafa00014, 0x8001238, 0x0, +0x3c020001, 0x2442f5a8, 0x21100, 0x21182, 0x431025, 0x3c010001, 0xac221278, 0x96e2045a, 0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8, 0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8, 0x3c040001, 0x248449d4, 0x24020001, 0xa2e204ec, 0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001, -0x2442a3a0, 0x451024, 0x21082, 0xaee304c8, +0x2442a390, 0x451024, 0x21082, 0xaee304c8, 0x3c030800, 0x431025, 0x3c010001, 0xac221220, -0x3c020001, 0x2442ade4, 0x451024, 0x21082, +0x3c020001, 0x2442add4, 0x451024, 0x21082, 0x431025, 0x3c010001, 0xac221280, 0x96e6045a, -0x3821, 0x24050011, 0xafa00010, 0xc002407, +0x3821, 0x24050011, 0xafa00010, 0xc002403, 0xafa00014, 0x8001268, 0x0, 0x3c020001, -0x2442a9e4, 0x21100, 0x21182, 0x3c030800, +0x2442a9d4, 0x21100, 0x21182, 0x3c030800, 0x431025, 0x3c010001, 0xac221280, 0x96e2046a, 0x30420010, 0x14400009, 0x0, 0x96e2047a, 0x30420010, 0x10400112, 0x0, 0x96e2046a, @@ -203,7 +212,7 @@ 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, 0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, +0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000, 0x800136d, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, @@ -229,16 +238,16 @@ 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x14c0001b, 0x0, 0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, +0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0, 0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, +0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001, 0x248449c8, 0x3405f002, 0x24420001, 0xaee20160, 0x8ee20160, 0x3021, -0x3821, 0xafa00010, 0xc002407, 0xafa00014, +0x3821, 0xafa00010, 0xc002403, 0xafa00014, 0x96e6047a, 0x96e7046a, 0x3c040001, 0x248449e0, -0x24050012, 0xafa00010, 0xc002407, 0xafa00014, +0x24050012, 0xafa00010, 0xc002403, 0xafa00014, 0xc004500, 0x0, 0xc002318, 0x0, 0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228, 0xaf40022c, 0x96e30458, 0x8ee40000, 0x3c0512d8, @@ -281,7 +290,7 @@ 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, 0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, +0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000, 0x80014a5, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, @@ -307,10 +316,10 @@ 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x14c0001b, 0x0, 0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, +0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0, 0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, +0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc, 0x8ee20154, 0x8f8200a0, 0x30420004, 0x1440fffd, @@ -322,7 +331,7 @@ 0x8ee20178, 0x24420001, 0xaee20178, 0x8ee20178, 0x8f8200d8, 0x8f8300d4, 0x431023, 0xaee2726c, 0x8ee2726c, 0x1c400003, 0x3c030001, 0x431021, -0xaee2726c, 0xc004068, 0x0, 0xc004440, +0xaee2726c, 0xc004064, 0x0, 0xc004440, 0xaf800228, 0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, 0x3e00008, 0x0, 0x3e00008, 0x0, 0x0, 0x0, 0x2402002c, @@ -350,7 +359,7 @@ 0x8f8200b4, 0x1462007c, 0x0, 0x3c070001, 0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001, 0x24844a50, 0xafa00014, 0xafa20010, 0x8f8600b0, -0x3c050005, 0xc002407, 0x34a50900, 0x8f82011c, +0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, @@ -382,7 +391,7 @@ 0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001, 0xf73821, 0x8ce783d0, 0x3c040001, 0x24844a64, 0x3c010001, 0x370821, 0xac2283d4, 0xafa00010, -0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002407, +0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403, 0x34a50900, 0x80015cc, 0x0, 0x8f820104, 0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4, 0x3c010001, 0x370821, 0xac2283d4, 0x8ee27274, @@ -415,7 +424,7 @@ 0x24020001, 0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4, 0x3c040001, 0x24844a6c, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, -0xc002407, 0x34a5f006, 0x16000003, 0x24020001, +0xc002403, 0x34a5f006, 0x16000003, 0x24020001, 0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274, 0xaee204f8, 0x8ee20e1c, @@ -444,7 +453,7 @@ 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001, 0x24844a78, 0xafa00014, 0xafa20010, 0x8ee6724c, -0x8f470280, 0x3c050009, 0xc002407, 0x34a5f008, +0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001, 0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019, 0x0, 0xaee04e24, 0x8f820040, 0x30420001, @@ -557,7 +566,7 @@ 0x24844a84, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001, 0x24844a90, 0xafa00010, 0xafa00014, 0x8f860120, -0x8f870124, 0x34a5f010, 0xc002407, 0x8021, +0x8f870124, 0x34a5f010, 0xc002403, 0x8021, 0x800197c, 0x0, 0x3c040001, 0x24844a9c, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228, @@ -590,7 +599,7 @@ 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x5600000c, 0xaee90608, 0x3c040001, 0x24844aa8, 0xafa00010, 0xafa00014, -0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, +0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000, 0x800197c, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, @@ -616,11 +625,11 @@ 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600001d, 0x24100001, 0x3c040001, 0x24844ab0, 0xafa00010, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, +0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c, 0x8ee201b0, 0x3c040001, 0x24844abc, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005, -0xc002407, 0x0, 0x8ee201ac, 0x8021, +0xc002403, 0x0, 0x8ee201ac, 0x8021, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c, 0x24020001, 0x3c010001, 0x370821, 0xa02083b0, 0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158, @@ -691,12 +700,12 @@ 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x10620022, 0x0, 0x3c040001, 0x24844a84, 0xafa00010, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, +0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011, 0x8001aad, 0x0, 0x3c040001, 0x24844a90, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, -0xc002407, 0x34a5f010, 0x8001aad, 0x0, +0xc002403, 0x34a5f010, 0x8001aad, 0x0, 0x3c040001, 0x24844a9c, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, +0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, 0x8ee204d4, 0x30420001, 0x10400055, 0x0, @@ -732,7 +741,7 @@ 0xaf820044, 0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b88, 0x24430001, 0x28421389, 0x14400005, 0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044, -0xaee07b88, 0xc0045c1, 0x0, 0x8fbf0024, +0xaee07b88, 0xc0045c2, 0x0, 0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8, 0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038, 0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028, @@ -743,14 +752,14 @@ 0x10400004, 0x24020001, 0xaf820064, 0x80022f4, 0x0, 0x32c20002, 0x1440000c, 0x3c050003, 0x3c040001, 0x24844b34, 0x34a50001, 0x2c03021, -0x3821, 0xafa00010, 0xc002407, 0xafa00014, +0x3821, 0xafa00010, 0xc002403, 0xafa00014, 0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c, 0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c, 0x21080, 0x5a1021, 0x8c420300, 0xafa20020, 0x8f42022c, 0x24070001, 0x24420001, 0x3042003f, 0x8001b80, 0xaf42022c, 0x3c040001, 0x24844b40, 0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003, -0xc002407, 0x34a5f01f, 0x3821, 0x14e00003, +0xc002403, 0x34a5f01f, 0x3821, 0x14e00003, 0x0, 0x80022ed, 0xaf960064, 0x93a20020, 0x2443ffff, 0x2c620011, 0x10400658, 0x31080, 0x3c010001, 0x220821, 0x8c224bf8, 0x400008, @@ -770,7 +779,7 @@ 0x41cc2, 0x431023, 0x41d02, 0x431021, 0x41d42, 0x431023, 0x8001bd0, 0xaee20078, 0x3c040001, 0x24844b4c, 0xafa00014, 0x8fa60020, -0x3c050003, 0xc002407, 0x34a50004, 0x8ee20110, +0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110, 0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110, 0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, 0x920c0, 0x2e41021, 0x9442727c, 0x30424000, @@ -786,7 +795,7 @@ 0x618c0, 0x610c0, 0x571821, 0x8c63737c, 0x571021, 0xafa30010, 0x8c427380, 0x3c040001, 0x24844b58, 0xafa20014, 0x8f470214, 0x3c050003, -0xc002407, 0x34a50013, 0x8001c90, 0x3c020800, +0xc002403, 0x34a50013, 0x8001c90, 0x3c020800, 0x97440212, 0x771021, 0xa444737e, 0x8f440214, 0x771021, 0x2e31821, 0xac447380, 0x34028000, 0xa462737c, 0x910c0, 0x2e21021, 0x8001c79, @@ -804,7 +813,7 @@ 0x4c10023, 0x618c0, 0x910c0, 0x571821, 0x8c63727c, 0x571021, 0xafa30010, 0x8c427280, 0x3c040001, 0x24844b64, 0xafa20014, 0x8f470214, -0x3c050003, 0xc002407, 0x34a5f017, 0x8001c90, +0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90, 0x3c020800, 0x8f430210, 0xb71021, 0xac43777c, 0x8f430214, 0xb71021, 0xac437780, 0x3c020001, 0x571021, 0x8c4283b4, 0x24420001, 0x3c010001, @@ -880,12 +889,12 @@ 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x10620022, 0x0, 0x3c040001, 0x24844b70, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, -0x3c050009, 0xc002407, 0x34a5f011, 0x8001da0, +0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0, 0x0, 0x3c040001, 0x24844b7c, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, +0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010, 0x8001da0, 0x0, 0x3c040001, 0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, +0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124, 0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124, 0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, @@ -901,7 +910,7 @@ 0xa462727c, 0x8f420214, 0xafa20010, 0x910c0, 0x571021, 0x8c42727c, 0x3c040001, 0x24844b94, 0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c, -0xc002407, 0x1203021, 0x8001e83, 0x3c020800, +0xc002403, 0x1203021, 0x8001e83, 0x3c020800, 0xb71021, 0x9443727e, 0x97420212, 0x14620019, 0x918c0, 0xb71021, 0x8c437280, 0x8f420214, 0x14620014, 0x918c0, 0x2e51021, 0x9447727c, @@ -929,7 +938,7 @@ 0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c, 0x3c040001, 0x24844ba0, 0x3c050003, 0xafa20010, 0x710c0, 0x571021, 0x8c42737c, 0x34a5001e, -0x1203021, 0xc002407, 0xafa20014, 0x8001e83, +0x1203021, 0xc002403, 0xafa20014, 0x8001e83, 0x3c020800, 0x2021, 0x428c0, 0xb71021, 0x9443777e, 0x97420212, 0x5462002b, 0x24840001, 0xb71021, 0x8c437780, 0x8f420214, 0x54620026, @@ -937,11 +946,11 @@ 0x2442ffff, 0x3c010001, 0x370821, 0xac2283b4, 0x3c020001, 0x571021, 0x8c4283b4, 0x809021, 0x242102b, 0x1040000e, 0x24b1777c, 0x24b07784, -0x2f02021, 0x2f12821, 0xc002494, 0x24060008, +0x2f02021, 0x2f12821, 0xc002490, 0x24060008, 0x26310008, 0x3c020001, 0x571021, 0x8c4283b4, 0x26520001, 0x242102b, 0x1440fff5, 0x26100008, 0x3c040001, 0x972021, 0x8c8483b4, 0x24050008, -0x420c0, 0x2484777c, 0xc00248c, 0x2e42021, +0x420c0, 0x2484777c, 0xc002488, 0x2e42021, 0x8001e83, 0x3c020800, 0x2c820080, 0x1440ffcf, 0x428c0, 0x3c020800, 0x34422000, 0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff, @@ -1005,12 +1014,12 @@ 0x0, 0x316300ff, 0x24020001, 0x10620022, 0x0, 0x3c040001, 0x24844b70, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, -0xc002407, 0x34a5f011, 0x8001f93, 0x0, +0xc002403, 0x34a5f011, 0x8001f93, 0x0, 0x3c040001, 0x24844b7c, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, +0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010, 0x8001f93, 0x0, 0x3c040001, 0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, -0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, +0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001, 0xaee20128, 0x8ee20128, 0x8ee20164, 0x24420001, 0xaee20164, 0x80022e8, 0x8ee20164, 0x8fa20020, @@ -1021,7 +1030,7 @@ 0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8, 0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228, 0x8001fbe, 0xa2e004d8, 0x3c040001, 0x24844ba8, -0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, +0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, 0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c, 0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200, 0x22502, 0x24020001, 0x10820005, 0x24020002, @@ -1032,7 +1041,7 @@ 0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024, 0xaf820220, 0x3c010001, 0x370821, 0xa02083b2, 0x8001fea, 0xaee40108, 0x3c040001, 0x24844bb4, -0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, +0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, 0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c, 0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200, 0x21d02, 0x24020001, 0x10620005, 0x24020002, @@ -1044,21 +1053,21 @@ 0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024, 0x8002018, 0xaf820220, 0x3c040001, 0x24844bc0, 0xafa00014, 0x8fa60020, -0x3c050003, 0xc002407, 0x34a5f00b, 0x8ee20114, +0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114, 0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114, -0x27840208, 0x27450200, 0xc00249e, 0x24060008, -0x26e40094, 0x27450200, 0xc00249e, 0x24060008, +0x27840208, 0x27450200, 0xc00249a, 0x24060008, +0x26e40094, 0x27450200, 0xc00249a, 0x24060008, 0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8, 0x8ee20134, 0x8f460248, 0x2021, 0xc004fa8, 0x24050004, 0x8ee20130, 0x24420001, 0xaee20130, 0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0, 0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001, 0xaee20140, 0x8ef00140, 0x8ef10074, 0x8ef20070, -0xc00248c, 0x24050400, 0xaef301cc, 0xaef401d0, +0xc002488, 0x24050400, 0xaef301cc, 0xaef401d0, 0xaef501d8, 0xaef00140, 0xaef10074, 0xaef20070, 0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260, 0x27450200, 0x24060008, 0xaee20068, 0x24020006, -0xc00249e, 0xaee20064, 0x3c023b9a, 0x3442ca00, +0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00, 0xaee2006c, 0x240203e8, 0x24040002, 0x24030001, 0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220, 0x30420008, 0x10400004, 0x0, 0xaee30108, @@ -1145,22 +1154,22 @@ 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x10620022, 0x0, 0x3c040001, 0x24844b70, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, -0x3c050009, 0xc002407, 0x34a5f011, 0x80021c4, +0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4, 0x0, 0x3c040001, 0x24844b7c, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, +0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010, 0x80021c4, 0x0, 0x3c040001, 0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, +0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120, 0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168, 0x24420001, 0xaee20168, 0x80022e8, 0x8ee20168, 0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260, -0x27450200, 0x24060008, 0xc00249e, 0xaee20068, +0x27450200, 0x24060008, 0xc00249a, 0xaee20068, 0x8f820220, 0x30420008, 0x14400002, 0x24020001, 0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001, 0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001, 0x24844bcc, 0xafa00010, 0xafa00014, 0x8fa60020, -0x3c050003, 0xc002407, 0x34a5f00f, 0x93a20020, +0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020, 0x3c030700, 0x34631000, 0x431025, 0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608, 0x210c0, @@ -1192,7 +1201,7 @@ 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x54e0000c, 0xaee90608, 0x3c040001, 0x24844bd4, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002407, 0x34a5f000, 0x80022e0, +0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, @@ -1218,10 +1227,10 @@ 0xac820000, 0x24020001, 0xac820004, 0x14e0001b, 0x0, 0x3c040001, 0x24844bdc, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, -0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, +0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001, 0x24844be8, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, +0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150, 0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160, 0x24420001, 0xaee20160, 0x8ee20160, 0x8f43022c, @@ -1237,7 +1246,7 @@ 0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842, 0x25290001, 0x125102b, 0x1440fff0, 0x0, 0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffe8, -0x27642800, 0xafbf0010, 0xc00248c, 0x24051000, +0x27642800, 0xafbf0010, 0xc002488, 0x24051000, 0x24020021, 0xaf800100, 0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114, 0xaf800118, 0xaf800120, 0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134, @@ -1247,32 +1256,31 @@ 0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010, 0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0, -0x8f87011c, 0x3c040001, 0x24844ca0, 0xc002407, +0x8f87011c, 0x3c040001, 0x24844ca0, 0xc002403, 0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824, -0x3c020400, 0x1062002b, 0x43102b, 0x14400008, -0x3c022000, 0x3c020100, 0x10620026, 0x3c020200, -0x10620013, 0x0, 0x8002376, 0x0, -0x1062000a, 0x43102b, 0x1040001e, 0x3c024000, -0x1462001c, 0x0, 0x8ee20190, 0x24420001, -0xaee20190, 0x8002376, 0x8ee20190, 0x8ee2018c, -0x24420001, 0xaee2018c, 0x8002376, 0x8ee2018c, -0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, -0x8f8200b0, 0x34420001, 0xaf8200b0, 0xaf830104, -0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, -0x8ee201a0, 0x24420001, 0xaee201a0, 0x8002379, -0x8ee201a0, 0x8f8200b0, 0x34420001, 0xaf8200b0, -0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, -0xafbf001c, 0xafb00018, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c050001, 0xafa20014, 0x8f8600a0, -0x8f87011c, 0x3c040001, 0x24844cac, 0xc002407, -0x34a5f000, 0x8f8300a0, 0x3c027f00, 0x621824, -0x3c020400, 0x10620055, 0x8021, 0x43102b, -0x14400008, 0x3c042000, 0x3c020100, 0x1062004f, -0x3c020200, 0x1062003c, 0x0, 0x80023e4, -0x0, 0x10640005, 0x83102b, 0x10400047, +0x3c020400, 0x10620029, 0x43102b, 0x14400008, +0x3c022000, 0x3c020100, 0x10620024, 0x3c020200, +0x10620011, 0x0, 0x8002374, 0x0, +0x10620008, 0x3c024000, 0x1462001c, 0x0, +0x8ee20190, 0x24420001, 0xaee20190, 0x8002374, +0x8ee20190, 0x8ee2018c, 0x24420001, 0xaee2018c, +0x8002374, 0x8ee2018c, 0x8f82011c, 0x34420002, +0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, +0xaf8200b0, 0xaf830104, 0x8f82011c, 0x2403fffd, +0x431024, 0xaf82011c, 0x8ee201a0, 0x24420001, +0xaee201a0, 0x8002377, 0x8ee201a0, 0x8f8200b0, +0x34420001, 0xaf8200b0, 0x8fbf0018, 0x3e00008, +0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018, +0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001, +0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001, +0x24844cac, 0xc002403, 0x34a5f000, 0x8f8300a0, +0x3c027f00, 0x621824, 0x3c020400, 0x10620053, +0x8021, 0x43102b, 0x14400008, 0x3c042000, +0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a, +0x0, 0x80023e0, 0x0, 0x10640003, 0x3c024000, 0x14620045, 0x0, 0x8f8200a0, 0x441024, 0x10400006, 0x0, 0x8ee20194, -0x24420001, 0xaee20194, 0x80023ad, 0x8ee20194, +0x24420001, 0xaee20194, 0x80023a9, 0x8ee20194, 0x8ee20198, 0x24420001, 0xaee20198, 0x8ee20198, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f82011c, 0x30420200, 0x1040001b, 0x0, 0x8f8300a0, @@ -1281,18 +1289,18 @@ 0x24100001, 0x24020001, 0x1200000d, 0xaf8200a0, 0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124, 0x8f820124, 0x27633000, 0x43102b, 0x10400005, -0x276237e0, 0xaf820124, 0x80023ce, 0x0, +0x276237e0, 0xaf820124, 0x80023ca, 0x0, 0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024, -0x80023e7, 0xaf82011c, 0x8f82011c, 0x34420002, +0x80023e3, 0xaf82011c, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001, 0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee2019c, 0x24420001, -0xaee2019c, 0x80023e7, 0x8ee2019c, 0x8f8200a0, +0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0, 0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 0x0, 0x3c020001, 0x8c425418, 0x27bdffe8, 0xafbf0014, 0x14400012, 0xafb00010, 0x3c100001, 0x26105560, 0x2002021, -0xc00248c, 0x24052000, 0x26021fe0, 0x3c010001, +0xc002488, 0x24052000, 0x26021fe0, 0x3c010001, 0xac225534, 0x3c010001, 0xac225530, 0xaf420250, 0x24022000, 0xaf500254, 0xaf420258, 0x24020001, 0x3c010001, 0xac225418, 0x8fbf0014, 0x8fb00010, @@ -1313,8 +1321,8 @@ 0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018, 0xac620000, 0x3c050001, 0x8ca55534, 0x3c020001, 0x8c425400, 0xc09021, 0xe09821, 0x10800006, -0xaca20004, 0x24a50008, 0xc002494, 0x24060018, -0x8002452, 0x0, 0x24a40008, 0xc00248c, +0xaca20004, 0x24a50008, 0xc002490, 0x24060018, +0x800244e, 0x0, 0x24a40008, 0xc002488, 0x24050018, 0x3c020001, 0x8c425534, 0x3c050001, 0x24a55560, 0x2442ffe0, 0x3c010001, 0xac225534, 0x45102b, 0x10400005, 0x0, 0x3c020001, @@ -1347,13 +1355,13 @@ 0x3c030001, 0x431021, 0xaee2726c, 0x8ee2725c, 0x8ee3726c, 0x441021, 0x62182b, 0x10600006, 0x31a20004, 0x8ee201b8, 0x24420001, 0xaee201b8, -0x80028e5, 0x8ee201b8, 0x10400240, 0x31a20200, +0x80028e1, 0x8ee201b8, 0x10400240, 0x31a20200, 0x1040014d, 0x4821, 0x96e2045a, 0x30420010, 0x10400149, 0x0, 0x8f840100, 0x27623000, 0x24850020, 0xa2102b, 0x50400001, 0x27652800, 0x8f820108, 0x10a20004, 0x0, 0x8f820104, 0x14a20006, 0x2402000c, 0x8ee201a8, 0x24420001, -0xaee201a8, 0x8002530, 0x8ee201a8, 0xac8a0000, +0xaee201a8, 0x800252c, 0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e, 0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010, 0xaf850100, 0x92e204ec, @@ -1363,17 +1371,17 @@ 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, -0x0, 0x800251a, 0x0, 0x14a00005, +0x0, 0x8002516, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x8002530, 0x0, 0x8ee24e28, +0xac800000, 0x800252c, 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, -0x80028c2, 0x34a5f114, 0x8ee27264, 0x34843800, +0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800, 0x3641821, 0x24420010, 0x43102b, 0x14400073, 0x0, 0x8ee27264, 0x24480010, 0x3641021, 0x102102b, 0x14400002, 0x3c02ffff, 0x1024021, @@ -1381,7 +1389,7 @@ 0x50400001, 0x27662800, 0x8f820108, 0x10c20004, 0x0, 0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8, -0x80025a4, 0x8ee201a8, 0x2c64000c, 0x1441021, +0x80025a0, 0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8, 0x3c030002, 0x431025, @@ -1392,22 +1400,22 @@ 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, -0x0, 0x800258e, 0x0, 0x14a00005, +0x0, 0x800258a, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x80025a4, 0x0, 0x8ee24e28, +0xac800000, 0x80025a0, 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, -0x80028c2, 0x34a5f125, 0x34028100, 0xa5020000, -0x9582000e, 0x8002621, 0xa5020002, 0x8f850100, +0x80028be, 0x34a5f125, 0x34028100, 0xa5020000, +0x9582000e, 0x800261d, 0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, 0xc2102b, 0x50400001, 0x27662800, 0x8f820108, 0x10c20004, 0x0, 0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8, -0x4821, 0x24420001, 0xaee201a8, 0x8002611, +0x4821, 0x24420001, 0xaee201a8, 0x800260d, 0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018, 0x24630010, 0xaca30008, @@ -1419,23 +1427,23 @@ 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, 0x24420001, -0x10a20005, 0x0, 0x80025fb, 0x0, +0x10a20005, 0x0, 0x80025f7, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x8002611, 0x0, +0x50400013, 0xac800000, 0x800260d, 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, -0x8ee604e4, 0x80028c2, 0x34a5f015, 0x8ee37264, +0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264, 0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e, -0x8002685, 0x24e70004, 0x8f840100, 0x27623000, +0x8002681, 0x24e70004, 0x8f840100, 0x27623000, 0x24850020, 0xa2102b, 0x50400001, 0x27652800, 0x8f820108, 0x10a20004, 0x0, 0x8f820104, 0x14a20007, 0x24020006, 0x8ee201a8, 0x4821, -0x24420001, 0xaee201a8, 0x800267b, 0x8ee201a8, +0x24420001, 0xaee201a8, 0x8002677, 0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264, 0xa487000e, 0xac820018, 0xac830008, 0x8ee204e4, 0xac82001c, 0x8ee204c8, 0x3c030002, 0x431025, 0xac820010, @@ -1446,16 +1454,16 @@ 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, -0x8002665, 0x0, 0x14a00005, 0x0, +0x8002661, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x800267b, 0x0, 0x8ee24e28, 0x24030040, +0x8002677, 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x15200009, 0x3c050004, 0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, -0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f004, +0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004, 0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c, 0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100, 0x431021, 0xac44000c, 0x8ee27258, 0xafa20018, @@ -1470,34 +1478,34 @@ 0xaee27264, 0x8f8200f0, 0x24470008, 0x27621800, 0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4, 0x4821, -0x24420001, 0xaee201b4, 0x80026c8, 0x8ee201b4, +0x24420001, 0xaee201b4, 0x80026c4, 0x8ee201b4, 0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0, 0x15200012, 0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4, 0x3c040001, 0x24844f1c, 0xafa20014, 0x8fa60018, -0x8fa7001c, 0x3c050004, 0xc002407, 0x34a5f005, +0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005, 0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088, -0x80028d7, 0xaee0725c, 0x30430003, 0x24020002, +0x80028d3, 0xaee0725c, 0x30430003, 0x24020002, 0x10620016, 0x28620003, 0x10400005, 0x24020001, -0x10620008, 0x0, 0x8002707, 0x0, -0x24020003, 0x10620017, 0x0, 0x8002707, +0x10620008, 0x0, 0x8002703, 0x0, +0x24020003, 0x10620017, 0x0, 0x8002703, 0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001, 0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec, -0x8ee200e8, 0x8002707, 0x8ee300ec, 0x8ee200f0, +0x8ee200e8, 0x8002703, 0x8ee300ec, 0x8ee200f0, 0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, -0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002707, +0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002703, 0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001, 0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, 0x8ee200f8, 0x8ee300fc, 0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x401821, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaee400e0, -0xaee500e4, 0x80028d7, 0xaee0725c, 0x30e2ffff, +0xaee500e4, 0x80028d3, 0xaee0725c, 0x30e2ffff, 0x104001c1, 0x31a20200, 0x1040014d, 0x4821, 0x96e2045a, 0x30420010, 0x10400149, 0x0, 0x8f840100, 0x27623000, 0x24850020, 0xa2102b, 0x50400001, 0x27652800, 0x8f820108, 0x10a20004, 0x0, 0x8f820104, 0x14a20006, 0x2402000c, -0x8ee201a8, 0x24420001, 0xaee201a8, 0x8002772, +0x8ee201a8, 0x24420001, 0xaee201a8, 0x800276e, 0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e, 0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010, @@ -1507,17 +1515,17 @@ 0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, -0x24420001, 0x10a20005, 0x0, 0x800275c, +0x24420001, 0x10a20005, 0x0, 0x8002758, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8002772, +0x2c420011, 0x50400013, 0xac800000, 0x800276e, 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, -0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f014, +0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014, 0x8ee27264, 0x34843800, 0x3641821, 0x24420010, 0x43102b, 0x14400073, 0x0, 0x8ee27264, 0x24480010, 0x3641021, 0x102102b, 0x14400002, @@ -1525,7 +1533,7 @@ 0x24a60020, 0xc2102b, 0x50400001, 0x27662800, 0x8f820108, 0x10c20004, 0x0, 0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821, -0x24420001, 0xaee201a8, 0x80027e6, 0x8ee201a8, +0x24420001, 0xaee201a8, 0x80027e2, 0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8, @@ -1536,23 +1544,23 @@ 0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, -0x24420001, 0x10a20005, 0x0, 0x80027d0, +0x24420001, 0x10a20005, 0x0, 0x80027cc, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x80027e6, +0x2c420011, 0x50400013, 0xac800000, 0x80027e2, 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, -0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f015, -0x34028100, 0xa5020000, 0x9582000e, 0x8002863, +0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015, +0x34028100, 0xa5020000, 0x9582000e, 0x800285f, 0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, 0xc2102b, 0x50400001, 0x27662800, 0x8f820108, 0x10c20004, 0x0, 0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821, 0x24420001, -0xaee201a8, 0x8002853, 0x8ee201a8, 0x2c64000c, +0xaee201a8, 0x800284f, 0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018, 0x24630010, 0xaca30008, 0x8ee204e4, 0xaca2001c, @@ -1564,23 +1572,23 @@ 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, -0x800283d, 0x0, 0x14a00005, 0x0, +0x8002839, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x8002853, 0x0, 0x8ee24e28, 0x24030040, +0x800284f, 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, -0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, +0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264, -0x9582000e, 0xa462000e, 0x80028c6, 0x24e70004, +0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004, 0x8f830100, 0x27623000, 0x24640020, 0x82102b, 0x50400001, 0x27642800, 0x8f820108, 0x10820004, 0x0, 0x8f820104, 0x14820007, 0x24050005, 0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8, -0x80028ba, 0x8ee201a8, 0xac6a0000, 0xac6b0004, +0x80028b6, 0x8ee201a8, 0xac6a0000, 0xac6b0004, 0x8ee27264, 0xa467000e, 0xac650018, 0xac620008, 0x8ee204e4, 0xac62001c, 0x8ee204c8, 0xac620010, 0xaf840100, 0x92e204ec, 0x14400036, 0x24090001, @@ -1589,17 +1597,17 @@ 0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, -0x24420001, 0x10a20005, 0x0, 0x80028a4, +0x24420001, 0x10a20005, 0x0, 0x80028a0, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x80028ba, +0x2c420011, 0x50400013, 0xac800000, 0x80028b6, 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000b, 0x3c050004, 0x3c040001, 0x24844f28, 0xafab0010, 0xafa00014, 0x8ee604e4, -0x34a5f017, 0xc002407, 0x30e7ffff, 0x80028e5, +0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1, 0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff, 0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264, 0x34a53800, 0x441021, 0xaee2725c, 0x3651021, @@ -1620,14 +1628,14 @@ 0xaee27264, 0x8ee37264, 0x42400, 0x3651021, 0x3c010001, 0x370821, 0xac2483dc, 0x62182b, 0x14600005, 0x24e70004, 0x8ee27264, 0x3c03ffff, -0x431021, 0xaee27264, 0x8ee27264, 0x800291b, +0x431021, 0xaee27264, 0x8ee27264, 0x8002917, 0xaee27258, 0x8ee604c8, 0x8ee2726c, 0x30e4ffff, 0x44102a, 0x10400015, 0x0, 0x8f8200d8, 0x8ee37258, 0x431023, 0xaee2726c, 0x8ee2726c, 0x1c400007, 0x44102a, 0x8ee2726c, 0x3c030001, 0x431021, 0xaee2726c, 0x8ee2726c, 0x44102a, 0x10400006, 0x0, 0x8ee201b8, 0x24420001, -0xaee201b8, 0x8002a76, 0x8ee201b8, 0x3c020001, +0xaee201b8, 0x8002a72, 0x8ee201b8, 0x3c020001, 0x571021, 0x8c4283d8, 0x54400001, 0x24e7fffc, 0x31420004, 0x104000b9, 0x30e2ffff, 0x3c020001, 0x571021, 0x8c4283d8, 0x1040002f, 0x5021, @@ -1642,11 +1650,11 @@ 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e21821, 0x24020015, 0xac620000, 0x24020001, -0x80029c3, 0xac620004, 0x8f840100, 0x27623000, +0x80029bf, 0xac620004, 0x8f840100, 0x27623000, 0x24850020, 0xa2102b, 0x50400001, 0x27652800, 0x8f820108, 0x10a20004, 0x0, 0x8f820104, 0x14a20006, 0x24020006, 0x8ee201a8, 0x24420001, -0xaee201a8, 0x80029c3, 0x8ee201a8, 0xac880000, +0xaee201a8, 0x80029bf, 0x8ee201a8, 0xac880000, 0xac890004, 0x8ee37264, 0xa487000e, 0xac820018, 0xac830008, 0x8ee204e8, 0xac860010, 0xac82001c, 0xaf850100, 0x92e204ec, 0x14400037, 0x240a0001, @@ -1656,16 +1664,16 @@ 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, -0x80029ad, 0x0, 0x14a00005, 0x0, +0x80029a9, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x80029c3, 0x0, 0x8ee24e28, 0x24030040, +0x80029bf, 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1540000a, 0x24020001, 0xafa90010, 0x8ee27264, 0x3c040001, 0x24844f10, -0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a53, +0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f, 0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc, 0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001, 0x370821, 0xac2083d8, 0x3c010001, 0x370821, @@ -1675,12 +1683,12 @@ 0x8ee2726c, 0x8ee47258, 0x651824, 0x431023, 0xaee2726c, 0x3661021, 0x82202b, 0x14800004, 0x3c03ffff, 0x8ee27258, 0x431021, 0xaee27258, -0x8ee27258, 0x8002a68, 0xaee27264, 0x10400073, +0x8ee27258, 0x8002a64, 0xaee27264, 0x10400073, 0x0, 0x8f830100, 0x27623000, 0x24640020, 0x82102b, 0x14400002, 0x5021, 0x27642800, 0x8f820108, 0x10820004, 0x0, 0x8f820104, 0x14820006, 0x24050005, 0x8ee201a8, 0x24420001, -0xaee201a8, 0x8002a4a, 0x8ee201a8, 0xac680000, +0xaee201a8, 0x8002a46, 0x8ee201a8, 0xac680000, 0xac690004, 0x8ee27264, 0xa467000e, 0xac650018, 0xac620008, 0x8ee204e8, 0xac660010, 0xac62001c, 0xaf840100, 0x92e204ec, 0x14400036, 0x240a0001, @@ -1689,18 +1697,18 @@ 0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, -0x24420001, 0x10a20005, 0x0, 0x8002a34, +0x24420001, 0x10a20005, 0x0, 0x8002a30, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8002a4a, +0x2c420011, 0x50400013, 0xac800000, 0x8002a46, 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001, 0x24844f28, 0x3c050004, 0xafa90010, 0xafa00014, -0x8ee604e4, 0x34a5f237, 0xc002407, 0x30e7ffff, -0x8002a76, 0x0, 0x8ee27264, 0x451021, +0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff, +0x8002a72, 0x0, 0x8ee27264, 0x451021, 0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001, 0x34843800, 0xa2e004ed, 0x451023, 0xaee2726c, 0x3641021, 0x62182b, 0x14600004, 0x3c03ffff, @@ -1715,7 +1723,7 @@ 0x24420001, 0xaee24e2c, 0x8ee24e2c, 0x8ee34e2c, 0x210c0, 0x24424e38, 0x2e22021, 0x8ee24e28, 0x8c870004, 0x14620007, 0xa03021, 0x8f820108, -0x24420020, 0xaf820108, 0x8f820108, 0x8002aa6, +0x24420020, 0xaf820108, 0x8f820108, 0x8002aa2, 0xac800000, 0x8ee24e2c, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e2c, 0x24420001, 0x210c0, 0x24424e38, 0x2e22021, 0x8c820004, @@ -1729,7 +1737,7 @@ 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, -0x8021, 0x24420001, 0xaee201a4, 0x8002b16, +0x8021, 0x24420001, 0xaee201a4, 0x8002b12, 0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, @@ -1740,38 +1748,38 @@ 0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007, 0x0, 0x8ee24e34, -0x24420001, 0x10a20005, 0x0, 0x8002b00, +0x24420001, 0x10a20005, 0x0, 0x8002afc, 0x0, 0x14a00005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8002b16, +0x2c420011, 0x50400013, 0xac800000, 0x8002b12, 0x0, 0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4, 0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, -0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, -0x34a5f006, 0x16000003, 0x24020001, 0x8002b75, +0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, +0x34a5f006, 0x16000003, 0x24020001, 0x8002b71, 0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee204f8, 0x8f42023c, 0x50400045, 0xaee07274, 0x8ee20184, 0x24420001, 0xaee20184, 0x8ee20184, -0x8002b75, 0xaee07274, 0x8ee20504, 0x24030040, +0x8002b71, 0xaee07274, 0x8ee20504, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee20504, 0x24420001, 0xaee20504, 0x8ee20504, 0x8cc30018, 0x21080, 0x571021, 0x8c440508, 0x24020003, 0x1462000f, 0x0, 0x3c020001, 0x571021, 0x904283b1, 0x10400014, 0x0, 0x8ee201d0, 0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8, -0x641821, 0x306300ff, 0x8002b5d, 0xaee35240, +0x641821, 0x306300ff, 0x8002b59, 0xaee35240, 0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc, 0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8, 0x8ee20000, 0x34420040, -0x8002b75, 0xaee20000, 0x8ee2014c, 0x3c010001, +0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0, 0x24420001, 0xaee2014c, -0x8002b75, 0x8ee2014c, 0x94c7000e, 0x8cc2001c, +0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c, 0x3c040001, 0x24844f40, 0xafa60014, 0xafa20010, -0x8cc60018, 0x3c050008, 0xc002407, 0x34a50910, +0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910, 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058, 0xafb50054, 0xafb40050, 0xafb3004c, 0xafb20048, @@ -1788,7 +1796,7 @@ 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, -0x8021, 0x24420001, 0xaee201a4, 0x8002c02, +0x8021, 0x24420001, 0xaee201a4, 0x8002bfe, 0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, @@ -1799,10 +1807,10 @@ 0x8ee24e34, 0x1062001b, 0x240c0040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x8002bec, +0x24420001, 0x10620005, 0x0, 0x8002be8, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8002c02, +0x2c420011, 0x50400013, 0xac800000, 0x8002bfe, 0x0, 0x8ee24e30, 0x240c0040, 0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, @@ -1810,8 +1818,8 @@ 0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4, 0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006, -0xc002407, 0xafab0038, 0x8fab0038, 0x1200030a, -0x240c0001, 0x8002f1d, 0x0, 0x966c001c, +0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a, +0x240c0001, 0x8002f19, 0x0, 0x966c001c, 0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024, 0xae62001c, 0x8e75001c, 0x8ee204fc, 0x8ee404fc, 0x151900, 0x621021, 0x8c52000c, 0x92e27b98, @@ -1821,8 +1829,8 @@ 0x8e63001c, 0x8ee204fc, 0x32100, 0x821021, 0x8c42000c, 0x37e1821, 0x24420022, 0x43102b, 0x1440000a, 0x24050014, 0x8ee204fc, 0x821021, -0x8c44000c, 0xafab0038, 0xc002f79, 0x2484000e, -0x8fab0038, 0x8002c56, 0x3050ffff, 0x8ee204fc, +0x8c44000c, 0xafab0038, 0xc002f75, 0x2484000e, +0x8fab0038, 0x8002c52, 0x3050ffff, 0x8ee204fc, 0x821021, 0x8c42000c, 0x9450000e, 0x94430010, 0x94440012, 0x94450014, 0x2038021, 0x2048021, 0x2058021, 0x94430016, 0x94440018, 0x9445001a, @@ -1833,7 +1841,7 @@ 0xa21021, 0x8c43000c, 0x3202ffff, 0x828021, 0x37e1021, 0x24630018, 0x62182b, 0x14600009, 0x0, 0x8ee204fc, 0xa21021, 0x8c43000c, -0x101027, 0x3c01ffff, 0x230821, 0x8002c73, +0x101027, 0x3c01ffff, 0x230821, 0x8002c6f, 0xa4220018, 0x8ee204fc, 0xa21021, 0x8c43000c, 0x101027, 0xa4620018, 0x96e2045a, 0x8821, 0x30420008, 0x14400063, 0xa021, 0x8e63001c, @@ -1851,7 +1859,7 @@ 0x94e20000, 0x24e70002, 0x2228821, 0x37e1021, 0xe2102b, 0x50400001, 0xeb3821, 0x94e20000, 0x24e70002, 0x2228821, 0x37e1021, 0xe2102b, -0x50400001, 0xeb3821, 0x94e20000, 0x8002cd4, +0x50400001, 0xeb3821, 0x94e20000, 0x8002cd0, 0x2228821, 0x8ee204fc, 0xc21021, 0x8c43000c, 0x8ee204fc, 0x94710010, 0x8ee304fc, 0xc21021, 0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec, @@ -1867,8 +1875,8 @@ 0x0, 0x240c0001, 0xa2ec7b98, 0xaef57b9c, 0xaef27ba4, 0x8ee304fc, 0x151100, 0x431021, 0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b, -0x14400008, 0xe02021, 0x2405000e, 0xc002f79, -0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d0d, +0x14400008, 0xe02021, 0x2405000e, 0xc002f75, +0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d09, 0x2028021, 0x94e60000, 0x24e70002, 0x94e50000, 0x24e70002, 0x94e30000, 0x24e70002, 0x94e20000, 0x24e70002, 0x94e40000, 0x24e70002, 0x2068021, @@ -1876,7 +1884,7 @@ 0x94e30002, 0x2048021, 0x2028021, 0x2038021, 0x101c02, 0x3202ffff, 0x628021, 0x101c02, 0x3202ffff, 0x8ee47b9c, 0x628021, 0x14950004, -0x3205ffff, 0x96620016, 0x8002d1b, 0x512021, +0x3205ffff, 0x96620016, 0x8002d17, 0x512021, 0x96620016, 0x542021, 0x41402, 0x3083ffff, 0x432021, 0x852023, 0x41402, 0x822021, 0x3084ffff, 0x50800001, 0x3404ffff, 0x8ee27ba4, @@ -1889,11 +1897,11 @@ 0x3082ffff, 0x622021, 0x32c20100, 0x14400004, 0x41027, 0x92e27b98, 0x14400002, 0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 0x220821, -0x8002d8e, 0xa4240028, 0x8ee27b9c, 0x12a20008, +0x8002d8a, 0xa4240028, 0x8ee27b9c, 0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420028, 0x822021, 0x41c02, 0x3082ffff, 0x622021, 0x32c20100, 0x14400004, 0x41027, 0x92e27b98, 0x14400002, -0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8e, +0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8a, 0xa4440028, 0x1462002f, 0x37e1821, 0x8ee27ba4, 0x24420032, 0x43102b, 0x14400018, 0x0, 0x8ee27b9c, 0x12a2000a, 0x32c20100, 0x8ee27ba4, @@ -1901,7 +1909,7 @@ 0x41c02, 0x3082ffff, 0x622021, 0x32c20100, 0x14400004, 0x41027, 0x92e27b98, 0x14400002, 0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff, -0x220821, 0x8002d8e, 0xa4240032, 0x8ee27b9c, +0x220821, 0x8002d8a, 0xa4240032, 0x8ee27b9c, 0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420032, 0x822021, 0x41c02, 0x3082ffff, 0x622021, 0x32c20100, 0x14400004, 0x41027, 0x92e27b98, @@ -1914,7 +1922,7 @@ 0x37e1021, 0x62102b, 0x50400001, 0x6b1821, 0x8c620000, 0xac820000, 0x34028100, 0xa4620000, 0x24630002, 0x37e1021, 0x62102b, 0x50400001, -0x6b1821, 0x97ac002e, 0x8002db8, 0xa46c0000, +0x6b1821, 0x97ac002e, 0x8002db4, 0xa46c0000, 0x8e420004, 0x8e440008, 0xa6430008, 0x97ac002e, 0xa64c000a, 0xae420000, 0xae440004, 0x9662000e, 0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e, @@ -1924,55 +1932,55 @@ 0xafa2001c, 0x32c20080, 0x1040000c, 0x32c20100, 0x8ee27ba8, 0x24430001, 0x210c0, 0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac, -0xac447bb0, 0x8002ea4, 0xaee0725c, 0x10400072, +0xac447bb0, 0x8002ea0, 0xaee0725c, 0x10400072, 0x0, 0x8ee27ba8, 0x24430001, 0x210c0, 0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac, 0xac447bb0, 0x8ee27ba8, 0x10400063, 0x4821, 0x5021, 0x8f8200f0, 0x24480008, 0x27621800, 0x102102b, 0x50400001, 0x27681000, 0x8f8200f4, 0x15020007, 0x0, 0x8ee201b4, -0x8021, 0x24420001, 0xaee201b4, 0x8002dfe, +0x8021, 0x24420001, 0xaee201b4, 0x8002dfa, 0x8ee201b4, 0x8f8300f0, 0x24100001, 0x1571021, 0x8c447bac, 0x8c457bb0, 0xac640000, 0xac650004, 0xaf8800f0, 0x16000006, 0x2ea1021, 0x8ee20088, -0x24420001, 0xaee20088, 0x8002e43, 0x8ee20088, +0x24420001, 0xaee20088, 0x8002e3f, 0x8ee20088, 0x8c427bb0, 0x8ee400e0, 0x8ee500e4, 0x8ee67b9c, 0x401821, 0x1021, 0xa32821, 0xa3382b, 0x822021, 0x872021, 0x8ee204fc, 0xc93021, 0x63100, 0xaee400e0, 0xaee500e4, 0xc23021, 0x94c2000a, 0x240c0002, 0x21142, 0x30430003, 0x106c0016, 0x28620003, 0x10400005, 0x240c0001, -0x106c0008, 0x0, 0x8002e43, 0x0, -0x240c0003, 0x106c0017, 0x0, 0x8002e43, +0x106c0008, 0x0, 0x8002e3f, 0x0, +0x240c0003, 0x106c0017, 0x0, 0x8002e3f, 0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001, 0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec, -0x8ee200e8, 0x8002e43, 0x8ee300ec, 0x8ee200f0, +0x8ee200e8, 0x8002e3f, 0x8ee300ec, 0x8ee200f0, 0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, -0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e43, +0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e3f, 0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001, 0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, 0x8ee200f8, 0x8ee300fc, 0x8ee27ba8, 0x25290001, 0x122102b, 0x1440ffa0, 0x254a0008, 0xa2e07b98, -0x8002ea3, 0xaee07ba8, 0x8f8200f0, 0x24470008, +0x8002e9f, 0xaee07ba8, 0x8f8200f0, 0x24470008, 0x27621800, 0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4, -0x8021, 0x24420001, 0xaee201b4, 0x8002e61, +0x8021, 0x24420001, 0xaee201b4, 0x8002e5d, 0x8ee201b4, 0x8f8200f0, 0x24100001, 0x8fa30018, 0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0, 0x16000007, 0x0, 0x8ee20088, 0x24420001, -0xaee20088, 0x8ee20088, 0x8002ea4, 0xaee0725c, +0xaee20088, 0x8ee20088, 0x8002ea0, 0xaee0725c, 0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x240c0002, 0x401821, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0x161142, 0x30430003, 0xaee400e0, 0xaee500e4, 0x106c0017, 0x2c620003, 0x10400005, 0x240c0001, 0x106c0008, 0x0, -0x8002ea4, 0xaee0725c, 0x240c0003, 0x106c0019, -0x0, 0x8002ea4, 0xaee0725c, 0x8ee200e8, +0x8002ea0, 0xaee0725c, 0x240c0003, 0x106c0019, +0x0, 0x8002ea0, 0xaee0725c, 0x8ee200e8, 0x8ee300ec, 0x24630001, 0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8ee300ec, -0x8002ea4, 0xaee0725c, 0x8ee200f0, 0x8ee300f4, +0x8002ea0, 0xaee0725c, 0x8ee200f0, 0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, 0xaee200f0, -0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea4, +0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea0, 0xaee0725c, 0x8ee200f8, 0x8ee300fc, 0x24630001, 0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, 0x8ee200f8, 0x8ee300fc, 0xaee0725c, 0x8e62001c, @@ -1983,7 +1991,7 @@ 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, -0x8002f0b, 0x8ee201a4, 0x8ee204e4, 0xac62001c, +0x8002f07, 0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, @@ -1994,22 +2002,22 @@ 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007, 0x0, 0x8ee24e34, 0x24420001, 0x10620005, 0x0, -0x8002ef5, 0x0, 0x14600005, 0x0, +0x8002ef1, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x8002f0b, 0x0, 0x8ee24e30, 0x240c0040, +0x8002f07, 0x0, 0x8ee24e30, 0x240c0040, 0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0x240c0001, 0xac820000, 0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4, 0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, -0x34a5f006, 0xc002407, 0xafab0038, 0x8fab0038, -0x16000003, 0x240c0001, 0x8002f60, 0xa2ec04f4, +0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038, +0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4, 0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274, 0xaee204f8, 0x8f42023c, 0x10400038, 0x0, -0x8ee20184, 0x24420001, 0xaee20184, 0x8002f60, +0x8ee20184, 0x24420001, 0xaee20184, 0x8002f5c, 0x8ee20184, 0x8ee20504, 0x240c0040, 0x24420001, 0x504c0003, 0x1021, 0x8ee20504, 0x24420001, 0xaee20504, 0x8ee20504, 0x8e630018, 0x240c0003, @@ -2017,10 +2025,10 @@ 0x3c020001, 0x571021, 0x904283b1, 0x10400014, 0x0, 0x8ee201d0, 0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8, 0x641821, 0x306300ff, -0x8002f53, 0xaee35240, 0x8ee201cc, 0x8ee30e10, +0x8002f4f, 0xaee35240, 0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc, 0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8, -0x8ee20000, 0x34420040, 0x8002f60, 0xaee20000, +0x8ee20000, 0x34420040, 0x8002f5c, 0xaee20000, 0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0, 0x24420001, 0xaee2014c, 0x8ee2014c, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8f820108, @@ -2049,40 +2057,40 @@ 0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4, -0x80034d0, 0xaf8700e8, 0x3c020001, 0x571021, +0x80034cc, 0xaf8700e8, 0x3c020001, 0x571021, 0x904283c0, 0x1040000b, 0x0, 0x3c140001, 0x297a021, 0x8e9483c4, 0x3c130001, 0x2779821, -0x8e7383c8, 0x3c120001, 0x2579021, 0x8003197, +0x8e7383c8, 0x3c120001, 0x2579021, 0x8003193, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007, 0x8821, 0x8f8200e4, 0x24110001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, 0x3c040001, 0x24845050, 0xafa20014, 0x8f8600e0, -0x8f8700e4, 0x3c050006, 0xc002407, 0x34a5f000, -0x80034d0, 0x0, 0x8fa3001c, 0x8fb20018, +0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000, +0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018, 0x3074ffff, 0x2694fffc, 0x621024, 0x10400058, 0x2409821, 0x3c020080, 0x621024, 0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001, 0xaee201fc, -0x80034ca, 0x8ee201fc, 0x3c060004, 0x3c0b0001, +0x80034c6, 0x8ee201fc, 0x3c060004, 0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080, 0x3c080020, 0x34078000, 0x24420001, 0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021, 0xc3102b, 0x14400007, 0x0, 0x106b0011, -0x0, 0x106a0015, 0x0, 0x800304d, +0x0, 0x106a0015, 0x0, 0x8003049, 0x42042, 0x10650023, 0xa3102b, 0x14400005, -0x0, 0x10690019, 0x0, 0x800304d, -0x42042, 0x10680021, 0x0, 0x800304d, +0x0, 0x10690019, 0x0, 0x8003049, +0x42042, 0x10680021, 0x0, 0x8003049, 0x42042, 0x8ee20034, 0x24420001, 0xaee20034, -0x8ee20034, 0x800304d, 0x42042, 0x8ee201ec, -0x24420001, 0xaee201ec, 0x8ee201ec, 0x800304d, +0x8ee20034, 0x8003049, 0x42042, 0x8ee201ec, +0x24420001, 0xaee201ec, 0x8ee201ec, 0x8003049, 0x42042, 0x8ee201f0, 0x24420001, 0xaee201f0, -0x8ee201f0, 0x800304d, 0x42042, 0x8ee201f4, -0x24420001, 0xaee201f4, 0x8ee201f4, 0x800304d, +0x8ee201f0, 0x8003049, 0x42042, 0x8ee201f4, +0x24420001, 0xaee201f4, 0x8ee201f4, 0x8003049, 0x42042, 0x8ee20030, 0x24420001, 0xaee20030, -0x8ee20030, 0x800304d, 0x42042, 0x8ee201f8, +0x8ee20030, 0x8003049, 0x42042, 0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8, 0x42042, -0x1087047c, 0x0, 0x8003012, 0x0, +0x1087047c, 0x0, 0x800300e, 0x0, 0x3c020001, 0x571021, 0x904283b2, 0x14400084, 0x24020001, 0x3c030001, 0x771821, 0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000, 0x621024, @@ -2097,7 +2105,7 @@ 0x94437782, 0x96620004, 0x50620008, 0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff, -0x10400440, 0x0, 0x80030d9, 0x0, +0x10400440, 0x0, 0x80030d5, 0x0, 0x2402021, 0xc0022fe, 0x24050006, 0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, 0x30424000, 0x14400434, 0xb71021, 0x9443727e, 0x96620000, @@ -2106,14 +2114,14 @@ 0x94437282, 0x96620004, 0x10620035, 0x418c0, 0x2e31021, 0x9442727c, 0x30428000, 0x14400421, 0x2e31021, 0x944b727c, 0x96670000, 0xb28c0, -0xb71021, 0x9442737e, 0x80030bb, 0x3021, +0xb71021, 0x9442737e, 0x80030b7, 0x3021, 0x420c0, 0x2e41021, 0x9443737c, 0x2e41021, 0x944b737c, 0x30638000, 0x14600010, 0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5, 0x1602021, 0xb71021, 0x94437380, 0x96620002, 0x5462fff1, 0x420c0, 0xb71021, 0x94437382, 0x96620004, 0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff, -0x10400400, 0x0, 0x80030d9, 0x0, +0x10400400, 0x0, 0x80030d5, 0x0, 0x97430202, 0x96420000, 0x146203fa, 0x0, 0x97430204, 0x96420002, 0x146203f6, 0x0, 0x97430206, 0x96420004, 0x146203f2, 0x0, @@ -2130,7 +2138,7 @@ 0x971021, 0x94437782, 0x96620004, 0x50620008, 0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, -0x30e200ff, 0x14400044, 0x240f0003, 0x80034ca, +0x30e200ff, 0x14400044, 0x240f0003, 0x80034c6, 0x0, 0x2402021, 0xc0022fe, 0x24050006, 0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, 0x30424000, 0x144003af, 0xb71021, 0x9443727e, @@ -2139,14 +2147,14 @@ 0xb71021, 0x94437282, 0x96620004, 0x10620027, 0x418c0, 0x2e31021, 0x9442727c, 0x30428000, 0x1440039c, 0x2e31021, 0x944b727c, 0x96670000, -0xb28c0, 0xb71021, 0x9442737e, 0x8003140, +0xb28c0, 0xb71021, 0x9442737e, 0x800313c, 0x3021, 0x420c0, 0x2e41021, 0x9443737c, 0x2e41021, 0x944b737c, 0x30638000, 0x14600010, 0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5, 0x1602021, 0xb71021, 0x94437380, 0x96620002, 0x5462fff1, 0x420c0, 0xb71021, 0x94437382, 0x96620004, 0x5462ffec, 0x420c0, 0x24060001, -0x30c200ff, 0x1040037b, 0x0, 0x8003153, +0x30c200ff, 0x1040037b, 0x0, 0x800314f, 0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260, 0x54102b, 0x1040003a, 0x0, 0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, @@ -2157,12 +2165,12 @@ 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845058, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, -0xc002407, 0x34a5f003, 0x80034d0, 0x0, +0xc002403, 0x34a5f003, 0x80034cc, 0x0, 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, 0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, -0x3c050006, 0xc002407, 0x34a5f002, 0x8ee201c0, +0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0, -0x2403ffbf, 0x431024, 0x8003474, 0xaee20000, +0x2403ffbf, 0x431024, 0x8003470, 0xaee20000, 0x96e20468, 0x54102b, 0x10400003, 0x0, 0x240f0001, 0xa3af0027, 0x12800301, 0x24160007, 0x24150040, 0x241e0001, 0x240e0012, 0x8ee2724c, @@ -2170,7 +2178,7 @@ 0x0, 0x93a20027, 0x10400014, 0x0, 0x8ee35240, 0x8ee25244, 0x10620009, 0x26ed5244, 0x8ee65244, 0x8ee35244, 0x21140, 0x24425248, -0x2e28021, 0x24630001, 0x80031c3, 0x306b00ff, +0x2e28021, 0x24630001, 0x80031bf, 0x306b00ff, 0x92e27248, 0x1440ffca, 0x0, 0x8ee201e0, 0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffc2, 0x26ed0e18, 0x8ee60e18, @@ -2193,7 +2201,7 @@ 0x50400001, 0x27693000, 0x8f820128, 0x11220004, 0x0, 0x8f820124, 0x15220007, 0x1401821, 0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4, -0x8003250, 0x8ee201a4, 0x8e040000, 0x8e050004, +0x800324c, 0x8ee201a4, 0x8e040000, 0x8e050004, 0x1021, 0xad130008, 0xa507000e, 0xad160018, 0xad06001c, 0xa3302b, 0xa32823, 0x822023, 0x862023, 0xad040000, 0xad050004, 0x8ee204c0, @@ -2204,26 +2212,26 @@ 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10550007, 0x0, 0x8ee24e34, 0x24420001, 0x10620005, 0x0, -0x800323d, 0x0, 0x14600005, 0x0, +0x8003239, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, -0x8003250, 0x0, 0x8ee24e30, 0x24420001, +0x800324c, 0x0, 0x8ee24e30, 0x24420001, 0x50550003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 0xac9e0004, 0x16200018, 0x3c050006, 0x8e020018, 0x3c040001, 0x24845070, 0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, -0x2003021, 0xc002407, 0xafa30014, 0x93a20037, +0x2003021, 0xc002403, 0xafa30014, 0x93a20037, 0x10400216, 0x340f8100, 0x8e420004, 0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004, -0xae440008, 0x96020016, 0x8003474, 0xa642000e, +0xae440008, 0x96020016, 0x8003470, 0xa642000e, 0x14ec0168, 0x28a1823, 0x960c000a, 0x9603000e, 0x28a1023, 0xa602000a, 0x34620004, 0xa602000e, 0x8f880120, 0x27623800, 0x25090020, 0x122102b, 0x14400002, 0x306affff, 0x27693000, 0x8f820128, 0x11220004, 0x0, 0x8f820124, 0x15220007, 0x24040020, 0x8ee201a4, 0x8821, 0x24420001, -0xaee201a4, 0x80032ce, 0x8ee201a4, 0x8ee5724c, +0xaee201a4, 0x80032ca, 0x8ee201a4, 0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004, 0xad100008, 0xad040018, 0x52940, 0xa01821, 0x1021, 0xe33821, 0xe3202b, 0xc23021, @@ -2235,22 +2243,22 @@ 0x1062001b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10550007, 0x0, 0x8ee24e34, 0x24420001, -0x10620005, 0x0, 0x80032bb, 0x0, +0x10620005, 0x0, 0x80032b7, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400010, 0xac800000, 0x80032ce, 0x0, +0x50400010, 0xac800000, 0x80032ca, 0x0, 0x8ee24e30, 0x24420001, 0x50550003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 0xac9e0004, 0x1620000d, 0x0, 0xa60c000a, 0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104, 0x3c040001, 0x2484507c, 0x3c050006, 0xafa20014, -0x8ee6724c, 0x800343f, 0x34a5f00b, 0x3c010001, +0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001, 0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8, 0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8, 0x24630001, 0x306307ff, 0x26e25244, 0x15a20006, 0xaee3724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0, -0x80032f3, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, +0x80032ef, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, 0xaee201cc, 0x8ee201cc, 0x8f420240, 0x10400073, 0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b, 0x14400176, 0xa021, @@ -2258,7 +2266,7 @@ 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4, -0x8003353, 0x8ee201a4, 0x8ee2724c, 0xac62001c, +0x800334f, 0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, @@ -2268,23 +2276,23 @@ 0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10550007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x8003340, +0x24420001, 0x10620005, 0x0, 0x800333c, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400010, 0xac800000, 0x8003353, +0x2c420011, 0x50400010, 0xac800000, 0x800334f, 0x0, 0x8ee24e30, 0x24420001, 0x50550003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001, 0x8ee2724c, 0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, -0x34a5f008, 0xc002407, 0xafae0048, 0x8fae0048, +0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048, 0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001, -0xaee20188, 0x80033cc, 0x8ee20188, 0x8f830120, +0xaee20188, 0x80033c8, 0x8ee20188, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, -0x8821, 0x24420001, 0xaee201a4, 0x80033be, +0x8821, 0x24420001, 0xaee201a4, 0x80033ba, 0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, @@ -2295,24 +2303,24 @@ 0x1062001b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10550007, 0x0, 0x8ee24e34, 0x24420001, -0x10620005, 0x0, 0x80033ab, 0x0, +0x10620005, 0x0, 0x80033a7, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400010, 0xac800000, 0x80033be, 0x0, +0x50400010, 0xac800000, 0x80033ba, 0x0, 0x8ee24e30, 0x24420001, 0x50550003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac8e0000, 0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c, 0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008, -0xc002407, 0xafae0048, 0x8fae0048, 0x8ee20174, -0x24420001, 0xaee20174, 0x8ee20174, 0x8003472, +0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174, +0x24420001, 0xaee20174, 0x8ee20174, 0x800346e, 0xa021, 0x960c000a, 0x183102b, 0x54400001, 0x1801821, 0xa603000a, 0x8f880120, 0x27623800, 0x25090020, 0x122102b, 0x50400001, 0x27693000, 0x8f820128, 0x11220004, 0x0, 0x8f820124, 0x15220007, 0x24040020, 0x8ee201a4, 0x8821, -0x24420001, 0xaee201a4, 0x8003433, 0x8ee201a4, +0x24420001, 0xaee201a4, 0x800342f, 0x8ee201a4, 0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004, 0xad100008, 0xad040018, 0x52940, 0xa01821, 0x1021, 0xe33821, 0xe3202b, @@ -2324,21 +2332,21 @@ 0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10550007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x8003420, +0x24420001, 0x10620005, 0x0, 0x800341c, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400010, 0xac800000, 0x8003433, +0x2c420011, 0x50400010, 0xac800000, 0x800342f, 0x0, 0x8ee24e30, 0x24420001, 0x50550003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 0xac9e0004, 0x1620001d, 0x0, 0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104, 0x3c040001, 0x2484507c, 0x3c050006, 0xafa20014, -0x8ee6724c, 0x34a5f00d, 0xc002407, 0x2003821, +0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821, 0x93a20037, 0x10400031, 0x340f8100, 0x8e420004, 0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004, 0xae440008, 0x96020016, 0xa642000e, -0x9602000e, 0x3042fdff, 0x8003474, 0xa602000e, +0x9602000e, 0x3042fdff, 0x8003470, 0xa602000e, 0x8ee201d8, 0x2442ffff, 0xaee201d8, 0x8ee201d8, 0x8ee201cc, 0x3c04001f, 0x3c010001, 0x370821, 0xa03e83c0, 0x2442ffff, 0xaee201cc, 0x9603000a, @@ -2355,8 +2363,8 @@ 0x24420004, 0x3c010001, 0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff, 0x14620006, 0x0, 0x8ee201c4, 0x24420001, -0xaee201c4, 0x80034d0, 0x8ee201c4, 0x8ee201bc, -0x24420001, 0xaee201bc, 0x80034d0, 0x8ee201bc, +0xaee201c4, 0x80034cc, 0x8ee201c4, 0x8ee201bc, +0x24420001, 0xaee201bc, 0x80034cc, 0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaee400c0, 0xaee500c4, @@ -2364,9 +2372,9 @@ 0x14400017, 0x24020003, 0x15e20015, 0x0, 0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001, 0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0, -0x80034ca, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, +0x80034c6, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001, 0x2c640001, 0x441021, 0xaee200d8, -0xaee300dc, 0x8ee200d8, 0x80034ca, 0x8ee300dc, +0xaee300dc, 0x8ee200d8, 0x80034c6, 0x8ee300dc, 0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001, 0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, @@ -2387,40 +2395,40 @@ 0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8, -0xaf8700e4, 0x8003854, 0xaf8700e8, 0x3c020001, +0xaf8700e4, 0x8003850, 0xaf8700e8, 0x3c020001, 0x571021, 0x904283c0, 0x1040000b, 0x0, 0x3c130001, 0x2779821, 0x8e7383c4, 0x3c110001, 0x2378821, 0x8e3183c8, 0x3c120001, 0x2579021, -0x80036ec, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, +0x80036e8, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007, 0x4821, 0x8f8200e4, 0x24090001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, 0x3c040001, 0x24845050, 0xafa20014, -0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, -0x34a5f000, 0x8003854, 0x0, 0x8fa3001c, +0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403, +0x34a5f000, 0x8003850, 0x0, 0x8fa3001c, 0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, 0x10400058, 0x2408821, 0x3c020080, 0x621024, 0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001, -0xaee201fc, 0x800384e, 0x8ee201fc, 0x3c060004, +0xaee201fc, 0x800384a, 0x8ee201fc, 0x3c060004, 0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080, 0x3c080020, 0x34078000, 0x24420001, 0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021, 0xc3102b, 0x14400007, 0x0, 0x106b0011, 0x0, 0x106a0015, 0x0, -0x8003596, 0x42042, 0x10650023, 0xa3102b, +0x8003592, 0x42042, 0x10650023, 0xa3102b, 0x14400005, 0x0, 0x10690019, 0x0, -0x8003596, 0x42042, 0x10680021, 0x0, -0x8003596, 0x42042, 0x8ee20034, 0x24420001, -0xaee20034, 0x8ee20034, 0x8003596, 0x42042, +0x8003592, 0x42042, 0x10680021, 0x0, +0x8003592, 0x42042, 0x8ee20034, 0x24420001, +0xaee20034, 0x8ee20034, 0x8003592, 0x42042, 0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec, -0x8003596, 0x42042, 0x8ee201f0, 0x24420001, -0xaee201f0, 0x8ee201f0, 0x8003596, 0x42042, +0x8003592, 0x42042, 0x8ee201f0, 0x24420001, +0xaee201f0, 0x8ee201f0, 0x8003592, 0x42042, 0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4, -0x8003596, 0x42042, 0x8ee20030, 0x24420001, -0xaee20030, 0x8ee20030, 0x8003596, 0x42042, +0x8003592, 0x42042, 0x8ee20030, 0x24420001, +0xaee20030, 0x8ee20030, 0x8003592, 0x42042, 0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8, -0x42042, 0x108702b7, 0x0, 0x800355b, +0x42042, 0x108702b7, 0x0, 0x8003557, 0x0, 0x3c020001, 0x571021, 0x904283b2, 0x14400084, 0x24020001, 0x3c030001, 0x771821, 0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000, @@ -2435,7 +2443,7 @@ 0x971021, 0x94437782, 0x96220004, 0x50620008, 0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, -0x30e200ff, 0x1040027b, 0x0, 0x8003622, +0x30e200ff, 0x1040027b, 0x0, 0x800361e, 0x0, 0x2402021, 0xc0022fe, 0x24050006, 0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, 0x30424000, 0x1440026f, 0xb71021, 0x9443727e, @@ -2444,14 +2452,14 @@ 0xb71021, 0x94437282, 0x96220004, 0x10620035, 0x418c0, 0x2e31021, 0x9442727c, 0x30428000, 0x1440025c, 0x2e31021, 0x9448727c, 0x96270000, -0x828c0, 0xb71021, 0x9442737e, 0x8003604, +0x828c0, 0xb71021, 0x9442737e, 0x8003600, 0x3021, 0x420c0, 0x2e41021, 0x9443737c, 0x2e41021, 0x9448737c, 0x30638000, 0x14600010, 0x828c0, 0xb71021, 0x9442737e, 0x1447fff5, 0x1002021, 0xb71021, 0x94437380, 0x96220002, 0x5462fff1, 0x420c0, 0xb71021, 0x94437382, 0x96220004, 0x5462ffec, 0x420c0, 0x24060001, -0x30c200ff, 0x1040023b, 0x0, 0x8003622, +0x30c200ff, 0x1040023b, 0x0, 0x800361e, 0x0, 0x97430202, 0x96420000, 0x14620235, 0x0, 0x97430204, 0x96420002, 0x14620231, 0x0, 0x97430206, 0x96420004, 0x1462022d, @@ -2469,7 +2477,7 @@ 0x50620008, 0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff, 0x14400044, 0x24140003, -0x800384e, 0x0, 0x2402021, 0xc0022fe, +0x800384a, 0x0, 0x2402021, 0xc0022fe, 0x24050006, 0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, 0x30424000, 0x144001ea, 0xb71021, 0x9443727e, 0x96220000, 0x1462000b, 0x418c0, @@ -2478,14 +2486,14 @@ 0x10620027, 0x418c0, 0x2e31021, 0x9442727c, 0x30428000, 0x144001d7, 0x2e31021, 0x9448727c, 0x96270000, 0x828c0, 0xb71021, 0x9442737e, -0x8003689, 0x3021, 0x420c0, 0x2e41021, +0x8003685, 0x3021, 0x420c0, 0x2e41021, 0x9443737c, 0x2e41021, 0x9448737c, 0x30638000, 0x14600010, 0x828c0, 0xb71021, 0x9442737e, 0x1447fff5, 0x1002021, 0xb71021, 0x94437380, 0x96220002, 0x5462fff1, 0x420c0, 0xb71021, 0x94437382, 0x96220004, 0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff, 0x104001b6, 0x0, -0x800369c, 0x24140003, 0x24140001, 0x8f420260, +0x8003698, 0x24140003, 0x24140001, 0x8f420260, 0x53102b, 0x10400049, 0x0, 0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821, @@ -2495,23 +2503,23 @@ 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845058, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, -0xc002407, 0x34a5f003, 0x8003854, 0x0, +0xc002403, 0x34a5f003, 0x8003850, 0x0, 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, 0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, -0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, +0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf, -0x431024, 0x80037fc, 0xaee20000, 0x8ee25240, +0x431024, 0x80037f8, 0xaee20000, 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, 0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, -0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, -0xaee201c0, 0x80037fc, 0x8ee201c0, 0x96e20468, +0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001, +0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468, 0x53102b, 0x54400001, 0x3c158000, 0x12600131, 0x3c0c001f, 0x358cffff, 0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff, 0x10620108, 0x0, 0x12a00014, 0x0, 0x8ee35240, 0x8ee25244, 0x10620009, 0x26ee5244, 0x8eeb5244, 0x8ee35244, 0x21140, 0x24425248, 0x2e28021, 0x24630001, -0x8003716, 0x306800ff, 0x92e27248, 0x1440ffc0, +0x8003712, 0x306800ff, 0x92e27248, 0x1440ffc0, 0x3c050006, 0x8ee201e0, 0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffcb, 0x26ee0e18, 0x8eeb0e18, 0xa821, 0x8ee30e18, @@ -2532,7 +2540,7 @@ 0x38430006, 0x2c630001, 0x38420011, 0x2c420001, 0x621825, 0x10600013, 0x26220010, 0x182102b, 0x1040000e, 0x0, 0x3c07fff5, 0xf13821, -0x94e71010, 0x8003762, 0x24e7000e, 0x92220017, +0x94e71010, 0x800375e, 0x24e7000e, 0x92220017, 0x38430006, 0x2c630001, 0x38420011, 0x2c420001, 0x621825, 0x50600004, 0xae110018, 0x96270010, 0x24e7000e, 0xae110018, 0x3c020001, 0x571021, @@ -2541,7 +2549,7 @@ 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x2402000b, 0x8ee201a4, 0x4821, 0x24420001, -0xaee201a4, 0x80037c3, 0x8ee201a4, 0x8e040000, +0xaee201a4, 0x80037bf, 0x8ee201a4, 0x8e040000, 0x8e050004, 0xac620018, 0x1751025, 0x491025, 0xac710008, 0xa467000e, 0xac62001c, 0xac640000, 0xac650004, 0x8ee204c0, 0xac620010, 0xaf860120, @@ -2552,23 +2560,23 @@ 0x24420001, 0xac820004, 0x8ee34e34, 0x8ee54e30, 0x24020040, 0x24630001, 0x10620007, 0x0, 0x8ee24e34, 0x24420001, 0x10a20005, 0x0, -0x80037ad, 0x0, 0x14a00005, 0x0, +0x80037a9, 0x0, 0x14a00005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x80037c3, 0x0, 0x8ee24e30, 0x24030040, +0x80037bf, 0x0, 0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x15200018, 0x3c050006, 0x8e020018, 0x3c040001, 0x24845070, 0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021, -0xc002407, 0xafa30014, 0x32c200ff, 0x1040002b, +0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b, 0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c, 0xae430000, 0xae440004, 0xae450008, -0x96020016, 0x80037fc, 0xa642000e, 0x154d000a, +0x96020016, 0x80037f8, 0xa642000e, 0x154d000a, 0x0, 0x9602000e, 0xa613000a, 0x34420004, 0xa602000e, 0x3c010001, 0x370821, 0xa02083c0, -0x80037fa, 0x9821, 0x9604000a, 0x93102b, +0x80037f6, 0x9821, 0x9604000a, 0x93102b, 0x10400002, 0x2601821, 0x801821, 0x24020001, 0xa603000a, 0x3c010001, 0x370821, 0xa02283c0, 0x9604000a, 0x2248821, 0x191102b, 0x10400003, @@ -2580,8 +2588,8 @@ 0x571021, 0x8c4283cc, 0x24420004, 0x3c010001, 0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280, 0x24420001, 0x14620006, 0x0, 0x8ee201c4, -0x24420001, 0xaee201c4, 0x8003854, 0x8ee201c4, -0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003854, +0x24420001, 0xaee201c4, 0x8003850, 0x8ee201c4, +0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003850, 0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0x24020002, @@ -2589,9 +2597,9 @@ 0x14400017, 0x24020003, 0x16820015, 0x0, 0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001, 0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0, -0x800384e, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, +0x800384a, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001, 0x2c640001, 0x441021, 0xaee200d8, -0xaee300dc, 0x8ee200d8, 0x800384e, 0x8ee300dc, +0xaee300dc, 0x8ee200d8, 0x800384a, 0x8ee300dc, 0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001, 0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, @@ -2612,40 +2620,40 @@ 0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8, -0xaf8700e4, 0x8003c5f, 0xaf8700e8, 0x3c020001, +0xaf8700e4, 0x8003c5b, 0xaf8700e8, 0x3c020001, 0x571021, 0x904283c0, 0x1040000b, 0x0, 0x3c130001, 0x2779821, 0x8e7383c4, 0x3c100001, 0x2178021, 0x8e1083c8, 0x3c120001, 0x2579021, -0x8003a5d, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, +0x8003a59, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007, 0x3821, 0x8f8200e4, 0x24070001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, 0x3c040001, 0x24845094, 0xafa20014, -0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, -0x34a5f200, 0x8003c5f, 0x0, 0x8fa3001c, +0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403, +0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c, 0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, 0x10400058, 0x2408021, 0x3c020080, 0x621024, 0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001, -0xaee201fc, 0x8003c59, 0x8ee201fc, 0x3c060004, +0xaee201fc, 0x8003c55, 0x8ee201fc, 0x3c060004, 0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080, 0x3c080020, 0x34078000, 0x24420001, 0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021, 0xc3102b, 0x14400007, 0x0, 0x106b0011, 0x0, 0x106a0015, 0x0, -0x800391a, 0x42042, 0x10650023, 0xa3102b, +0x8003916, 0x42042, 0x10650023, 0xa3102b, 0x14400005, 0x0, 0x10690019, 0x0, -0x800391a, 0x42042, 0x10680021, 0x0, -0x800391a, 0x42042, 0x8ee20034, 0x24420001, -0xaee20034, 0x8ee20034, 0x800391a, 0x42042, +0x8003916, 0x42042, 0x10680021, 0x0, +0x8003916, 0x42042, 0x8ee20034, 0x24420001, +0xaee20034, 0x8ee20034, 0x8003916, 0x42042, 0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec, -0x800391a, 0x42042, 0x8ee201f0, 0x24420001, -0xaee201f0, 0x8ee201f0, 0x800391a, 0x42042, +0x8003916, 0x42042, 0x8ee201f0, 0x24420001, +0xaee201f0, 0x8ee201f0, 0x8003916, 0x42042, 0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4, -0x800391a, 0x42042, 0x8ee20030, 0x24420001, -0xaee20030, 0x8ee20030, 0x800391a, 0x42042, +0x8003916, 0x42042, 0x8ee20030, 0x24420001, +0xaee20030, 0x8ee20030, 0x8003916, 0x42042, 0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8, -0x42042, 0x1087033e, 0x0, 0x80038df, +0x42042, 0x1087033e, 0x0, 0x80038db, 0x0, 0x3c020001, 0x571021, 0x904283b2, 0x14400084, 0x24020001, 0x3c030001, 0x771821, 0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000, @@ -2660,7 +2668,7 @@ 0x971021, 0x94437782, 0x96020004, 0x50620008, 0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, -0x30e200ff, 0x10400302, 0x0, 0x80039a6, +0x30e200ff, 0x10400302, 0x0, 0x80039a2, 0x0, 0x2402021, 0xc0022fe, 0x24050006, 0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, 0x30424000, 0x144002f6, 0xb71021, 0x9443727e, @@ -2669,14 +2677,14 @@ 0xb71021, 0x94437282, 0x96020004, 0x10620035, 0x418c0, 0x2e31021, 0x9442727c, 0x30428000, 0x144002e3, 0x2e31021, 0x944d727c, 0x96070000, -0xd28c0, 0xb71021, 0x9442737e, 0x8003988, +0xd28c0, 0xb71021, 0x9442737e, 0x8003984, 0x3021, 0x420c0, 0x2e41021, 0x9443737c, 0x2e41021, 0x944d737c, 0x30638000, 0x14600010, 0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5, 0x1a02021, 0xb71021, 0x94437380, 0x96020002, 0x5462fff1, 0x420c0, 0xb71021, 0x94437382, 0x96020004, 0x5462ffec, 0x420c0, 0x24060001, -0x30c200ff, 0x104002c2, 0x0, 0x80039a6, +0x30c200ff, 0x104002c2, 0x0, 0x80039a2, 0x0, 0x97430202, 0x96420000, 0x146202bc, 0x0, 0x97430204, 0x96420002, 0x146202b8, 0x0, 0x97430206, 0x96420004, 0x146202b4, @@ -2694,7 +2702,7 @@ 0x50620008, 0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff, 0x14400044, 0x24150003, -0x8003c59, 0x0, 0x2402021, 0xc0022fe, +0x8003c55, 0x0, 0x2402021, 0xc0022fe, 0x24050006, 0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, 0x30424000, 0x14400271, 0xb71021, 0x9443727e, 0x96020000, 0x1462000b, 0x418c0, @@ -2703,14 +2711,14 @@ 0x10620027, 0x418c0, 0x2e31021, 0x9442727c, 0x30428000, 0x1440025e, 0x2e31021, 0x944d727c, 0x96070000, 0xd28c0, 0xb71021, 0x9442737e, -0x8003a0d, 0x3021, 0x420c0, 0x2e41021, +0x8003a09, 0x3021, 0x420c0, 0x2e41021, 0x9443737c, 0x2e41021, 0x944d737c, 0x30638000, 0x14600010, 0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5, 0x1a02021, 0xb71021, 0x94437380, 0x96020002, 0x5462fff1, 0x420c0, 0xb71021, 0x94437382, 0x96020004, 0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff, 0x1040023d, 0x0, -0x8003a20, 0x24150003, 0x24150001, 0x8f420260, +0x8003a1c, 0x24150003, 0x24150001, 0x8f420260, 0x53102b, 0x10400036, 0x0, 0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821, @@ -2720,11 +2728,11 @@ 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 0xafa20010, 0x8f8200e4, 0x3c040001, 0x248450a0, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, -0xc002407, 0x34a5f203, 0x8003c5f, 0x0, +0xc002403, 0x34a5f203, 0x8003c5b, 0x0, 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, 0x248450ac, 0xafa20014, 0x8ee60e10, 0x8ee70e18, -0x3c050006, 0xc002407, 0x34a5f202, 0x8ee201c0, -0x24420001, 0xaee201c0, 0x8003c06, 0x8ee201c0, +0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0, +0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0, 0x96e20468, 0x53102b, 0x54400001, 0x3c168000, 0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5, 0x35ef1000, 0x241e0040, 0x8ee2724c, 0x8f430280, @@ -2732,7 +2740,7 @@ 0x12c00012, 0x0, 0x8ee35240, 0x8ee25244, 0x1062000a, 0x26f85244, 0x8ef45244, 0xafb80024, 0x8ee35244, 0x21140, 0x24425248, 0x2e28821, -0x24630001, 0x8003a89, 0x306d00ff, 0x8ee201e0, +0x24630001, 0x8003a85, 0x306d00ff, 0x8ee201e0, 0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffca, 0x26f80e18, 0x8ef40e18, 0xb021, 0xafb80024, 0x8ee30e18, 0x21140, @@ -2751,7 +2759,7 @@ 0x2418fff8, 0x58c824, 0x6a1821, 0x79102b, 0x10400002, 0x3206021, 0x606021, 0x1801821, 0x24620007, 0x2418fff8, 0x586024, 0x26c102b, -0x14400004, 0x1932823, 0x1832823, 0x8003ac7, +0x14400004, 0x1932823, 0x1832823, 0x8003ac3, 0xc31021, 0xd31021, 0x4a2023, 0x1c4102b, 0x54400001, 0x8f2021, 0x25420040, 0x4c102b, 0x14400035, 0x5821, 0x94c3000c, 0x24020800, @@ -2761,7 +2769,7 @@ 0x461021, 0x90421017, 0x38430006, 0x2c630001, 0x38420011, 0x2c420001, 0x621825, 0x10600014, 0x24c20010, 0x1c2102b, 0x1040000e, 0x0, -0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af8, +0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af4, 0x2562000e, 0x90c20017, 0x38430006, 0x2c630001, 0x38420011, 0x2c420001, 0x621825, 0x10600005, 0x1601821, 0x94cb0010, 0x2562000e, 0x4a5821, @@ -2774,13 +2782,13 @@ 0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021, 0x50a00012, 0x81c02, 0x2ca20002, 0x54400009, 0x24a5ffff, 0x94820000, 0x24840002, 0x1024021, -0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b25, +0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b21, 0x8f2021, 0x90820000, 0x21200, 0x1024021, 0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff, 0x624021, 0x3108ffff, 0x1402821, 0x11400011, 0x2002021, 0x2ca20002, 0x54400009, 0x24a5ffff, 0x94820000, 0x24840002, 0x1024021, 0x1c4102b, -0x10400006, 0x24a5fffe, 0x8003b3c, 0x8f2021, +0x10400006, 0x24a5fffe, 0x8003b38, 0x8f2021, 0x90820000, 0x21200, 0x1024021, 0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff, 0x624021, 0x81c02, 0x3102ffff, 0x8f890120, 0x624021, @@ -2788,7 +2796,7 @@ 0x3108ffff, 0x27633000, 0x8f820128, 0x10620004, 0x0, 0x8f820124, 0x14620007, 0x1402821, 0x8ee201a4, 0x3821, 0x24420001, 0xaee201a4, -0x8003bcd, 0x8ee201a4, 0x8e260000, 0x8e270004, +0x8003bc9, 0x8ee201a4, 0x8e260000, 0x8e270004, 0x81400, 0x3448000b, 0xad300008, 0xa52b000e, 0xad280018, 0x8fb80044, 0x2021, 0x2961025, 0x581025, 0xad22001c, 0xe5102b, 0xe53823, @@ -2801,32 +2809,32 @@ 0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x105e002a, 0x0, -0x8003bac, 0x0, 0x8ee24e30, 0x24420001, +0x8003ba8, 0x0, 0x8ee24e30, 0x24420001, 0x505e0003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8003bca, 0x24020012, 0x8ee24e30, +0x2e22021, 0x8003bc6, 0x24020012, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x105e0007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x8003bb8, +0x24420001, 0x10620005, 0x0, 0x8003bb4, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400012, 0xac800000, 0x8003bcd, +0x2c420011, 0x50400012, 0xac800000, 0x8003bc9, 0x0, 0x8ee24e30, 0x24420001, 0x505e0003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x14e00019, 0x3c050006, 0x3c040001, 0x24845070, 0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000, -0x8e230004, 0x2203021, 0x1603821, 0xc002407, +0x8e230004, 0x2203021, 0x1603821, 0xc002403, 0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c, 0xae430000, 0xae440004, 0xae450008, 0x96220016, -0x8003c06, 0xa642000e, 0x1599000a, 0x26a1823, +0x8003c02, 0xa642000e, 0x1599000a, 0x26a1823, 0x9622000e, 0xa623000a, 0x34420004, 0xa622000e, -0x3c010001, 0x370821, 0xa02083c0, 0x8003c03, +0x3c010001, 0x370821, 0xa02083c0, 0x8003bff, 0x9821, 0x9624000a, 0x83102b, 0x54400001, 0x801821, 0x24020001, 0xa623000a, 0x3c010001, 0x370821, 0xa02283c0, 0x9622000a, 0x4a1821, @@ -2839,18 +2847,18 @@ 0x571021, 0x8c4283cc, 0x24420004, 0x3c010001, 0x370821, 0xac2283cc, 0x8f430280, 0x8ee2724c, 0x14620006, 0x0, 0x8ee201c4, 0x24420001, -0xaee201c4, 0x8003c5f, 0x8ee201c4, 0x8ee201bc, -0x24420001, 0xaee201bc, 0x8003c5f, 0x8ee201bc, +0xaee201c4, 0x8003c5b, 0x8ee201c4, 0x8ee201bc, +0x24420001, 0xaee201bc, 0x8003c5b, 0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0x24020002, 0xaee400c0, 0xaee500c4, 0x12a2000f, 0x2aa20003, 0x14400017, 0x24020003, 0x16a20015, 0x0, 0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001, 0x441021, -0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c59, +0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c55, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001, 0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc, -0x8ee200d8, 0x8003c59, 0x8ee300dc, 0x8ee200c8, +0x8ee200d8, 0x8003c55, 0x8ee300dc, 0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001, 0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008, @@ -2861,14 +2869,14 @@ 0x8ee20e0c, 0x10620074, 0x0, 0x8ee30e0c, 0x8ee20e14, 0x622023, 0x4820001, 0x24840200, 0x8ee30e18, 0x8ee20e14, 0x43102b, 0x14400004, -0x24020200, 0x8ee30e14, 0x8003c81, 0x431823, +0x24020200, 0x8ee30e14, 0x8003c7d, 0x431823, 0x8ee20e18, 0x8ee30e14, 0x431023, 0x2443ffff, 0x804821, 0x69102a, 0x54400001, 0x604821, 0x8f870100, 0x27623000, 0x24e80020, 0x102102b, 0x50400001, 0x27682800, 0x8f820108, 0x11020004, 0x0, 0x8f820104, 0x15020007, 0x1021, 0x8ee201a8, 0x2021, 0x24420001, 0xaee201a8, -0x8003cc3, 0x8ee201a8, 0x8ee40e14, 0x42140, +0x8003cbf, 0x8ee201a8, 0x8ee40e14, 0x42140, 0x801821, 0x8ee40460, 0x8ee50464, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee30e14, 0x91140, 0xa4e2000e, @@ -2882,7 +2890,7 @@ 0x24020001, 0xac620004, 0x1480000e, 0x24030040, 0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007, 0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001, -0x248450b4, 0xc002407, 0x34a5f001, 0x8003ce1, +0x248450b4, 0xc002403, 0x34a5f001, 0x8003cdd, 0x0, 0x8ee20500, 0x24420001, 0x50430003, 0x1021, 0x8ee20500, 0x24420001, 0xaee20500, 0x8ee20500, 0x21080, 0x571021, 0xac490508, @@ -2894,13 +2902,13 @@ 0x0, 0x8ee35238, 0x8ee2523c, 0x622023, 0x4820001, 0x24840100, 0x8ee35244, 0x8ee2523c, 0x43102b, 0x14400004, 0x24020100, 0x8ee3523c, -0x8003d03, 0x431823, 0x8ee25244, 0x8ee3523c, +0x8003cff, 0x431823, 0x8ee25244, 0x8ee3523c, 0x431023, 0x2443ffff, 0x804821, 0x69102a, 0x54400001, 0x604821, 0x8f870100, 0x27623000, 0x24e80020, 0x102102b, 0x50400001, 0x27682800, 0x8f820108, 0x11020004, 0x0, 0x8f820104, 0x15020007, 0x1021, 0x8ee201a8, 0x2021, -0x24420001, 0xaee201a8, 0x8003d45, 0x8ee201a8, +0x24420001, 0xaee201a8, 0x8003d41, 0x8ee201a8, 0x8ee4523c, 0x42140, 0x801821, 0x8ee40470, 0x8ee50474, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee3523c, @@ -2914,8 +2922,8 @@ 0x24020003, 0xac620000, 0x24020001, 0xac620004, 0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010, 0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238, -0x8ee75240, 0x3c040001, 0x248450c0, 0xc002407, -0x34a5f010, 0x8003d63, 0x0, 0x8ee20500, +0x8ee75240, 0x3c040001, 0x248450c0, 0xc002403, +0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500, 0x24420001, 0x50430003, 0x1021, 0x8ee20500, 0x24420001, 0xaee20500, 0x8ee20500, 0x21080, 0x571021, 0xac490508, 0x8ee2523c, 0x491021, @@ -2927,7 +2935,7 @@ 0x1021, 0x8ee24e34, 0x24420001, 0xaee24e34, 0x8ee24e34, 0x8ee44e34, 0x8ee34e30, 0x210c0, 0x24425038, 0x14830007, 0x2e22821, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8003d96, +0x24420020, 0xaf820128, 0x8f820128, 0x8003d92, 0xaca00000, 0x8ee24e34, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e34, 0x24420001, 0x210c0, 0x24425038, 0x2e22821, 0x8ca20004, @@ -2948,10 +2956,10 @@ 0x95830016, 0x95820018, 0x621823, 0x31402, 0x431021, 0xa5820016, 0x8d82001c, 0x3c038000, 0x3044ffff, 0x436824, 0x3c030800, 0x431824, -0x11a00004, 0xad84001c, 0x41140, 0x8003ddc, +0x11a00004, 0xad84001c, 0x41140, 0x8003dd8, 0x24425248, 0x41140, 0x24420e20, 0x2e25821, 0x9562000e, 0x3042fffc, 0x10600004, 0xa562000e, -0x95840016, 0x8003ec4, 0x0, 0x8d690018, +0x95840016, 0x8003ec0, 0x0, 0x8d690018, 0x4021, 0x952a0000, 0x25290002, 0x95270000, 0x25290002, 0x95260000, 0x25290002, 0x95250000, 0x25290002, 0x95240000, 0x25290002, 0x95230000, @@ -2965,7 +2973,7 @@ 0x721821, 0x94620000, 0x24630002, 0x24a5ffff, 0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff, 0x622021, 0x41402, 0x3083ffff, 0x431021, -0x3042ffff, 0x8003e37, 0x1425021, 0x952a0000, +0x3042ffff, 0x8003e33, 0x1425021, 0x952a0000, 0x25290002, 0x95280000, 0x25290002, 0x95270000, 0x25290002, 0x95260000, 0x25290002, 0x95250000, 0x25290002, 0x95230000, 0x25290002, 0x95220000, @@ -2982,7 +2990,7 @@ 0x10400034, 0x24690010, 0x229102b, 0x54400001, 0x1324821, 0x95250000, 0x24690014, 0x229102b, 0x10400002, 0x24a5ffec, 0x1324821, 0x95220000, -0x30420fff, 0x14400003, 0x25290002, 0x8003e64, +0x30420fff, 0x14400003, 0x25290002, 0x8003e60, 0x24130001, 0x9821, 0xa03021, 0x229102b, 0x54400001, 0x1324821, 0x91220001, 0x25290002, 0xa22821, 0x229102b, 0x54400001, 0x1324821, @@ -2991,9 +2999,9 @@ 0x54400001, 0x1324821, 0x95220000, 0x25290002, 0xa22821, 0x229102b, 0x54400001, 0x1324821, 0x95220000, 0x25290002, 0xa22821, 0x229102b, -0x54400001, 0x1324821, 0x95220000, 0x8003e9d, +0x54400001, 0x1324821, 0x95220000, 0x8003e99, 0xa22821, 0x94650010, 0x94620014, 0x24690016, -0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e90, +0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e8c, 0x24130001, 0x9821, 0xa03021, 0x91230001, 0x25290004, 0x95220000, 0x25290002, 0x95240000, 0x25290002, 0xa32821, 0xa22821, 0x95220000, @@ -3013,7 +3021,7 @@ 0x122102b, 0x50400001, 0x27693000, 0x8f820128, 0x11220004, 0x0, 0x8f820124, 0x15220007, 0x24040020, 0x8ee201a4, 0x8021, 0x24420001, -0xaee201a4, 0x8003f53, 0x8ee201a4, 0x8ee5724c, +0xaee201a4, 0x8003f4f, 0x8ee201a4, 0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xad0b0008, 0xa504000e, 0xad0a0018, 0x52940, 0xa01821, 0x1021, 0xe33821, 0xe3202b, 0xc23021, 0xc43021, @@ -3026,41 +3034,41 @@ 0x0, 0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x1054002b, -0x0, 0x8003f32, 0x0, 0x8ee24e30, +0x0, 0x8003f2e, 0x0, 0x8ee24e30, 0x24420001, 0x50540003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x24020001, 0x8003f52, +0x24425038, 0x2e22021, 0x24020001, 0x8003f4e, 0xac950000, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007, 0x0, 0x8ee24e34, 0x24420001, 0x10620005, -0x0, 0x8003f3e, 0x0, 0x14600005, +0x0, 0x8003f3a, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400012, -0xac800000, 0x8003f53, 0x0, 0x8ee24e30, +0xac800000, 0x8003f4f, 0x0, 0x8ee24e30, 0x24420001, 0x50540003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x1600000d, 0x0, 0x8f820120, 0x3c040001, 0x24845118, 0xafa00014, 0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008, -0xc002407, 0x34a50001, 0x800405b, 0x0, +0xc002403, 0x34a50001, 0x8004057, 0x0, 0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006, 0xaee2724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0, -0x8003f6f, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, +0x8003f6b, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, 0xaee201cc, 0x8ee201cc, 0x8ee201d8, 0x2442ffff, -0xaee201d8, 0x800405b, 0x8ee201d8, 0x8f420240, +0xaee201d8, 0x8004057, 0x8ee201d8, 0x8f420240, 0x104000e5, 0x0, 0x8ee20e1c, 0x24420001, -0x800405b, 0xaee20e1c, 0x9582001e, 0xad82001c, +0x8004057, 0xaee20e1c, 0x9582001e, 0xad82001c, 0x8f420240, 0x10400072, 0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b, 0x144000d5, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, 0x8021, -0x24420001, 0xaee201a4, 0x8003fde, 0x8ee201a4, +0x24420001, 0xaee201a4, 0x8003fda, 0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, 0xac650004, @@ -3071,23 +3079,23 @@ 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007, 0x0, 0x8ee24e34, 0x24420001, 0x10620005, -0x0, 0x8003fca, 0x0, 0x14600005, +0x0, 0x8003fc6, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400011, -0xac800000, 0x8003fde, 0x0, 0x8ee24e30, +0xac800000, 0x8003fda, 0x0, 0x8ee24e30, 0x24420001, 0x50540003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020001, 0xac950000, 0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, -0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002407, +0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188, -0x24420001, 0xaee20188, 0x8004054, 0x8ee20188, +0x24420001, 0xaee20188, 0x8004050, 0x8ee20188, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, -0x8004048, 0x8ee201a4, 0x8ee2724c, 0xac62001c, +0x8004044, 0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, @@ -3097,64 +3105,64 @@ 0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x8004034, +0x24420001, 0x10620005, 0x0, 0x8004030, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400011, 0xac800000, 0x8004048, +0x2c420011, 0x50400011, 0xac800000, 0x8004044, 0x0, 0x8ee24e30, 0x24420001, 0x50540003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020001, 0xac950000, 0xac820004, 0x1600000b, 0x0, 0x8ee2724c, 0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, -0x3c050009, 0xc002407, 0x34a5f008, 0x8ee20174, -0x24420001, 0xaee20174, 0x800405b, 0x8ee20174, +0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174, +0x24420001, 0xaee20174, 0x8004057, 0x8ee20174, 0x24020001, 0xaee24e24, 0x8f830128, 0x8f820124, 0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c, 0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8, 0x27840208, 0x27450200, 0x24060008, 0xafbf0014, -0xc00249e, 0xafb00010, 0x2021, 0x24100001, +0xc00249a, 0xafb00010, 0x2021, 0x24100001, 0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204, 0xaf820214, 0x8f460248, 0x24030004, 0x3c020040, 0x3c010001, 0xac235484, 0x3c010001, 0xac235488, 0x3c010001, 0xac20553c, 0x3c010001, 0xac225480, 0x3c010001, 0xac235488, 0xc004fa8, 0x24050004, -0xc004784, 0x0, 0x8ee20000, 0x3c03feff, +0xc004785, 0x0, 0x8ee20000, 0x3c03feff, 0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00, 0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac, 0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001, -0x248451d0, 0xc002407, 0x3821, 0x8ee20280, +0x248451d0, 0xc002403, 0x3821, 0x8ee20280, 0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200, 0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400, 0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0xafb00018, 0x8f900220, 0x8ee20214, 0x3821, 0x24420001, 0xaee20214, 0x8ee20214, 0x3c020300, 0x2021024, 0x10400027, 0x3c110400, -0xc00429f, 0x0, 0x3c020100, 0x2021024, +0xc00429b, 0x0, 0x3c020100, 0x2021024, 0x10400007, 0x0, 0x8ee20218, 0x24420001, -0xaee20218, 0x8ee20218, 0x80040ca, 0x3c03fdff, +0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff, 0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c, 0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff, 0x8ee20000, 0x3c040001, 0x248451dc, 0x3c050008, 0x2003021, 0x431024, 0xaee20000, 0x8f820220, 0x3821, 0x3c030300, 0x481024, 0x431025, -0xaf820220, 0xafa00010, 0xc002407, 0xafa00014, -0x800429a, 0x0, 0x2111024, 0x1040001f, +0xaf820220, 0xafa00010, 0xc002403, 0xafa00014, +0x8004296, 0x0, 0x2111024, 0x1040001f, 0x3c024000, 0x8f830224, 0x24021402, 0x1462000b, 0x3c03fdff, 0x3c040001, 0x248451e8, 0x3c050008, 0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff, -0xc002407, 0x3821, 0x3c03fdff, 0x8ee20000, +0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x2002021, 0x431024, 0xc004cf4, 0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220, 0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff, -0x431024, 0x8004299, 0x511025, 0x2021024, +0x431024, 0x8004295, 0x511025, 0x2021024, 0x10400142, 0x0, 0x8ee2022c, 0x24420001, 0xaee2022c, 0x8ee2022c, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x34420004, 0xaf820220, -0x8f830054, 0x8f820054, 0x8004112, 0x24630002, +0x8f830054, 0x8f820054, 0x800410e, 0x24630002, 0x8f820054, 0x621023, 0x2c420003, 0x1440fffc, 0x0, 0x8f8600e0, 0x8f8400e4, 0x30c20007, 0x10400012, 0x0, 0x8f8300e4, 0x2402fff8, @@ -3167,7 +3175,7 @@ 0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f, 0x3442ffff, 0x24680008, 0x48102b, 0x10400003, 0x3c02fff5, 0x34421000, 0x1024021, 0x8f8b00c8, -0x8f850120, 0x8f840124, 0x8004149, 0x6021, +0x8f850120, 0x8f840124, 0x8004145, 0x6021, 0x27623800, 0x82102b, 0x50400001, 0x27643000, 0x10a40010, 0x318200ff, 0x8c820018, 0x38430007, 0x2c630001, 0x3842000b, 0x2c420001, 0x621825, @@ -3177,19 +3185,19 @@ 0x571021, 0x904283c0, 0x14400060, 0x0, 0x8f8400e4, 0xc41023, 0x218c3, 0x4620001, 0x24630200, 0x8f8900c4, 0x10600005, 0x24020001, -0x10620009, 0x0, 0x800418b, 0x0, +0x10620009, 0x0, 0x8004187, 0x0, 0x8ee20230, 0x1205821, 0x24420001, 0xaee20230, -0x80041c0, 0x8ee20230, 0x8ee20234, 0x3c05000a, +0x80041bc, 0x8ee20230, 0x8ee20234, 0x3c05000a, 0x24420001, 0xaee20234, 0x8c8b0000, 0x34a5f000, 0x8ee20234, 0x12b1823, 0xa3102b, 0x54400001, 0x651821, 0x2c62233f, 0x14400040, 0x0, 0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8, 0x8f8200e4, 0x1205821, 0x24420008, 0xaf8200e4, -0x80041c0, 0x8f8200e4, 0x8ee20238, 0x3c03000a, +0x80041bc, 0x8f8200e4, 0x8ee20238, 0x3c03000a, 0x24420001, 0xaee20238, 0x8c840000, 0x3463f000, 0x8ee20238, 0x883823, 0x67102b, 0x54400001, 0xe33821, 0x3c020003, 0x34420d40, 0x47102b, -0x10400003, 0x0, 0x80041c0, 0x805821, +0x10400003, 0x0, 0x80041bc, 0x805821, 0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4, 0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003, 0x354a0d40, 0x8ee2007c, 0x24420001, 0xaee2007c, @@ -3197,19 +3205,19 @@ 0x54400001, 0xe53821, 0x147102b, 0x54400007, 0x605821, 0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4, 0x1486ffef, 0x0, 0x14860005, -0x0, 0x1205821, 0xaf8600e4, 0x80041c0, +0x0, 0x1205821, 0xaf8600e4, 0x80041bc, 0xaf8600e8, 0xaf8400e4, 0xaf8400e8, 0x8f8200c8, 0x3c03000a, 0x3463f000, 0x483823, 0x67102b, 0x54400001, 0xe33821, 0x3c020003, 0x34420d3f, 0x47102b, 0x54400007, 0x6021, 0x1683823, -0x67102b, 0x54400003, 0xe33821, 0x80041d3, +0x67102b, 0x54400003, 0xe33821, 0x80041cf, 0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b, 0x14400016, 0x318200ff, 0x14400006, 0x0, 0x3c020001, 0x571021, 0x904283c0, 0x1040000f, 0x0, 0x8ee2023c, 0x3c04fdff, 0x8ee30000, 0x3484ffff, 0x24420001, 0xaee2023c, 0x8ee2023c, 0x24020001, 0x641824, 0x3c010001, 0x370821, -0xa02283b8, 0x8004230, 0xaee30000, 0xaf8b00c8, +0xa02283b8, 0x800422c, 0xaee30000, 0xaf8b00c8, 0x8f8300c8, 0x8f8200c4, 0x3c04000a, 0x3484f000, 0x623823, 0x87102b, 0x54400001, 0xe43821, 0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001, @@ -3228,14 +3236,14 @@ 0x12a4821, 0x10690002, 0x10c1025, 0xac820004, 0xa02021, 0x14c4ffeb, 0x24850008, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002, -0xaf820220, 0x8f830054, 0x8f820054, 0x800423b, +0xaf820220, 0x8f830054, 0x8f820054, 0x8004237, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220, 0x6010055, 0x0, 0x8ee20228, 0x24420001, 0xaee20228, 0x8ee20228, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x34420004, 0xaf820220, 0x8f830054, -0x8f820054, 0x8004255, 0x24630002, 0x8f820054, +0x8f820054, 0x8004251, 0x24630002, 0x8f820054, 0x621023, 0x2c420003, 0x1440fffc, 0x0, 0x8f8600e0, 0x30c20007, 0x10400012, 0x0, 0x8f8300e4, 0x2402fff8, 0xc21024, 0x1043000d, @@ -3250,7 +3258,7 @@ 0x8ee2007c, 0x3c0408ff, 0x3484ffff, 0x471021, 0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002, 0x441024, 0x431025, 0xaf820220, 0x8f830054, -0x8f820054, 0x8004291, 0x24630001, 0x8f820054, +0x8f820054, 0x800428d, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, @@ -3259,7 +3267,7 @@ 0x248451f4, 0x3c050008, 0x24020001, 0x3c010001, 0x370821, 0xac2283ac, 0xafa00010, 0xafa00014, 0x8f860220, 0x34a50498, 0x3c010001, 0xac205498, -0x3c010001, 0xac22548c, 0xc002407, 0x3821, +0x3c010001, 0xac22548c, 0xc002403, 0x3821, 0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024, 0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe, 0x431024, 0x30840002, 0x1080011e, 0xaee204d0, @@ -3275,7 +3283,7 @@ 0x27623800, 0x24e80020, 0x102102b, 0x50400001, 0x27683000, 0x8f820128, 0x11020004, 0x0, 0x8f820124, 0x15020007, 0x1021, 0x8ee201a4, -0x2821, 0x24420001, 0xaee201a4, 0x8004341, +0x2821, 0x24420001, 0xaee201a4, 0x800433d, 0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0xace40000, 0xace50004, @@ -3288,10 +3296,10 @@ 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007, 0x0, 0x8ee24e34, 0x24420001, 0x10620005, -0x0, 0x800432e, 0x0, 0x14600005, +0x0, 0x800432a, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x8004341, 0x0, 0x8ee24e30, +0xac800000, 0x800433d, 0x0, 0x8ee24e30, 0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004, @@ -3305,7 +3313,7 @@ 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, 0x2821, 0x24420001, 0xaee201a4, -0x80043ad, 0x8ee201a4, 0x8ee20608, 0xac62001c, +0x80043a9, 0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, @@ -3315,30 +3323,30 @@ 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007, 0x0, 0x8ee24e34, 0x24420001, 0x10620005, -0x0, 0x800439a, 0x0, 0x14600005, +0x0, 0x8004396, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x80043ad, 0x0, 0x8ee24e30, +0xac800000, 0x80043a9, 0x0, 0x8ee24e30, 0x24420001, 0x50470003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac880000, 0xac8a0004, 0x54a00006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, -0x24020001, 0x54620003, 0xafa00010, 0x80043da, +0x24020001, 0x54620003, 0xafa00010, 0x80043d6, 0x0, 0x3c040001, 0x24845200, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, -0x34a5f011, 0x80043da, 0x0, 0x3c040001, +0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, +0x34a5f011, 0x80043d6, 0x0, 0x3c040001, 0x2484520c, 0xafa00014, 0x8f860120, 0x8f870124, -0x3c050009, 0xc002407, 0x34a5f010, 0x80043da, +0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6, 0x0, 0x3c040001, 0x24845218, 0xafa00014, -0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, +0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425498, 0x27bdffe0, 0x1440000d, 0xafbf0018, 0x3c040001, 0x24845224, 0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499, -0x24020001, 0x3c010001, 0xac225498, 0xc002407, +0x24020001, 0x3c010001, 0xac225498, 0xc002403, 0x3821, 0x8ee204d0, 0x3c030001, 0x771821, 0x946383b2, 0x34420001, 0x10600007, 0xaee204d0, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, @@ -3358,6 +3366,7 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c120001, 0x26521200, 0x3c140001, 0x8e945410, 0x3c100001, 0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000, @@ -3376,19 +3385,19 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80014d6, 0x0, 0x80014d8, 0x3c0a0001, 0x80014d8, -0x3c0a0002, 0x80014d8, 0x0, 0x80024aa, +0x3c0a0002, 0x80014d8, 0x0, 0x80024a6, 0x0, 0x80014d8, 0x3c0a0003, 0x80014d8, -0x3c0a0004, 0x8002f90, 0x0, 0x80014d8, -0x3c0a0005, 0x8003cec, 0x0, 0x8003c6a, +0x3c0a0004, 0x8002f8c, 0x0, 0x80014d8, +0x3c0a0005, 0x8003ce8, 0x0, 0x8003c66, 0x0, 0x80014d8, 0x3c0a0006, 0x80014d8, 0x3c0a0007, 0x80014d8, 0x0, 0x80014d8, -0x0, 0x80014d8, 0x0, 0x8002a79, +0x0, 0x80014d8, 0x0, 0x8002a75, 0x0, 0x80014d8, 0x3c0a000b, 0x80014d8, -0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237c, +0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237a, 0x0, 0x8002339, 0x0, 0x80014d8, -0x3c0a000e, 0x8001b3c, 0x0, 0x80024a8, -0x0, 0x80014d8, 0x3c0a000f, 0x80040ab, -0x0, 0x8004095, 0x0, 0x80014d8, +0x3c0a000e, 0x8001b3c, 0x0, 0x80024a4, +0x0, 0x80014d8, 0x3c0a000f, 0x80040a7, +0x0, 0x8004091, 0x0, 0x80014d8, 0x3c0a0010, 0x80014ee, 0x0, 0x80014d8, 0x3c0a0011, 0x80014d8, 0x3c0a0012, 0x80014d8, 0x3c0a0013, 0x0, 0x0, 0x0, @@ -3436,212 +3445,212 @@ 0x27a60018, 0x8f830054, 0x8f820054, 0x800456f, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 0x24050003, 0xc0048ac, -0x27a6001a, 0x97a20020, 0x10400027, 0x24030001, +0x27a6001a, 0x97a20020, 0x10400028, 0x24030001, 0x3c020001, 0x8c425484, 0x97a30018, 0x34420001, -0x3c010001, 0xac225484, 0x24020015, 0x1462000d, -0x0, 0x97a2001a, 0x3843f423, 0x2c630001, -0x3842f430, 0x2c420001, 0x621825, 0x10600005, -0x24020003, 0x3c010001, 0xac225550, 0x80045a7, -0x3c08fff0, 0x97a30018, 0x24027810, 0x1462000a, -0x24020002, 0x97a3001a, 0x24020001, 0x14620006, -0x24020002, 0x24020004, 0x3c010001, 0xac225550, -0x80045a7, 0x3c08fff0, 0x3c010001, 0xac225550, -0x80045a7, 0x3c08fff0, 0x3c020001, 0x8c425484, -0x3c010001, 0xac235550, 0x34420004, 0x3c010001, -0xac225484, 0x3c08fff0, 0x3508bdc0, 0x8f830054, -0x97a60018, 0x3c070001, 0x8ce75550, 0x3c040001, -0x24845290, 0x24020001, 0x3c010001, 0xac22548c, -0xafa60010, 0x3c060001, 0x8cc65484, 0x97a2001a, -0x3c05000d, 0x34a50100, 0x3c010001, 0xac205488, -0x681821, 0x3c010001, 0xac235548, 0xc002407, -0xafa20014, 0x8fbf0028, 0x3e00008, 0x27bd0030, -0x27bdffe8, 0x24070004, 0x3c040001, 0x8c845488, -0x3021, 0x24020001, 0x1482000a, 0xafbf0010, -0x3c020001, 0x8c4275cc, 0x3c050004, 0x30428000, -0x1040000c, 0x34a593e0, 0x3c05000f, 0x80045da, -0x34a54240, 0x3c020001, 0x8c4275cc, 0x3c05000f, -0x30428000, 0x10400003, 0x34a54240, 0x3c05001e, -0x34a58480, 0x3c020001, 0x8c425548, 0x8f830054, -0x451021, 0x431023, 0x45102b, 0x1440002e, -0x0, 0x3c020001, 0x8c425490, 0x1440002a, -0x2cc20001, 0x7182b, 0x431024, 0x1040001d, -0x0, 0x3c090001, 0x8d295484, 0x240b0001, -0x3c054000, 0x3c080001, 0x250875cc, 0x250afffc, -0x42042, 0x14800002, 0x24e7ffff, 0x24040008, -0x891024, 0x5040000b, 0x2cc20001, 0x148b0004, -0x0, 0x8d020000, 0x80045ff, 0x451024, -0x8d420000, 0x451024, 0x54400001, 0x24060001, -0x2cc20001, 0x7182b, 0x431024, 0x5440ffed, -0x42042, 0x3c010001, 0x10c00024, 0xac245488, -0x8f830054, 0x24020001, 0x3c010001, 0xac22548c, -0x3c010001, 0xac235548, 0x3c020001, 0x8c42548c, -0x10400006, 0x24020001, 0x3c010001, 0xac20548c, -0x3c010001, 0x370821, 0xac2283ac, 0x3c030001, -0x771821, 0x8c6383ac, 0x24020008, 0x10620005, -0x24020001, 0xc00462f, 0x0, 0x800462c, -0x0, 0x3c030001, 0x8c635488, 0x10620007, -0x2402000e, 0x3c030001, 0x8c637560, 0x10620003, -0x0, 0xc004cf4, 0x8f840220, 0x8fbf0010, -0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c02fdff, -0xafbf0018, 0x8ee30000, 0x3c050001, 0x8ca55488, -0x3c040001, 0x8c8454a8, 0x3442ffff, 0x621824, -0x14a40008, 0xaee30000, 0x3c030001, 0x771821, -0x8c6383ac, 0x3c020001, 0x8c4254ac, 0x10620008, +0x3c010001, 0xac225484, 0x24020015, 0x1462000e, +0x0, 0x97a2001a, 0x3042fff0, 0x3843f420, +0x2c630001, 0x3842f430, 0x2c420001, 0x621825, +0x10600005, 0x24020003, 0x3c010001, 0xac225550, +0x80045a8, 0x3c08fff0, 0x97a30018, 0x24027810, +0x1462000a, 0x24020002, 0x97a2001a, 0x3042fff0, +0x14400006, 0x24020002, 0x24020004, 0x3c010001, +0xac225550, 0x80045a8, 0x3c08fff0, 0x3c010001, +0xac225550, 0x80045a8, 0x3c08fff0, 0x3c020001, +0x8c425484, 0x3c010001, 0xac235550, 0x34420004, +0x3c010001, 0xac225484, 0x3c08fff0, 0x3508bdc0, +0x8f830054, 0x97a60018, 0x3c070001, 0x8ce75550, +0x3c040001, 0x24845290, 0x24020001, 0x3c010001, +0xac22548c, 0xafa60010, 0x3c060001, 0x8cc65484, +0x97a2001a, 0x3c05000d, 0x34a50100, 0x3c010001, +0xac205488, 0x681821, 0x3c010001, 0xac235548, +0xc002403, 0xafa20014, 0x8fbf0028, 0x3e00008, +0x27bd0030, 0x27bdffe8, 0x24070004, 0x3c040001, +0x8c845488, 0x3021, 0x24020001, 0x1482000a, +0xafbf0010, 0x3c020001, 0x8c4275cc, 0x3c050004, +0x30428000, 0x1040000c, 0x34a593e0, 0x3c05000f, +0x80045db, 0x34a54240, 0x3c020001, 0x8c4275cc, +0x3c05000f, 0x30428000, 0x10400003, 0x34a54240, +0x3c05001e, 0x34a58480, 0x3c020001, 0x8c425548, +0x8f830054, 0x451021, 0x431023, 0x45102b, +0x1440002e, 0x0, 0x3c020001, 0x8c425490, +0x1440002a, 0x2cc20001, 0x7182b, 0x431024, +0x1040001d, 0x0, 0x3c090001, 0x8d295484, +0x240b0001, 0x3c054000, 0x3c080001, 0x250875cc, +0x250afffc, 0x42042, 0x14800002, 0x24e7ffff, +0x24040008, 0x891024, 0x5040000b, 0x2cc20001, +0x148b0004, 0x0, 0x8d020000, 0x8004600, +0x451024, 0x8d420000, 0x451024, 0x54400001, +0x24060001, 0x2cc20001, 0x7182b, 0x431024, +0x5440ffed, 0x42042, 0x3c010001, 0x10c00024, +0xac245488, 0x8f830054, 0x24020001, 0x3c010001, +0xac22548c, 0x3c010001, 0xac235548, 0x3c020001, +0x8c42548c, 0x10400006, 0x24020001, 0x3c010001, +0xac20548c, 0x3c010001, 0x370821, 0xac2283ac, +0x3c030001, 0x771821, 0x8c6383ac, 0x24020008, +0x10620005, 0x24020001, 0xc004630, 0x0, +0x800462d, 0x0, 0x3c030001, 0x8c635488, +0x10620007, 0x2402000e, 0x3c030001, 0x8c637560, +0x10620003, 0x0, 0xc004cf4, 0x8f840220, +0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0, +0x3c02fdff, 0xafbf0018, 0x8ee30000, 0x3c050001, +0x8ca55488, 0x3c040001, 0x8c8454a8, 0x3442ffff, +0x621824, 0x14a40008, 0xaee30000, 0x3c030001, +0x771821, 0x8c6383ac, 0x3c020001, 0x8c4254ac, +0x10620008, 0x0, 0x3c020001, 0x571021, +0x8c4283ac, 0x3c010001, 0xac2554a8, 0x3c010001, +0xac2254ac, 0x3c030001, 0x8c635488, 0x24020002, +0x10620131, 0x2c620003, 0x10400005, 0x24020001, +0x10620008, 0x0, 0x800477f, 0x0, +0x24020004, 0x10620079, 0x24020001, 0x8004780, 0x0, 0x3c020001, 0x571021, 0x8c4283ac, -0x3c010001, 0xac2554a8, 0x3c010001, 0xac2254ac, -0x3c030001, 0x8c635488, 0x24020002, 0x10620131, -0x2c620003, 0x10400005, 0x24020001, 0x10620008, -0x0, 0x800477e, 0x0, 0x24020004, -0x10620079, 0x24020001, 0x800477f, 0x0, -0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff, -0x2c620008, 0x10400122, 0x31080, 0x3c010001, -0x220821, 0x8c2252a8, 0x400008, 0x0, -0xc004784, 0x0, 0x3c020001, 0x8c425494, -0x3c010001, 0xac205420, 0x104000bd, 0x24020002, -0x3c010001, 0x370821, 0xac2283ac, 0x3c010001, -0x8004781, 0xac205494, 0xc00492f, 0x0, -0x3c030001, 0x8c6354b0, 0x80046f0, 0x24020011, -0x3c050001, 0x8ca55488, 0x3c060001, 0x8cc675cc, -0xc004fa8, 0x2021, 0x24020005, 0x3c010001, -0xac205494, 0x3c010001, 0x370821, 0x8004781, -0xac2283ac, 0x3c040001, 0x2484529c, 0x3c05000f, -0x34a50100, 0x3021, 0x3821, 0xafa00010, -0xc002407, 0xafa00014, 0x8004781, 0x0, -0x8f820220, 0x3c03f700, 0x431025, 0x8004719, -0xaf820220, 0x8f820220, 0x3c030004, 0x431024, -0x14400090, 0x24020007, 0x8f830054, 0x3c020001, +0x2443ffff, 0x2c620008, 0x10400122, 0x31080, +0x3c010001, 0x220821, 0x8c2252a8, 0x400008, +0x0, 0xc004785, 0x0, 0x3c020001, +0x8c425494, 0x3c010001, 0xac205420, 0x104000bd, +0x24020002, 0x3c010001, 0x370821, 0xac2283ac, +0x3c010001, 0x8004782, 0xac205494, 0xc00492f, +0x0, 0x3c030001, 0x8c6354b0, 0x80046f1, +0x24020011, 0x3c050001, 0x8ca55488, 0x3c060001, +0x8cc675cc, 0xc004fa8, 0x2021, 0x24020005, +0x3c010001, 0xac205494, 0x3c010001, 0x370821, +0x8004782, 0xac2283ac, 0x3c040001, 0x2484529c, +0x3c05000f, 0x34a50100, 0x3021, 0x3821, +0xafa00010, 0xc002403, 0xafa00014, 0x8004782, +0x0, 0x8f820220, 0x3c03f700, 0x431025, +0x800471a, 0xaf820220, 0x8f820220, 0x3c030004, +0x431024, 0x14400090, 0x24020007, 0x8f830054, +0x3c020001, 0x8c425540, 0x2463d8f0, 0x431023, +0x2c422710, 0x144000df, 0x24020001, 0x8004780, +0x0, 0x3c050001, 0x8ca55488, 0xc0050b3, +0x2021, 0xc00517e, 0x2021, 0x3c030001, +0x8c6375c4, 0x46100d1, 0x24020001, 0x3c020008, +0x621024, 0x10400006, 0x0, 0x8f820214, +0x3c03ffff, 0x431024, 0x80046bd, 0x3442251f, +0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f, +0xaf820214, 0x8ee20000, 0x3c030200, 0x431025, +0xaee20000, 0x8f820220, 0x2403fffb, 0x431024, +0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, +0x24020008, 0x3c010001, 0x370821, 0xc0043dd, +0xac2283ac, 0x8004782, 0x0, 0x3c020001, +0x571021, 0x8c4283ac, 0x2443ffff, 0x2c620008, +0x104000ac, 0x31080, 0x3c010001, 0x220821, +0x8c2252c8, 0x400008, 0x0, 0xc00429b, +0x0, 0x3c010001, 0xac20548c, 0xaf800204, +0x3c010001, 0xc004785, 0xac2075b0, 0x24020001, +0x3c010001, 0xac2254a0, 0x24020002, 0x3c010001, +0x370821, 0x8004782, 0xac2283ac, 0xc004802, +0x0, 0x3c030001, 0x8c6354a0, 0x24020009, +0x14620090, 0x24020003, 0x3c010001, 0x370821, +0x8004782, 0xac2283ac, 0x3c020001, 0x8c4275c8, +0x30424000, 0x10400005, 0x0, 0x8f820044, +0x3c03ffff, 0x8004702, 0x34637fff, 0x8f820044, +0x2403ff7f, 0x431024, 0xaf820044, 0x8f830054, +0x800471c, 0x24020004, 0x8f830054, 0x3c020001, 0x8c425540, 0x2463d8f0, 0x431023, 0x2c422710, -0x144000df, 0x24020001, 0x800477f, 0x0, +0x14400074, 0x24020005, 0x3c010001, 0x370821, +0x8004782, 0xac2283ac, 0x8f820220, 0x3c03f700, +0x431025, 0xaf820220, 0xaf800204, 0x3c010001, +0xac2075b0, 0x8f830054, 0x24020006, 0x3c010001, +0x370821, 0xac2283ac, 0x3c010001, 0x8004782, +0xac235540, 0x8f830054, 0x3c020001, 0x8c425540, +0x2463fff6, 0x431023, 0x2c42000a, 0x14400059, +0x0, 0x24020007, 0x3c010001, 0x370821, +0x8004782, 0xac2283ac, 0x8f820220, 0x3c04f700, +0x441025, 0xaf820220, 0x8f820220, 0x3c030300, +0x431024, 0x14400005, 0x1821, 0x8f820220, +0x24030001, 0x441025, 0xaf820220, 0x10600043, +0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, +0x8c845538, 0x431024, 0x3442251f, 0xaf820214, +0x24020008, 0x3c010001, 0x370821, 0x1080000b, +0xac2283ac, 0x3c020001, 0x8c425514, 0x14400007, +0x24020001, 0x3c010001, 0xac227560, 0xc004cf4, +0x8f840220, 0x800476f, 0x0, 0x8f820220, +0x3c030008, 0x431024, 0x14400017, 0x2402000e, +0x3c010001, 0xac227560, 0x8ee20000, 0x2021, +0x3c030200, 0x431025, 0xc00517e, 0xaee20000, +0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, +0x8f820220, 0x34420002, 0xc0043dd, 0xaf820220, 0x3c050001, 0x8ca55488, 0xc0050b3, 0x2021, -0xc00517e, 0x2021, 0x3c030001, 0x8c6375c4, -0x46100d1, 0x24020001, 0x3c020008, 0x621024, -0x10400006, 0x0, 0x8f820214, 0x3c03ffff, -0x431024, 0x80046bc, 0x3442251f, 0x8f820214, -0x3c03ffff, 0x431024, 0x3442241f, 0xaf820214, -0x8ee20000, 0x3c030200, 0x431025, 0xaee20000, +0x8004782, 0x0, 0x3c020001, 0x8c425514, +0x10400010, 0x0, 0x3c020001, 0x8c425510, +0x2442ffff, 0x3c010001, 0xac225510, 0x14400009, +0x24020002, 0x3c010001, 0xac205514, 0x3c010001, +0x8004782, 0xac225510, 0x24020001, 0x3c010001, +0xac22548c, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0x8f820200, 0x8f820220, 0x8f820220, 0x34420004, +0xaf820220, 0x8f820200, 0x3c060001, 0x8cc65488, +0x34420004, 0xaf820200, 0x24020002, 0x10c2003a, +0x2cc20003, 0x10400005, 0x24020001, 0x10c20008, +0x0, 0x80047cb, 0x0, 0x24020004, +0x10c20013, 0x24020001, 0x80047cb, 0x0, +0x3c030001, 0x8c635478, 0x3c020001, 0x8c425480, +0x3c040001, 0x8c84549c, 0x3c050001, 0x8ca5547c, +0xaf860200, 0xaf860220, 0x34630022, 0x441025, +0x451025, 0x34420002, 0x80047ca, 0xaf830200, +0x3c030001, 0x8c635538, 0xaf820200, 0x10600009, +0xaf820220, 0x3c020001, 0x8c425514, 0x14400005, +0x3c033f00, 0x3c020001, 0x8c425470, 0x80047be, +0x346300e0, 0x3c020001, 0x8c425470, 0x3c033f00, +0x346300e2, 0x431025, 0xaf820200, 0x3c030001, +0x8c635474, 0x3c04f700, 0x3c020001, 0x8c425480, +0x3c050001, 0x8ca5549c, 0x641825, 0x431025, +0x451025, 0xaf820220, 0x3e00008, 0x0, +0x8f820220, 0x3c030001, 0x8c635488, 0x34420004, +0xaf820220, 0x24020001, 0x1062000f, 0x0, +0x8f830054, 0x8f820054, 0x24630002, 0x621023, +0x2c420003, 0x10400011, 0x0, 0x8f820054, +0x621023, 0x2c420003, 0x1040000c, 0x0, +0x80047dc, 0x0, 0x8f830054, 0x8f820054, +0x80047e8, 0x24630007, 0x8f820054, 0x621023, +0x2c420008, 0x1440fffc, 0x0, 0x8f8400e0, +0x30820007, 0x1040000d, 0x0, 0x8f820054, +0x8f8300e0, 0x14830009, 0x24450032, 0x8f820054, +0xa21023, 0x2c420033, 0x10400004, 0x0, +0x8f8200e0, 0x1082fff9, 0x0, 0x8f820220, +0x2403fffd, 0x431024, 0xaf820220, 0x3e00008, +0x0, 0x3c030001, 0x8c6354a0, 0x3c020001, +0x8c4254a4, 0x50620004, 0x2463ffff, 0x3c010001, +0xac2354a4, 0x2463ffff, 0x2c620009, 0x1040009d, +0x31080, 0x3c010001, 0x220821, 0x8c2252e8, +0x400008, 0x0, 0x8f820044, 0x34428080, +0xaf820044, 0x8f830054, 0x800489b, 0x24020002, +0x8f830054, 0x3c020001, 0x8c425544, 0x2463d8f0, +0x431023, 0x2c422710, 0x1440008a, 0x24020003, +0x80048a8, 0x0, 0x8f820044, 0x3c03ffff, +0x34637fff, 0x431024, 0xaf820044, 0x8f830054, +0x800489b, 0x24020004, 0x8f830054, 0x3c020001, +0x8c425544, 0x2463fff6, 0x431023, 0x2c42000a, +0x14400078, 0x24020005, 0x80048a8, 0x0, +0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, -0x8f820220, 0x34420002, 0xaf820220, 0x24020008, -0x3c010001, 0x370821, 0xc0043e1, 0xac2283ac, -0x8004781, 0x0, 0x3c020001, 0x571021, -0x8c4283ac, 0x2443ffff, 0x2c620008, 0x104000ac, -0x31080, 0x3c010001, 0x220821, 0x8c2252c8, -0x400008, 0x0, 0xc00429f, 0x0, -0x3c010001, 0xac20548c, 0xaf800204, 0x3c010001, -0xc004784, 0xac2075b0, 0x24020001, 0x3c010001, -0xac2254a0, 0x24020002, 0x3c010001, 0x370821, -0x8004781, 0xac2283ac, 0xc004801, 0x0, -0x3c030001, 0x8c6354a0, 0x24020009, 0x14620090, -0x24020003, 0x3c010001, 0x370821, 0x8004781, -0xac2283ac, 0x3c020001, 0x8c4275c8, 0x30424000, -0x10400005, 0x0, 0x8f820044, 0x3c03ffff, -0x8004701, 0x34637fff, 0x8f820044, 0x2403ff7f, -0x431024, 0xaf820044, 0x8f830054, 0x800471b, -0x24020004, 0x8f830054, 0x3c020001, 0x8c425540, -0x2463d8f0, 0x431023, 0x2c422710, 0x14400074, -0x24020005, 0x3c010001, 0x370821, 0x8004781, -0xac2283ac, 0x8f820220, 0x3c03f700, 0x431025, -0xaf820220, 0xaf800204, 0x3c010001, 0xac2075b0, -0x8f830054, 0x24020006, 0x3c010001, 0x370821, -0xac2283ac, 0x3c010001, 0x8004781, 0xac235540, -0x8f830054, 0x3c020001, 0x8c425540, 0x2463fff6, -0x431023, 0x2c42000a, 0x14400059, 0x0, -0x24020007, 0x3c010001, 0x370821, 0x8004781, -0xac2283ac, 0x8f820220, 0x3c04f700, 0x441025, -0xaf820220, 0x8f820220, 0x3c030300, 0x431024, -0x14400005, 0x1821, 0x8f820220, 0x24030001, -0x441025, 0xaf820220, 0x10600043, 0x24020001, -0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c845538, -0x431024, 0x3442251f, 0xaf820214, 0x24020008, -0x3c010001, 0x370821, 0x1080000b, 0xac2283ac, -0x3c020001, 0x8c425514, 0x14400007, 0x24020001, -0x3c010001, 0xac227560, 0xc004cf4, 0x8f840220, -0x800476e, 0x0, 0x8f820220, 0x3c030008, -0x431024, 0x14400017, 0x2402000e, 0x3c010001, -0xac227560, 0x8ee20000, 0x2021, 0x3c030200, -0x431025, 0xc00517e, 0xaee20000, 0x8f820220, -0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, -0x34420002, 0xc0043e1, 0xaf820220, 0x3c050001, -0x8ca55488, 0xc0050b3, 0x2021, 0x8004781, -0x0, 0x3c020001, 0x8c425514, 0x10400010, -0x0, 0x3c020001, 0x8c425510, 0x2442ffff, -0x3c010001, 0xac225510, 0x14400009, 0x24020002, -0x3c010001, 0xac205514, 0x3c010001, 0x8004781, -0xac225510, 0x24020001, 0x3c010001, 0xac22548c, -0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f820200, -0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, -0x8f820200, 0x3c060001, 0x8cc65488, 0x34420004, -0xaf820200, 0x24020002, 0x10c2003a, 0x2cc20003, -0x10400005, 0x24020001, 0x10c20008, 0x0, -0x80047ca, 0x0, 0x24020004, 0x10c20013, -0x24020001, 0x80047ca, 0x0, 0x3c030001, -0x8c635478, 0x3c020001, 0x8c425480, 0x3c040001, -0x8c84549c, 0x3c050001, 0x8ca5547c, 0xaf860200, -0xaf860220, 0x34630022, 0x441025, 0x451025, -0x34420002, 0x80047c9, 0xaf830200, 0x3c030001, -0x8c635538, 0xaf820200, 0x10600009, 0xaf820220, -0x3c020001, 0x8c425514, 0x14400005, 0x3c033f00, -0x3c020001, 0x8c425470, 0x80047bd, 0x346300e0, -0x3c020001, 0x8c425470, 0x3c033f00, 0x346300e2, -0x431025, 0xaf820200, 0x3c030001, 0x8c635474, -0x3c04f700, 0x3c020001, 0x8c425480, 0x3c050001, -0x8ca5549c, 0x641825, 0x431025, 0x451025, -0xaf820220, 0x3e00008, 0x0, 0x8f820220, -0x3c030001, 0x8c635488, 0x34420004, 0xaf820220, -0x24020001, 0x1062000f, 0x0, 0x8f830054, -0x8f820054, 0x24630002, 0x621023, 0x2c420003, -0x10400011, 0x0, 0x8f820054, 0x621023, -0x2c420003, 0x1040000c, 0x0, 0x80047db, -0x0, 0x8f830054, 0x8f820054, 0x80047e7, -0x24630007, 0x8f820054, 0x621023, 0x2c420008, -0x1440fffc, 0x0, 0x8f8400e0, 0x30820007, -0x1040000d, 0x0, 0x8f820054, 0x8f8300e0, -0x14830009, 0x24450032, 0x8f820054, 0xa21023, -0x2c420033, 0x10400004, 0x0, 0x8f8200e0, -0x1082fff9, 0x0, 0x8f820220, 0x2403fffd, -0x431024, 0xaf820220, 0x3e00008, 0x0, -0x3c030001, 0x8c6354a0, 0x3c020001, 0x8c4254a4, -0x50620004, 0x2463ffff, 0x3c010001, 0xac2354a4, -0x2463ffff, 0x2c620009, 0x1040009d, 0x31080, -0x3c010001, 0x220821, 0x8c2252e8, 0x400008, -0x0, 0x8f820044, 0x34428080, 0xaf820044, -0x8f830054, 0x800489a, 0x24020002, 0x8f830054, +0x8f820220, 0x34420002, 0xaf820220, 0x3c023f00, +0x344200e0, 0xaf820200, 0x8f820200, 0x2403fffd, +0x431024, 0xaf820200, 0x24040001, 0x3405ffff, +0xaf840204, 0x8f830054, 0x8f820054, 0x800484f, +0x24630001, 0x8f820054, 0x621023, 0x2c420002, +0x1440fffc, 0x0, 0x8f820224, 0x42040, +0xa4102b, 0x1040fff2, 0x0, 0x8f820220, +0x3c03f700, 0x431025, 0xaf820220, 0x8f820214, +0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214, +0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, +0x8f820220, 0x3c04f700, 0x34840008, 0x34420002, +0xaf820220, 0x8f820220, 0x3c033f00, 0x346300e2, +0x441025, 0xaf820220, 0xaf830200, 0x8f8400f0, +0x276217f8, 0x14820002, 0x24850008, 0x27651000, +0x8f8200f4, 0x10a20007, 0x3c038000, 0x34630040, +0x3c020001, 0x24425430, 0xac820000, 0xac830004, +0xaf8500f0, 0x8f830054, 0x800489b, 0x24020006, +0x8f830054, 0x3c020001, 0x8c425544, 0x2463fff6, +0x431023, 0x2c42000a, 0x14400022, 0x24020007, +0x80048a8, 0x0, 0x8f8200e0, 0xaf8200e4, +0x8f8200e0, 0xaf8200e8, 0x8f820220, 0x34420004, +0xaf820220, 0x8f820220, 0x2403fff7, 0x431024, +0xaf820220, 0x8f820044, 0x34428080, 0xaf820044, +0x8f830054, 0x24020008, 0x3c010001, 0xac2254a0, +0x3c010001, 0x80048aa, 0xac235544, 0x8f830054, 0x3c020001, 0x8c425544, 0x2463d8f0, 0x431023, -0x2c422710, 0x1440008a, 0x24020003, 0x80048a7, -0x0, 0x8f820044, 0x3c03ffff, 0x34637fff, -0x431024, 0xaf820044, 0x8f830054, 0x800489a, -0x24020004, 0x8f830054, 0x3c020001, 0x8c425544, -0x2463fff6, 0x431023, 0x2c42000a, 0x14400078, -0x24020005, 0x80048a7, 0x0, 0x8f820220, -0x3c03f700, 0x431025, 0xaf820220, 0x8f820220, -0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, -0x34420002, 0xaf820220, 0x3c023f00, 0x344200e0, -0xaf820200, 0x8f820200, 0x2403fffd, 0x431024, -0xaf820200, 0x24040001, 0x3405ffff, 0xaf840204, -0x8f830054, 0x8f820054, 0x800484e, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, -0x0, 0x8f820224, 0x42040, 0xa4102b, -0x1040fff2, 0x0, 0x8f820220, 0x3c03f700, -0x431025, 0xaf820220, 0x8f820214, 0x3c03ffff, -0x431024, 0x3442251f, 0xaf820214, 0x8f820220, -0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, -0x3c04f700, 0x34840008, 0x34420002, 0xaf820220, -0x8f820220, 0x3c033f00, 0x346300e2, 0x441025, -0xaf820220, 0xaf830200, 0x8f8400f0, 0x276217f8, -0x14820002, 0x24850008, 0x27651000, 0x8f8200f4, -0x10a20007, 0x3c038000, 0x34630040, 0x3c020001, -0x24425430, 0xac820000, 0xac830004, 0xaf8500f0, -0x8f830054, 0x800489a, 0x24020006, 0x8f830054, -0x3c020001, 0x8c425544, 0x2463fff6, 0x431023, -0x2c42000a, 0x14400022, 0x24020007, 0x80048a7, -0x0, 0x8f8200e0, 0xaf8200e4, 0x8f8200e0, -0xaf8200e8, 0x8f820220, 0x34420004, 0xaf820220, -0x8f820220, 0x2403fff7, 0x431024, 0xaf820220, -0x8f820044, 0x34428080, 0xaf820044, 0x8f830054, -0x24020008, 0x3c010001, 0xac2254a0, 0x3c010001, -0x80048a9, 0xac235544, 0x8f830054, 0x3c020001, -0x8c425544, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400003, 0x24020009, 0x3c010001, 0xac2254a0, -0x3e00008, 0x0, 0x0, 0x27bdffd8, +0x2c422710, 0x14400003, 0x24020009, 0x3c010001, +0xac2254a0, 0x3e00008, 0x0, 0x27bdffd8, 0xafb20018, 0x809021, 0xafb3001c, 0xa09821, 0xafb10014, 0xc08821, 0xafb00010, 0x8021, 0xafbf0020, 0xa6200000, 0xc004cab, 0x24040001, @@ -3923,14 +3932,14 @@ 0x621825, 0x1460000d, 0x38a30030, 0x2c630001, 0x38a20400, 0x2c420001, 0x621825, 0x14600007, 0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001, -0x621825, 0x10600005, 0x0, 0xc00429f, -0x0, 0x8004d2d, 0x2402000e, 0xc0043e1, +0x621825, 0x10600005, 0x0, 0xc00429b, +0x0, 0x8004d2d, 0x2402000e, 0xc0043dd, 0x0, 0x3c050001, 0x8ca55488, 0xc0050b3, 0x2021, 0x3c030001, 0x8c635488, 0x24020004, 0x14620005, 0x2403fffb, 0x3c020001, 0x8c425484, 0x8004d29, 0x2403fff7, 0x3c020001, 0x8c425484, 0x431024, 0x3c010001, 0xac225484, 0x2402000e, -0x3c010001, 0xc00429f, 0xac227560, 0x8004f27, +0x3c010001, 0xc00429b, 0xac227560, 0x8004f27, 0x0, 0x8f820220, 0x3c030400, 0x431024, 0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001, 0x8c42756c, 0xa32024, 0x431024, 0x1482000c, @@ -3954,10 +3963,10 @@ 0x3c010001, 0xac207590, 0x3c010001, 0xac207570, 0x3c010001, 0xac20756c, 0x3c010001, 0xac207594, 0x3c010001, 0xac207588, 0x3c010001, 0xac207580, -0xc0047cc, 0xaf800224, 0x24020002, 0x3c010001, +0xc0047cd, 0xaf800224, 0x24020002, 0x3c010001, 0xac227560, 0x3c020001, 0x8c4275a0, 0x14400056, 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, -0xc00429f, 0xaee20000, 0xaf800204, 0x8f820200, +0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200, 0x2403fffd, 0x431024, 0xaf820200, 0x3c010001, 0xac2075b0, 0x8f830054, 0x3c020001, 0x8c427588, 0x24040001, 0x3c010001, 0xac24759c, 0x24420001, @@ -4039,7 +4048,7 @@ 0x2c422710, 0x1440003a, 0x0, 0x3c020001, 0x8c4275a0, 0x10400029, 0x2402000e, 0x3c030001, 0x8c6375b4, 0x3c010001, 0x14600015, 0xac227560, -0xc0043e1, 0x0, 0x3c050001, 0x8ca55488, +0xc0043dd, 0x0, 0x3c050001, 0x8ca55488, 0xc0050b3, 0x2021, 0x3c030001, 0x8c635488, 0x24020004, 0x14620005, 0x2403fffb, 0x3c020001, 0x8c425484, 0x8004ef2, 0x2403fff7, 0x3c020001, @@ -4055,7 +4064,7 @@ 0x3c020001, 0x8c42756c, 0x1440000b, 0x0, 0x24020002, 0x3c010001, 0x8004f23, 0xac227560, 0x3c020001, 0x8c427590, 0x10400003, 0x0, -0xc00429f, 0x0, 0x8f820220, 0x3c03f700, +0xc00429b, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030001, 0x246375b8, 0x8c620000, 0x10400005, 0x34422000, 0x3c010001, 0xac2275ac, @@ -4086,14 +4095,14 @@ 0x431025, 0xaf820220, 0x24020100, 0x3c010001, 0xac2275d4, 0x3c010001, 0x8004fa4, 0xac2375dc, 0x34a5ffff, 0x3c040001, 0x24845398, 0xafa30010, -0xc002407, 0xafa00014, 0x8004fa4, 0x0, +0xc002403, 0xafa00014, 0x8004fa4, 0x0, 0x24020030, 0x3c010001, 0xac2275b8, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8, 0xafb10024, 0x808821, 0xafb3002c, 0xa09821, 0xafb00020, 0xc08021, 0x3c040001, 0x248453b0, 0x3c050009, 0x3c020001, 0x8c425488, 0x34a59001, 0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, -0xa7a0001a, 0xafb00014, 0xc002407, 0xafa20010, +0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010, 0x24020002, 0x126200ed, 0x2e620003, 0x10400005, 0x24020001, 0x1262000a, 0x3c02fffb, 0x80050ac, 0x0, 0x24020004, 0x1262006d, 0x24020008, @@ -4114,8 +4123,8 @@ 0x34420001, 0xc0048ee, 0xa4e20002, 0x24040001, 0x2821, 0xc0048ee, 0x27a60018, 0x3c020001, 0x8c425488, 0x24110001, 0x3c010001, 0xac315494, -0x14530004, 0x32028000, 0xc00429f, 0x0, -0x32028000, 0x10400099, 0x0, 0xc00429f, +0x14530004, 0x32028000, 0xc00429b, 0x0, +0x32028000, 0x10400099, 0x0, 0xc00429b, 0x0, 0x24020002, 0x3c010001, 0xac31548c, 0x3c010001, 0x80050ac, 0xac225488, 0x24040001, 0x24050004, 0x27b0001a, 0xc0048ee, 0x2003021, @@ -4153,7 +4162,7 @@ 0x3c010001, 0x230821, 0x80050a5, 0xac2275dc, 0x111140, 0x3c010001, 0x220821, 0xac2075dc, 0x3c030001, 0x8c635488, 0x24020001, 0x10620003, -0x0, 0xc00429f, 0x0, 0x8fbf0030, +0x0, 0xc00429b, 0x0, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, 0x27bdffd0, 0xafb40028, 0x80a021, 0xafb20020, 0x9021, 0xafb30024, @@ -4227,19 +4236,19 @@ 0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe, 0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff, 0x2228824, 0x3c010001, 0x230821, 0xac2075d0, -0x3c010001, 0x230821, 0xac2075d8, 0xc0047cc, +0x3c010001, 0x230821, 0xac2075d8, 0xc0047cd, 0x0, 0xaf900200, 0xaf930220, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 0x80051eb, 0x141140, -0x8f820200, 0x2403fffd, 0x431024, 0xc0047cc, -0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429f, +0x8f820200, 0x2403fffd, 0x431024, 0xc0047cd, +0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b, 0x2228824, 0x141140, 0x3c010001, 0x220821, 0x8005240, 0xac3175c4, 0x149140, 0x3c040001, 0x922021, 0x8c8475c8, 0x3c110001, 0x2328821, 0x8e3175c0, 0x3c024000, 0x821024, 0x14400011, 0x0, 0x3c020001, 0x8c425538, 0x14400006, -0x3c02bfff, 0x8f820200, 0x34420002, 0xc0047cc, -0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429f, +0x3c02bfff, 0x8f820200, 0x34420002, 0xc0047cd, +0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b, 0x2228824, 0x3c010001, 0x320821, 0x8005240, 0xac3175c0, 0x3c020001, 0x8c425538, 0x10400005, 0x3c020020, 0x3c020001, 0x8c425514, 0x1040002b, @@ -4251,7 +4260,7 @@ 0x3c010001, 0x230821, 0xac2275dc, 0x8005231, 0x2629825, 0x141140, 0x3c010001, 0x220821, 0xac2075dc, 0x3c02fffe, 0x3442ffff, 0x2629824, -0xc0047cc, 0x0, 0xaf900200, 0xaf930220, +0xc0047cd, 0x0, 0xaf900200, 0xaf930220, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 0x141140, 0x3c010001, 0x220821, 0xac3175c0, 0x8fbf0024, @@ -4329,10 +4338,10 @@ 0x32203139, 0x39382f30, 0x342f3237, 0x2032323a, 0x31333a34, 0x30207368, 0x75616e67, 0x20457870, 0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20, -0x23312054, 0x75652041, 0x70722032, 0x30203137, -0x3a32313a, 0x30382050, 0x44542031, 0x39393900, +0x23312054, 0x68752041, 0x75672031, 0x32203135, +0x3a34393a, 0x35332050, 0x44542031, 0x39393900, 0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a, -0x2031373a, 0x32313a30, 0x38000000, 0x46575f43, +0x2031353a, 0x34393a35, 0x33000000, 0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, 0x0, @@ -4357,17 +4366,17 @@ 0x6e6f454e, 0x515f5458, 0x0, 0x736e6464, 0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845, 0x0, 0x756e6b72, 0x64747970, 0x65000000, -0x0, 0xacdc, 0xacdc, 0xadac, -0xaac0, 0xaac0, 0xadac, 0xadac, -0xadac, 0xadac, 0xadac, 0xadac, -0xadac, 0xadac, 0xadac, 0xadac, -0xadac, 0xadac, 0xadac, 0xad8c, -0x0, 0xbcb8, 0xbcb8, 0xbd80, -0xae5c, 0xb068, 0xbd80, 0xbd80, -0xbd80, 0xbd80, 0xbd80, 0xbd80, -0xbd80, 0xbd80, 0xbd80, 0xbd80, -0xbd80, 0xbd80, 0xbd80, 0xbd64, -0xb050, 0x24486561, 0x6465723a, 0x202f7072, +0x0, 0xaccc, 0xaccc, 0xad9c, +0xaab0, 0xaab0, 0xad9c, 0xad9c, +0xad9c, 0xad9c, 0xad9c, 0xad9c, +0xad9c, 0xad9c, 0xad9c, 0xad9c, +0xad9c, 0xad9c, 0xad9c, 0xad7c, +0x0, 0xbca8, 0xbca8, 0xbd70, +0xae4c, 0xb058, 0xbd70, 0xbd70, +0xbd70, 0xbd70, 0xbd70, 0xbd70, +0xbd70, 0xbd70, 0xbd70, 0xbd70, +0xbd70, 0xbd70, 0xbd70, 0xbd54, +0xb040, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, 0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e, @@ -4381,17 +4390,17 @@ 0x0, 0x66726d32, 0x4c726753, 0x0, 0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146, 0x0, 0x3f724a42, 0x64446d46, 0x0, -0x0, 0xf688, 0xf688, 0xf688, -0xf688, 0xf688, 0xf688, 0xf688, -0xf688, 0xf688, 0xf688, 0xf688, -0xf688, 0xf688, 0xf688, 0xf688, -0xf680, 0xf680, 0xf680, 0x572d444d, -0x41456e46, 0x0, 0x0, 0xfdd0, -0x1016c, 0xfdec, 0x1016c, 0x1016c, -0x1016c, 0x1016c, 0x1016c, 0x1016c, -0xf714, 0x1016c, 0x1016c, 0x1016c, -0x1016c, 0x1016c, 0x10164, 0x10164, -0x10164, 0x24486561, 0x6465723a, 0x202f7072, +0x0, 0xf678, 0xf678, 0xf678, +0xf678, 0xf678, 0xf678, 0xf678, +0xf678, 0xf678, 0xf678, 0xf678, +0xf678, 0xf678, 0xf678, 0xf678, +0xf670, 0xf670, 0xf670, 0x572d444d, +0x41456e46, 0x0, 0x0, 0xfdc0, +0x1015c, 0xfddc, 0x1015c, 0x1015c, +0x1015c, 0x1015c, 0x1015c, 0x1015c, +0xf704, 0x1015c, 0x1015c, 0x1015c, +0x1015c, 0x1015c, 0x10154, 0x10154, +0x10154, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, 0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31, @@ -4410,13 +4419,13 @@ 0x2e322031, 0x3939382f, 0x30342f32, 0x37203232, 0x3a31333a, 0x33392073, 0x6875616e, 0x67204578, 0x70202400, 0x50726f62, 0x65506879, 0x0, -0x6c6e6b41, 0x53535254, 0x0, 0x11994, -0x119cc, 0x119e4, 0x11a18, 0x11a44, -0x11a58, 0x11a94, 0x11e04, 0x11b6c, -0x11bac, 0x11bd8, 0x11c18, 0x11c48, -0x11c84, 0x11cb8, 0x11e04, 0x12048, -0x12060, 0x12088, 0x120a8, 0x120d0, -0x12200, 0x12228, 0x1227c, 0x122a4, +0x6c6e6b41, 0x53535254, 0x0, 0x11998, +0x119d0, 0x119e8, 0x11a1c, 0x11a48, +0x11a5c, 0x11a98, 0x11e08, 0x11b70, +0x11bb0, 0x11bdc, 0x11c1c, 0x11c4c, +0x11c88, 0x11cbc, 0x11e08, 0x1204c, +0x12064, 0x1208c, 0x120ac, 0x120d4, +0x12204, 0x1222c, 0x12280, 0x122a8, 0x0, 0x1250c, 0x125dc, 0x126b4, 0x12784, 0x127e0, 0x128bc, 0x128e4, 0x129c0, 0x129e8, 0x12b90, 0x12bb8, @@ -4452,28 +4461,29 @@ 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x30001, 0x1, 0x30201, 0x0, 0x0, 0x0 }; +#endif /* Generated by genfw.c */ -int tigon2FwReleaseMajor = 0xc; -int tigon2FwReleaseMinor = 0x3; -int tigon2FwReleaseFix = 0xa; -u32 tigon2FwStartAddr = 0x00004000; -u32 tigon2FwTextAddr = 0x00004000; -int tigon2FwTextLen = 0xed40; -u32 tigon2FwRodataAddr = 0x00012d40; -int tigon2FwRodataLen = 0xff0; -u32 tigon2FwDataAddr = 0x00013d60; -int tigon2FwDataLen = 0x170; -u32 tigon2FwSbssAddr = 0x00013ed0; -int tigon2FwSbssLen = 0xbc; -u32 tigon2FwBssAddr = 0x00013f90; -int tigon2FwBssLen = 0x20c0; +#define tigon2FwReleaseMajor 0xc +#define tigon2FwReleaseMinor 0x3 +#define tigon2FwReleaseFix 0xd +#define tigon2FwStartAddr 0x00004000 +#define tigon2FwTextAddr 0x00004000 +#define tigon2FwTextLen 0xeca0 +#define tigon2FwRodataAddr 0x00012ca0 +#define tigon2FwRodataLen 0xff0 +#define tigon2FwDataAddr 0x00013cc0 +#define tigon2FwDataLen 0x170 +#define tigon2FwSbssAddr 0x00013e30 +#define tigon2FwSbssLen 0xbc +#define tigon2FwBssAddr 0x00013ef0 +#define tigon2FwBssLen 0x20c0 u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x0, 0x10000003, 0x0, 0xd, 0xd, -0x3c1d0001, 0x8fbd3db0, 0x3a0f021, 0x3c100000, +0x3c1d0001, 0x8fbd3d10, 0x3a0f021, 0x3c100000, 0x26104000, 0xc0010c0, 0x0, 0xd, -0x3c1d0001, 0x8fbd3db4, 0x3a0f021, 0x3c100000, -0x26104000, 0xc00178d, 0x0, 0xd, +0x3c1d0001, 0x8fbd3d14, 0x3a0f021, 0x3c100000, +0x26104000, 0xc00178e, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -4485,22 +4495,22 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000008, -0x0, 0x80016de, 0x3c0a0001, 0x80016de, -0x3c0a0002, 0x80016de, 0x0, 0x8002afd, -0x0, 0x8002aa0, 0x0, 0x80016de, -0x3c0a0004, 0x80030d1, 0x0, 0x8001a0e, -0x0, 0x8003779, 0x0, 0x8003720, -0x0, 0x80016de, 0x3c0a0006, 0x80037e7, -0x3c0a0007, 0x80016de, 0x3c0a0008, 0x80016de, -0x3c0a0009, 0x800383f, 0x0, 0x8002cf7, -0x0, 0x80016de, 0x3c0a000b, 0x80016de, -0x3c0a000c, 0x80016de, 0x3c0a000d, 0x80027c5, -0x0, 0x800275a, 0x0, 0x80016de, -0x3c0a000e, 0x8001f28, 0x0, 0x8001920, -0x0, 0x80019c0, 0x0, 0x8003aa8, -0x0, 0x8003a96, 0x0, 0x80016de, -0x0, 0x80018c6, 0x0, 0x80016de, -0x0, 0x80016de, 0x3c0a0013, 0x80016de, +0x0, 0x80016dd, 0x3c0a0001, 0x80016dd, +0x3c0a0002, 0x80016dd, 0x0, 0x8002ab5, +0x0, 0x8002a58, 0x0, 0x80016dd, +0x3c0a0004, 0x800306c, 0x0, 0x8001a07, +0x0, 0x80036c3, 0x0, 0x8004aad, +0x0, 0x80016dd, 0x3c0a0006, 0x8003731, +0x3c0a0007, 0x80016dd, 0x3c0a0008, 0x80016dd, +0x3c0a0009, 0x8003789, 0x0, 0x8002caf, +0x0, 0x80016dd, 0x3c0a000b, 0x80016dd, +0x3c0a000c, 0x80016dd, 0x3c0a000d, 0x800277b, +0x0, 0x8002710, 0x0, 0x80016dd, +0x3c0a000e, 0x8001f20, 0x0, 0x8001919, +0x0, 0x80019b9, 0x0, 0x8003a08, +0x0, 0x80039f6, 0x0, 0x80016dd, +0x0, 0x80018c6, 0x0, 0x80016dd, +0x0, 0x80016dd, 0x3c0a0013, 0x80016dd, 0x3c0a0014, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -4518,511 +4528,511 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x27bdffe0, 0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140, -0x24030003, 0xaf8300ec, 0x34420004, 0xc0029e8, -0xaf820140, 0x3c0100c0, 0xc001712, 0xac203ffc, -0x403021, 0x3c020008, 0x3c010001, 0xac263ee8, -0x50c2000d, 0x3c020003, 0x3c100010, 0x10d00009, -0x24050100, 0x3c040001, 0x24842df4, 0x3821, -0xafa00010, 0xc002a03, 0xafa00014, 0x3c010001, -0xac303ee8, 0x3c020003, 0x34422000, 0x3c010001, -0xac223ef8, 0x24020008, 0x3c010001, 0xac223f00, -0x2402001f, 0x3c010001, 0xac223f10, 0x24020016, -0x3c010001, 0xac223ee4, 0x3c05fffe, 0x34a56f08, -0x3c020001, 0x8c423ee8, 0x3c030001, 0x24636050, -0x3c040001, 0x8c843d64, 0x431023, 0x14800002, +0x24030003, 0xaf8300ec, 0x34420004, 0xc0029a0, +0xaf820140, 0x3c0100c0, 0xc001711, 0xac203ffc, +0x403021, 0x3c020008, 0x3c010001, 0xac263e48, +0x50c2000d, 0x24020008, 0x3c100010, 0x10d00009, +0x24050100, 0x3c040001, 0x24842d54, 0x3821, +0xafa00010, 0xc0029bb, 0xafa00014, 0x3c010001, +0xac303e48, 0x24020008, 0x3c010001, 0xac223e60, +0x2402001f, 0x3c010001, 0xac223e70, 0x24020016, +0x3c010001, 0xac223e44, 0x3c05fffe, 0x34a56f08, +0x3c020001, 0x8c423e48, 0x3c030001, 0x24635fb0, +0x3c040001, 0x8c843cc4, 0x431023, 0x14800002, 0x458021, 0x2610fa48, 0x2402f000, 0x2028024, -0xc001734, 0x2002021, 0x2022823, 0x3c040020, +0xc001733, 0x2002021, 0x2022823, 0x3c040020, 0x821823, 0x651823, 0x247bb000, 0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf, 0x34c6f000, -0x3c070001, 0x8ce73d60, 0x3c0300bf, 0x3463e000, -0x852023, 0x3c010001, 0xac243ef4, 0x822023, -0x3c010001, 0xac223ed0, 0x27620ffc, 0x3c010001, -0xac223db0, 0x27621ffc, 0xdb3023, 0x7b1823, -0x3c010001, 0xac253edc, 0x3c010001, 0xac243ed4, -0x3c010001, 0xac223db4, 0xaf860150, 0x10e00011, -0xaf830250, 0x3c1d0001, 0x8fbd3d6c, 0x3a0f021, -0xc0016f8, 0x0, 0x3c020001, 0x8c423d70, -0x3c030001, 0x8c633d74, 0x2442fe00, 0x24630200, -0x3c010001, 0xac223d70, 0x3c010001, 0x10000004, -0xac233d74, 0x3c1d0001, 0x8fbd3db0, 0x3a0f021, -0x3c020001, 0x8c423d64, 0x1040000d, 0x26fafa48, -0x3c020001, 0x8c423d70, 0x3c030001, 0x8c633d74, -0x3c1a0001, 0x8f5a3d74, 0x2442fa48, 0x246305b8, -0x3c010001, 0xac223d70, 0x3c010001, 0xac233d74, -0x3c020001, 0x8c423d68, 0x14400003, 0x0, -0x3c010001, 0xac203d70, 0xc00114d, 0x0, -0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, -0x3c020001, 0x8c423d70, 0x3c030001, 0x8c633d74, -0x27bdffa0, 0xafb00040, 0x3c100001, 0x8e1037d8, -0x3c040001, 0x24842e00, 0xafbf0058, 0xafbe0054, -0xafb50050, 0xafb3004c, 0xafb20048, 0xafb10044, -0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014, -0x8f860040, 0x24050200, 0xc002a03, 0x2003821, -0x8f830040, 0x3c02f000, 0x621824, 0x3c026000, -0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001, -0x24842e08, 0xa3ae003f, 0xafa00010, 0xafa00014, -0x8f860040, 0x24050300, 0xc002a03, 0x2003821, -0x8f820240, 0x3c030001, 0x431025, 0xaf820240, -0xaf800048, 0x8f820048, 0x14400005, 0x0, -0xaf800048, 0x8f820048, 0x10400004, 0x0, -0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c, -0x2e02021, 0x3c050001, 0xc002a70, 0x34a540f8, -0x3402021, 0xc002a70, 0x240505b8, 0x3c020001, -0x8c423ef4, 0x3c0d0001, 0x8dad3ed4, 0x3c030001, -0x8c633ed0, 0x3c080001, 0x8d083edc, 0x3c090001, -0x8d293ef8, 0x3c0a0001, 0x8d4a3f00, 0x3c0b0001, -0x8d6b3f10, 0x3c0c0001, 0x8d8c3ee4, 0x3c040001, -0x24842e14, 0x24050400, 0xaf420130, 0x8f420130, -0x24060001, 0x24070001, 0xaf400000, 0xaf4d012c, -0xaf430138, 0xaf48013c, 0xaf490140, 0xaf4a0144, -0xaf4b0148, 0xaf4c014c, 0x2442ff80, 0xaf420134, -0x24020001, 0xafa20010, 0xc002a03, 0xafa00014, -0x8f42012c, 0xafa20010, 0x8f420130, 0xafa20014, -0x8f460138, 0x8f47013c, 0x3c040001, 0x24842e20, -0xc002a03, 0x24050500, 0xafb70010, 0xafba0014, -0x8f460140, 0x8f470144, 0x3c040001, 0x24842e2c, -0xc002a03, 0x24050600, 0x3c020001, 0x8c423ee8, -0x3603821, 0x3c060001, 0x24c66050, 0x2448ffff, -0x1061824, 0xe81024, 0x43102b, 0x10400006, -0x24050900, 0x3c040001, 0x24842e38, 0xafa80010, -0xc002a03, 0xafa00014, 0x8f82000c, 0xafa20010, -0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004, -0x3c040001, 0x24842e44, 0xc002a03, 0x24051000, -0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c, -0x3c040001, 0x24842e4c, 0x24051100, 0xafa20010, -0xc002a03, 0xafa30014, 0xaf800054, 0xaf80011c, -0x8c020218, 0x30420002, 0x10400009, 0x0, -0x8c020220, 0x3c030002, 0x34630004, 0x431025, -0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004, -0x8c020220, 0x3c030002, 0x34630006, 0x431025, -0xaf42000c, 0x8c02021c, 0x34420006, 0xaf420014, -0x8c020218, 0x30420010, 0x1040000a, 0x0, -0x8c02021c, 0x34420004, 0xaf420010, 0x8c020220, -0x3c03000a, 0x34630004, 0x431025, 0x10000009, -0xaf420008, 0x8c020220, 0x3c03000a, 0x34630006, -0x431025, 0xaf420008, 0x8c02021c, 0x34420006, -0xaf420010, 0x24020001, 0xaf8200a0, 0xaf8200b0, -0x8f830054, 0x8f820054, 0x10000002, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, -0x0, 0x8c040208, 0x8c05020c, 0x26e20028, -0xaee20020, 0x24020490, 0xaee20010, 0xaee40008, -0xaee5000c, 0x26e40008, 0x8c820000, 0x8c830004, -0xaf820090, 0xaf830094, 0x8c820018, 0xaf8200b4, -0x9482000a, 0xaf82009c, 0x8f8200b0, 0x8f430014, -0x431025, 0xaf8200b0, 0x8f8200b0, 0x30420004, -0x1440fffd, 0x24051200, 0x96e20472, 0x96e60452, -0x96e70462, 0xafa20010, 0x96e20482, 0x3c040001, -0x24842e54, 0xc002a03, 0xafa20014, 0x96f00452, -0x32020001, 0x10400002, 0xb021, 0x24160001, -0x32020002, 0x54400001, 0x36d60002, 0x32020008, -0x54400001, 0x36d60004, 0x32020010, 0x54400001, -0x36d60008, 0x32020020, 0x54400001, 0x36d60010, -0x32020040, 0x54400001, 0x36d60020, 0x32020080, -0x54400001, 0x36d60040, 0x96e60482, 0x30c20200, -0x54400001, 0x36d64000, 0x96e30472, 0x30620200, -0x10400003, 0x30620100, 0x10000003, 0x36d62000, -0x54400001, 0x36d61000, 0x96f00462, 0x32c24000, -0x14400004, 0x3207009b, 0x30c2009b, 0x14e20007, -0x240e0001, 0x32c22000, 0x1440000d, 0x32020001, -0x3062009b, 0x10e20009, 0x240e0001, 0x3c040001, -0x24842e60, 0x24051300, 0x2003821, 0xa3ae003f, -0xafa30010, 0xc002a03, 0xafa00014, 0x32020001, -0x54400001, 0x36d60080, 0x32020002, 0x54400001, -0x36d60100, 0x32020008, 0x54400001, 0x36d60200, -0x32020010, 0x54400001, 0x36d60400, 0x32020080, -0x54400001, 0x36d60800, 0x8c020218, 0x30420200, -0x10400002, 0x3c020008, 0x2c2b025, 0x8c020218, -0x30420800, 0x10400002, 0x3c020080, 0x2c2b025, -0x8c020218, 0x30420400, 0x10400002, 0x3c020100, -0x2c2b025, 0x8c020218, 0x30420100, 0x10400002, -0x3c020200, 0x2c2b025, 0x8c020218, 0x30420080, -0x10400002, 0x3c020400, 0x2c2b025, 0x8c020218, -0x30422000, 0x10400002, 0x3c020010, 0x2c2b025, -0x8c020218, 0x30424000, 0x10400002, 0x3c020020, -0x2c2b025, 0x8c020218, 0x30421000, 0x10400002, -0x3c020040, 0x2c2b025, 0x8ee20498, 0x8ee3049c, -0xaf420150, 0xaf430154, 0x8ee204a0, 0x8ee304a4, -0xaf420158, 0xaf43015c, 0x8ee204a8, 0x8ee304ac, -0xaf420160, 0xaf430164, 0x8ee20428, 0x8ee3042c, -0xaf420168, 0xaf43016c, 0x8ee20448, 0x8ee3044c, -0xaf420170, 0xaf430174, 0x8ee20458, 0x8ee3045c, -0xaf420178, 0xaf43017c, 0x8ee20468, 0x8ee3046c, -0xaf420180, 0xaf430184, 0x8ee20478, 0x8ee3047c, -0xaf420188, 0xaf43018c, 0x8ee20488, 0x8ee3048c, -0xaf420190, 0xaf430194, 0x8ee204b0, 0x8ee304b4, -0x24040080, 0xaf420198, 0xaf43019c, 0xc002a70, -0x24050080, 0x8c02025c, 0x27440214, 0xaf4201e0, -0x8c020260, 0x24050200, 0x24060008, 0xc002a87, -0xaf4201e8, 0x3c043b9a, 0x3484ca00, 0x3821, -0x24020006, 0x24030002, 0xaf4201e4, 0x240203e8, -0xaf4301f4, 0xaf4301f0, 0xaf4401ec, 0xaf420284, -0x24020001, 0xaf430280, 0xaf42028c, 0x3c030001, -0x671821, 0x90633d78, 0x3471021, 0x24e70001, -0xa043021c, 0x2ce2000f, 0x1440fff8, 0x3471821, -0x24e70001, 0x3c080001, 0x350840f8, 0x8f820040, -0x3c040001, 0x24842e6c, 0x24051400, 0x21702, -0x24420030, 0xa062021c, 0x3471021, 0xa040021c, -0x8c070218, 0x2c03021, 0x240205b8, 0xafa20010, -0xc002a03, 0xafa80014, 0x3c040001, 0x24842e78, -0x3c050000, 0x24a55b3c, 0x24060010, 0x27b10030, -0x2203821, 0x27b30034, 0xc001750, 0xafb30010, -0x3c030001, 0x8c633d68, 0x1060000a, 0x408021, -0x8fa30030, 0x2405ff00, 0x8fa20034, 0x246400ff, -0x852024, 0x831823, 0x431023, 0xafa20034, -0xafa40030, 0xafb30010, 0x3c040001, 0x24842e84, -0x3c050000, 0x24a54100, 0x24060108, 0xc001750, -0x2203821, 0x409021, 0x32c20003, 0x50400045, -0x2203821, 0x8f820050, 0x3c030010, 0x431024, +0x3c070001, 0x8ce73cc0, 0x3c0300bf, 0x3463e000, +0x852023, 0x3c010001, 0xac243e54, 0x822023, +0x3c010001, 0xac253e3c, 0x52842, 0x3c010001, +0xac223e30, 0x27620ffc, 0x3c010001, 0xac223d10, +0x27621ffc, 0xdb3023, 0x7b1823, 0x3c010001, +0xac243e34, 0x3c010001, 0xac253e58, 0x3c010001, +0xac223d14, 0xaf860150, 0x10e00011, 0xaf830250, +0x3c1d0001, 0x8fbd3ccc, 0x3a0f021, 0xc0016f7, +0x0, 0x3c020001, 0x8c423cd0, 0x3c030001, +0x8c633cd4, 0x2442fe00, 0x24630200, 0x3c010001, +0xac223cd0, 0x3c010001, 0x10000004, 0xac233cd4, +0x3c1d0001, 0x8fbd3d10, 0x3a0f021, 0x3c020001, +0x8c423cc4, 0x1040000d, 0x26fafa48, 0x3c020001, +0x8c423cd0, 0x3c030001, 0x8c633cd4, 0x3c1a0001, +0x8f5a3cd4, 0x2442fa48, 0x246305b8, 0x3c010001, +0xac223cd0, 0x3c010001, 0xac233cd4, 0x3c020001, +0x8c423cc8, 0x14400003, 0x0, 0x3c010001, +0xac203cd0, 0xc00114c, 0x0, 0x8fbf001c, +0x8fb00018, 0x3e00008, 0x27bd0020, 0x3c020001, +0x8c423cd0, 0x3c030001, 0x8c633cd4, 0x27bdffa0, +0xafb00040, 0x3c100001, 0x8e103738, 0x3c040001, +0x24842d60, 0xafbf0058, 0xafbe0054, 0xafb50050, +0xafb3004c, 0xafb20048, 0xafb10044, 0xafa20034, +0xafa30030, 0xafa00010, 0xafa00014, 0x8f860040, +0x24050200, 0xc0029bb, 0x2003821, 0x8f830040, +0x3c02f000, 0x621824, 0x3c026000, 0x1062000b, +0xa3a0003f, 0x240e0001, 0x3c040001, 0x24842d68, +0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f860040, +0x24050300, 0xc0029bb, 0x2003821, 0x8f820240, +0x3c030001, 0x431025, 0xaf820240, 0xaf800048, +0x8f820048, 0x14400005, 0x0, 0xaf800048, +0x8f820048, 0x10400004, 0x0, 0xaf800048, +0x10000003, 0x2e02021, 0xaf80004c, 0x2e02021, +0x3c050001, 0xc002a28, 0x34a540f8, 0x3402021, +0xc002a28, 0x240505b8, 0x3c020001, 0x8c423e54, +0x3c0d0001, 0x8dad3e34, 0x3c030001, 0x8c633e30, +0x3c080001, 0x8d083e3c, 0x3c090001, 0x8d293e58, +0x3c0a0001, 0x8d4a3e60, 0x3c0b0001, 0x8d6b3e70, +0x3c0c0001, 0x8d8c3e44, 0x3c040001, 0x24842d74, +0x24050400, 0xaf420130, 0x8f420130, 0x24060001, +0x24070001, 0xaf400000, 0xaf4d012c, 0xaf430138, +0xaf48013c, 0xaf490140, 0xaf4a0144, 0xaf4b0148, +0xaf4c014c, 0x2442ff80, 0xaf420134, 0x24020001, +0xafa20010, 0xc0029bb, 0xafa00014, 0x8f42012c, +0xafa20010, 0x8f420130, 0xafa20014, 0x8f460138, +0x8f47013c, 0x3c040001, 0x24842d80, 0xc0029bb, +0x24050500, 0xafb70010, 0xafba0014, 0x8f460140, +0x8f470144, 0x3c040001, 0x24842d8c, 0xc0029bb, +0x24050600, 0x3c020001, 0x8c423e48, 0x3603821, +0x3c060001, 0x24c65fb0, 0x2448ffff, 0x1061824, +0xe81024, 0x43102b, 0x10400006, 0x24050900, +0x3c040001, 0x24842d98, 0xafa80010, 0xc0029bb, +0xafa00014, 0x8f82000c, 0xafa20010, 0x8f82003c, +0xafa20014, 0x8f860000, 0x8f870004, 0x3c040001, +0x24842da4, 0xc0029bb, 0x24051000, 0x8c020220, +0x8c030224, 0x8c060218, 0x8c07021c, 0x3c040001, +0x24842dac, 0x24051100, 0xafa20010, 0xc0029bb, +0xafa30014, 0xaf800054, 0xaf80011c, 0x8c020218, +0x30420002, 0x10400009, 0x0, 0x8c020220, +0x3c030002, 0x34630004, 0x431025, 0xaf42000c, +0x8c02021c, 0x10000008, 0x34420004, 0x8c020220, +0x3c030002, 0x34630006, 0x431025, 0xaf42000c, +0x8c02021c, 0x34420006, 0xaf420014, 0x8c020218, +0x30420010, 0x1040000a, 0x0, 0x8c02021c, +0x34420004, 0xaf420010, 0x8c020220, 0x3c03000a, +0x34630004, 0x431025, 0x10000009, 0xaf420008, +0x8c020220, 0x3c03000a, 0x34630006, 0x431025, +0xaf420008, 0x8c02021c, 0x34420006, 0xaf420010, +0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054, +0x8f820054, 0x10000002, 0x24630064, 0x8f820054, +0x621023, 0x2c420065, 0x1440fffc, 0x0, +0x8c040208, 0x8c05020c, 0x26e20028, 0xaee20020, +0x24020490, 0xaee20010, 0xaee40008, 0xaee5000c, +0x26e40008, 0x8c820000, 0x8c830004, 0xaf820090, +0xaf830094, 0x8c820018, 0xaf8200b4, 0x9482000a, +0xaf82009c, 0x8f8200b0, 0x8f430014, 0x431025, +0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd, +0x24051200, 0x96e20472, 0x96e60452, 0x96e70462, +0xafa20010, 0x96e20482, 0x3c040001, 0x24842db4, +0xc0029bb, 0xafa20014, 0x96f00452, 0x32020001, +0x10400002, 0xb021, 0x24160001, 0x32020002, +0x54400001, 0x36d60002, 0x32020008, 0x54400001, +0x36d60004, 0x32020010, 0x54400001, 0x36d60008, +0x32020020, 0x54400001, 0x36d60010, 0x32020040, +0x54400001, 0x36d60020, 0x32020080, 0x54400001, +0x36d60040, 0x96e60482, 0x30c20200, 0x54400001, +0x36d64000, 0x96e30472, 0x30620200, 0x10400003, +0x30620100, 0x10000003, 0x36d62000, 0x54400001, +0x36d61000, 0x96f00462, 0x32c24000, 0x14400004, +0x3207009b, 0x30c2009b, 0x14e20007, 0x240e0001, +0x32c22000, 0x1440000d, 0x32020001, 0x3062009b, +0x10e20009, 0x240e0001, 0x3c040001, 0x24842dc0, +0x24051300, 0x2003821, 0xa3ae003f, 0xafa30010, +0xc0029bb, 0xafa00014, 0x32020001, 0x54400001, +0x36d60080, 0x32020002, 0x54400001, 0x36d60100, +0x32020008, 0x54400001, 0x36d60200, 0x32020010, +0x54400001, 0x36d60400, 0x32020080, 0x54400001, +0x36d60800, 0x8c020218, 0x30420200, 0x10400002, +0x3c020008, 0x2c2b025, 0x8c020218, 0x30420800, +0x10400002, 0x3c020080, 0x2c2b025, 0x8c020218, +0x30420400, 0x10400002, 0x3c020100, 0x2c2b025, +0x8c020218, 0x30420100, 0x10400002, 0x3c020200, +0x2c2b025, 0x8c020218, 0x30420080, 0x10400002, +0x3c020400, 0x2c2b025, 0x8c020218, 0x30422000, +0x10400002, 0x3c020010, 0x2c2b025, 0x8c020218, +0x30424000, 0x10400002, 0x3c020020, 0x2c2b025, +0x8c020218, 0x30421000, 0x10400002, 0x3c020040, +0x2c2b025, 0x8ee20498, 0x8ee3049c, 0xaf420150, +0xaf430154, 0x8ee204a0, 0x8ee304a4, 0xaf420158, +0xaf43015c, 0x8ee204a8, 0x8ee304ac, 0xaf420160, +0xaf430164, 0x8ee20428, 0x8ee3042c, 0xaf420168, +0xaf43016c, 0x8ee20448, 0x8ee3044c, 0xaf420170, +0xaf430174, 0x8ee20458, 0x8ee3045c, 0xaf420178, +0xaf43017c, 0x8ee20468, 0x8ee3046c, 0xaf420180, +0xaf430184, 0x8ee20478, 0x8ee3047c, 0xaf420188, +0xaf43018c, 0x8ee20488, 0x8ee3048c, 0xaf420190, +0xaf430194, 0x8ee204b0, 0x8ee304b4, 0x24040080, +0xaf420198, 0xaf43019c, 0xc002a28, 0x24050080, +0x8c02025c, 0x27440214, 0xaf4201e0, 0x8c020260, +0x24050200, 0x24060008, 0xc002a3f, 0xaf4201e8, +0x3c043b9a, 0x3484ca00, 0x3821, 0x24020006, +0x24030002, 0xaf4201e4, 0x240203e8, 0xaf4301f4, +0xaf4301f0, 0xaf4401ec, 0xaf420284, 0x24020001, +0xaf430280, 0xaf42028c, 0x3c030001, 0x671821, +0x90633cd8, 0x3471021, 0x24e70001, 0xa043021c, +0x2ce2000f, 0x1440fff8, 0x3471821, 0x24e70001, +0x3c080001, 0x350840f8, 0x8f820040, 0x3c040001, +0x24842dcc, 0x24051400, 0x21702, 0x24420030, +0xa062021c, 0x3471021, 0xa040021c, 0x8c070218, +0x2c03021, 0x240205b8, 0xafa20010, 0xc0029bb, +0xafa80014, 0x3c040001, 0x24842dd8, 0x3c050000, +0x24a55b38, 0x24060010, 0x27b10030, 0x2203821, +0x27b30034, 0xc001751, 0xafb30010, 0x3c030001, +0x8c633cc8, 0x1060000a, 0x408021, 0x8fa30030, +0x2405ff00, 0x8fa20034, 0x246400ff, 0x852024, +0x831823, 0x431023, 0xafa20034, 0xafa40030, +0xafb30010, 0x3c040001, 0x24842de4, 0x3c050000, +0x24a54100, 0x24060108, 0xc001751, 0x2203821, +0x409021, 0x32c20003, 0x50400045, 0x2203821, +0x8f820050, 0x3c030010, 0x431024, 0x10400016, +0x0, 0x8c020218, 0x30420040, 0x1040000f, +0x24020001, 0x8f820050, 0x8c030218, 0x240e0001, +0x3c040001, 0x24842df0, 0xa3ae003f, 0xafa20010, +0xafa30014, 0x8f870040, 0x24051500, 0xc0029bb, +0x2c03021, 0x10000004, 0x0, 0x3c010001, +0x370821, 0xa02240f4, 0x3c040001, 0x24842dfc, +0x3c050001, 0x24a52c20, 0x3c060001, 0x24c62c8c, +0xc53023, 0x8f420010, 0x27b30030, 0x2603821, +0x27b10034, 0x34420a00, 0xaf420010, 0xc001751, +0xafb10010, 0x3c040001, 0x24842e10, 0x3c050001, +0x24a5af38, 0x3c060001, 0x24c6b2b4, 0xc53023, +0x2603821, 0xaf420108, 0xc001751, 0xafb10010, +0x3c040001, 0x24842e2c, 0x3c050001, 0x24a5b6c4, +0x3c060001, 0x24c6c1a8, 0xc53023, 0x2603821, +0x3c010001, 0xac223ea0, 0xc001751, 0xafb10010, +0x3c040001, 0x24842e44, 0x10000024, 0x24051600, +0x3c040001, 0x24842e4c, 0x3c050001, 0x24a59b0c, +0x3c060001, 0x24c69c38, 0xc53023, 0xc001751, +0xafb30010, 0x3c040001, 0x24842e5c, 0x3c050001, +0x24a5aad4, 0x3c060001, 0x24c6af30, 0xc53023, +0x2203821, 0xaf420108, 0xc001751, 0xafb30010, +0x3c040001, 0x24842e70, 0x3c050001, 0x24a5b2bc, +0x3c060001, 0x24c6b6bc, 0xc53023, 0x2203821, +0x3c010001, 0xac223ea0, 0xc001751, 0xafb30010, +0x3c040001, 0x24842e84, 0x24051650, 0x2c03021, +0x3821, 0x3c010001, 0xac223ea4, 0xafa00010, +0xc0029bb, 0xafa00014, 0x32c20020, 0x10400021, +0x27a70030, 0x3c040001, 0x24842e90, 0x3c050001, +0x24a5a960, 0x3c060001, 0x24c6aacc, 0xc53023, +0x24022000, 0xaf42001c, 0x27a20034, 0xc001751, +0xafa20010, 0x21900, 0x31982, 0x3c040800, +0x641825, 0xae430028, 0x24030010, 0xaf43003c, +0x96e30450, 0xaf430040, 0x8f430040, 0x3c040001, +0x24842ea4, 0xafa00014, 0xafa30010, 0x8f47001c, +0x24051660, 0x3c010001, 0xac223e9c, 0x10000025, +0x32c60020, 0x8ee20448, 0x8ee3044c, 0xaf43001c, +0x8f42001c, 0x2442e000, 0x2c422001, 0x1440000a, +0x240e0001, 0x3c040001, 0x24842eb0, 0xa3ae003f, +0xafa00010, 0xafa00014, 0x8f46001c, 0x24051700, +0xc0029bb, 0x3821, 0x3c020000, 0x24425b74, +0x21100, 0x21182, 0x3c030800, 0x431025, +0xae420028, 0x24020008, 0xaf42003c, 0x96e20450, +0xaf420040, 0x8f420040, 0x3c040001, 0x24842ebc, +0xafa00014, 0xafa20010, 0x8f47001c, 0x24051800, +0x32c60020, 0xc0029bb, 0x0, 0x3c030001, +0x8c633ea0, 0x3c050fff, 0x34a5ffff, 0x3c020001, +0x8c423ea4, 0x3c040800, 0x651824, 0x31882, +0x641825, 0x451024, 0x21082, 0x441025, +0xae420080, 0x32c20180, 0x10400056, 0xae430020, +0x8f82005c, 0x3c030080, 0x431024, 0x1040000d, +0x0, 0x8f820050, 0xafa20010, 0x8f82005c, +0x240e0001, 0x3c040001, 0x24842ec8, 0xa3ae003f, +0xafa20014, 0x8f870040, 0x24051900, 0xc0029bb, +0x2c03021, 0x8f820050, 0x3c030010, 0x431024, 0x10400016, 0x0, 0x8c020218, 0x30420040, 0x1040000f, 0x24020001, 0x8f820050, 0x8c030218, -0x240e0001, 0x3c040001, 0x24842e90, 0xa3ae003f, -0xafa20010, 0xafa30014, 0x8f870040, 0x24051500, -0xc002a03, 0x2c03021, 0x10000004, 0x0, +0x240e0001, 0x3c040001, 0x24842df0, 0xa3ae003f, +0xafa20010, 0xafa30014, 0x8f870040, 0x24052000, +0xc0029bb, 0x2c03021, 0x10000004, 0x0, 0x3c010001, 0x370821, 0xa02240f4, 0x3c040001, -0x24842e9c, 0x3c050001, 0x24a59ce8, 0x3c060001, -0x24c69d60, 0xc53023, 0x8f420010, 0x27b30030, -0x2603821, 0x27b10034, 0x34420a00, 0xaf420010, -0xc001750, 0xafb10010, 0x3c040001, 0x24842eb0, -0x3c050001, 0x24a5b058, 0x3c060001, 0x24c6b3d4, -0xc53023, 0x2603821, 0xaf420108, 0xc001750, -0xafb10010, 0x3c040001, 0x24842ecc, 0x3c050001, -0x24a5b7e4, 0x3c060001, 0x24c6c2c8, 0xc53023, -0x2603821, 0x3c010001, 0xac223f40, 0xc001750, -0xafb10010, 0x3c040001, 0x24842ee4, 0x10000024, -0x24051600, 0x3c040001, 0x24842eec, 0x3c050001, -0x24a59bb4, 0x3c060001, 0x24c69ce0, 0xc53023, -0xc001750, 0xafb30010, 0x3c040001, 0x24842efc, -0x3c050001, 0x24a5abf4, 0x3c060001, 0x24c6b050, -0xc53023, 0x2203821, 0xaf420108, 0xc001750, -0xafb30010, 0x3c040001, 0x24842f10, 0x3c050001, -0x24a5b3dc, 0x3c060001, 0x24c6b7dc, 0xc53023, -0x2203821, 0x3c010001, 0xac223f40, 0xc001750, -0xafb30010, 0x3c040001, 0x24842f24, 0x24051650, -0x2c03021, 0x3821, 0x3c010001, 0xac223f44, -0xafa00010, 0xc002a03, 0xafa00014, 0x32c20020, -0x10400021, 0x27a70030, 0x3c040001, 0x24842f30, -0x3c050001, 0x24a5aa80, 0x3c060001, 0x24c6abec, -0xc53023, 0x24022000, 0xaf42001c, 0x27a20034, -0xc001750, 0xafa20010, 0x21900, 0x31982, -0x3c040800, 0x641825, 0xae430028, 0x24030010, -0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040, -0x3c040001, 0x24842f44, 0xafa00014, 0xafa30010, -0x8f47001c, 0x24051660, 0x3c010001, 0xac223f3c, -0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c, -0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001, -0x1440000a, 0x240e0001, 0x3c040001, 0x24842f50, -0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c, -0x24051700, 0xc002a03, 0x3821, 0x3c020000, -0x24425b78, 0x21100, 0x21182, 0x3c030800, -0x431025, 0xae420028, 0x24020008, 0xaf42003c, -0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001, -0x24842f5c, 0xafa00014, 0xafa20010, 0x8f47001c, -0x24051800, 0x32c60020, 0xc002a03, 0x0, -0x3c030001, 0x8c633f40, 0x3c050fff, 0x34a5ffff, -0x3c020001, 0x8c423f44, 0x3c040800, 0x651824, -0x31882, 0x641825, 0x451024, 0x21082, -0x441025, 0xae420080, 0x32c20180, 0x10400056, -0xae430020, 0x8f82005c, 0x3c030080, 0x431024, -0x1040000d, 0x0, 0x8f820050, 0xafa20010, -0x8f82005c, 0x240e0001, 0x3c040001, 0x24842f68, -0xa3ae003f, 0xafa20014, 0x8f870040, 0x24051900, -0xc002a03, 0x2c03021, 0x8f820050, 0x3c030010, -0x431024, 0x10400016, 0x0, 0x8c020218, -0x30420040, 0x1040000f, 0x24020001, 0x8f820050, -0x8c030218, 0x240e0001, 0x3c040001, 0x24842e90, -0xa3ae003f, 0xafa20010, 0xafa30014, 0x8f870040, -0x24052000, 0xc002a03, 0x2c03021, 0x10000004, -0x0, 0x3c010001, 0x370821, 0xa02240f4, -0x3c040001, 0x24842f74, 0x3c050001, 0x24a59b2c, -0x3c060001, 0x24c69bac, 0xc53023, 0x8f420008, -0x27b30030, 0x2603821, 0x27b10034, 0x34420e00, -0xaf420008, 0xc001750, 0xafb10010, 0x3c040001, -0x24842f8c, 0x3c050001, 0x24a5d180, 0x3c060001, -0x24c6dc78, 0xc53023, 0x2603821, 0xaf42010c, -0xc001750, 0xafb10010, 0x3c040001, 0x24842fa4, -0x3c050001, 0x24a5e25c, 0x3c060001, 0x24c6e948, -0xc53023, 0x2603821, 0x3c010001, 0xac223f50, -0xc001750, 0xafb10010, 0x3c040001, 0x24842fbc, -0x10000027, 0x24052100, 0x3c040001, 0x24842fc4, -0x3c050001, 0x24a599e8, 0x3c060001, 0x24c69b24, -0xc53023, 0x27b10030, 0x2203821, 0x27b30034, -0xc001750, 0xafb30010, 0x3c040001, 0x24842fd4, -0x3c050001, 0x24a5c3f0, 0x3c060001, 0x24c6d178, -0xc53023, 0x2203821, 0xaf42010c, 0xc001750, -0xafb30010, 0x3c040001, 0x24842fe4, 0x3c050001, -0x24a5e0fc, 0x3c060001, 0x24c6e254, 0xc53023, -0x2203821, 0x3c010001, 0xac223f50, 0xc001750, -0xafb30010, 0x3c040001, 0x24842ff8, 0x24052150, -0x2c03021, 0x3821, 0x3c010001, 0xac223f5c, -0xafa00010, 0xc002a03, 0xafa00014, 0x3c030001, -0x8c633f50, 0x3c110fff, 0x3631ffff, 0x3c020001, -0x8c423f5c, 0x3c1e0800, 0x711824, 0x31882, -0x7e1825, 0x511024, 0x21082, 0x5e1025, -0xae430038, 0xae420078, 0x8c020218, 0x30420040, -0x14400004, 0x24020001, 0x3c010001, 0x370821, -0xa02240f4, 0x3c040001, 0x24843004, 0x3c050001, -0x24a5dc80, 0x3c060001, 0x24c6dddc, 0xc53023, -0x27b50030, 0x2a03821, 0x27b30034, 0xc001750, -0xafb30010, 0x3c010001, 0xac223f48, 0x511024, -0x21082, 0x5e1025, 0xae420050, 0x32c22000, -0x10400005, 0x2a03821, 0x3c020000, 0x24425b78, -0x1000000d, 0x511024, 0x3c040001, 0x24843018, -0x3c050001, 0x24a5dde4, 0x3c060001, 0x24c6df94, -0xc53023, 0xc001750, 0xafb30010, 0x3c010001, -0xac223f60, 0x511024, 0x21082, 0x5e1025, -0xae420048, 0x32c24000, 0x10400005, 0x27a70030, -0x3c020000, 0x24425b78, 0x1000000e, 0x21100, -0x3c040001, 0x24843030, 0x3c050001, 0x24a5df9c, -0x3c060001, 0x24c6e0f4, 0xc53023, 0x27a20034, -0xc001750, 0xafa20010, 0x3c010001, 0xac223f54, -0x21100, 0x21182, 0x3c030800, 0x431025, -0xae420060, 0x3c040001, 0x24843048, 0x3c050000, -0x24a57ca0, 0x3c060001, 0x24c680c4, 0xc53023, -0x27b10030, 0x2203821, 0x27b30034, 0xc001750, -0xafb30010, 0x3c1e0fff, 0x37deffff, 0x3c040001, -0x24843054, 0x3c050000, 0x24a56318, 0x3c060000, -0x24c66478, 0xc53023, 0x2203821, 0x3c010001, -0xac223f28, 0x5e1024, 0x21082, 0x3c150800, -0x551025, 0xae4200b8, 0xc001750, 0xafb30010, -0x3c040001, 0x24843060, 0x3c050000, 0x24a56480, -0x3c060000, 0x24c666f8, 0xc53023, 0x2203821, -0x3c010001, 0xac223f1c, 0x5e1024, 0x21082, -0x551025, 0xae4200e8, 0xc001750, 0xafb30010, -0x3c040001, 0x24843078, 0x3c050000, 0x24a56700, -0x3c060000, 0x24c66830, 0xc53023, 0x2203821, -0x3c010001, 0xac223f14, 0x5e1024, 0x21082, -0x551025, 0xae4200c0, 0xc001750, 0xafb30010, -0x3c040001, 0x24843090, 0x3c050001, 0x24a5f300, -0x3c060001, 0x24c6f3d8, 0xc53023, 0x2203821, -0x3c010001, 0xac223f20, 0x5e1024, 0x21082, -0x551025, 0xae4200c8, 0xc001750, 0xafb30010, -0x3c040001, 0x2484309c, 0x3c050001, 0x24a5c2d0, -0x3c060001, 0x24c6c30c, 0xc53023, 0x2203821, -0xaf420110, 0xc001750, 0xafb30010, 0x3c040001, -0x248430ac, 0x3c050001, 0x24a5c314, 0x3c060001, -0x24c6c33c, 0xc53023, 0x2203821, 0xaf420114, -0xc001750, 0xafb30010, 0x3c040001, 0x248430b8, -0x3c050001, 0x24a5eaa0, 0x3c060001, 0x24c6ef78, -0xc53023, 0x2203821, 0xaf420118, 0xc001750, -0xafb30010, 0x3c010001, 0xac223f64, 0x5e1024, -0x21082, 0x551025, 0xc003dcf, 0xae4200d0, -0xc003a54, 0x0, 0xc002630, 0x0, -0xac000228, 0xac00022c, 0x96e20450, 0x2442ffff, -0xaf420038, 0x96e20460, 0xaf420080, 0x32c24000, -0x14400003, 0x0, 0x96e20480, 0xaf420084, -0x96e70490, 0x50e00001, 0x24070800, 0x24e2ffff, -0xaf420088, 0xaf42007c, 0x24020800, 0x10e2000f, -0x32c24000, 0x10400003, 0x24020400, 0x10e2000b, -0x0, 0x240e0001, 0x3c040001, 0x248430c8, -0xa3ae003f, 0x96e60490, 0x24052170, 0x2c03821, -0xafa00010, 0xc002a03, 0xafa00014, 0x8f43012c, -0x8f44012c, 0x24020001, 0xa34205b3, 0xaf430094, -0xaf440098, 0xafa00010, 0xafa00014, 0x8f460080, -0x8f470084, 0x3c040001, 0x248430d4, 0xc002a03, -0x24052200, 0xc00232c, 0x3c110800, 0x3c1433d8, -0x3694cb58, 0x3c020800, 0x34420080, 0x3c040001, -0x248430e0, 0x3c050000, 0x24a55bbc, 0x3c060000, -0x24c65bd8, 0xc53023, 0x27a70030, 0xaf820060, -0x2402ffff, 0xaf820064, 0x27a20034, 0xc001750, -0xafa20010, 0x3c010001, 0xac223f04, 0x21100, -0x21182, 0x511025, 0xc0018a8, 0xae420000, -0x8f820240, 0x3c030001, 0x431025, 0xaf820240, -0x3c020000, 0x24424034, 0xaf820244, 0xaf800240, -0x8f820060, 0x511024, 0x14400005, 0x3c030800, -0x8f820060, 0x431024, 0x1040fffd, 0x0, -0xc003a61, 0x8821, 0x3c020100, 0xafa20020, -0x8f530018, 0x240200ff, 0x56620001, 0x26710001, -0x8c020228, 0x1622000e, 0x1330c0, 0x8f42032c, -0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x3c040001, 0x24842da4, 0x3c050009, 0xafa00014, -0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, -0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, -0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c, -0x1021, 0x24070004, 0xafa70010, 0xafb10014, -0x8f48000c, 0x24c604c0, 0x2e63021, 0xafa80018, -0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, -0x822021, 0x100f809, 0x892021, 0x1440000b, -0x24070008, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x24842dac, 0x3c050009, 0xafa20014, -0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, -0x8f450154, 0x8f43000c, 0xaf510018, 0x8f860120, -0x24020010, 0xafa20010, 0xafb10014, 0xafa30018, -0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, -0x0, 0x8f420330, 0x24420001, 0xaf420330, -0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x24842db4, 0x3c050009, 0xafa20014, -0x8fa60020, 0x34a50300, 0xc002a03, 0x2603821, -0x8f4202d4, 0x24420001, 0xaf4202d4, 0x8f4202d4, -0x93a2003f, 0x10400069, 0x3c020700, 0x34423000, -0xafa20028, 0x8f530018, 0x240200ff, 0x12620002, -0x8821, 0x26710001, 0x8c020228, 0x1622000e, -0x1330c0, 0x8f42032c, 0x24420001, 0xaf42032c, -0x8f42032c, 0x8c020228, 0x3c040001, 0x24842da4, -0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60028, -0x1000003f, 0x34a50100, 0xd71021, 0x8fa30028, -0x8fa4002c, 0xac4304c0, 0xac4404c4, 0xc01821, -0x8f440168, 0x8f45016c, 0x1021, 0x24070004, -0xafa70010, 0xafb10014, 0x8f48000c, 0x24c604c0, -0x2e63021, 0xafa80018, 0x8f48010c, 0x24070008, -0xa32821, 0xa3482b, 0x822021, 0x100f809, -0x892021, 0x1440000b, 0x24070008, 0x8f820120, -0xafa20010, 0x8f820124, 0x3c040001, 0x24842dac, -0x3c050009, 0xafa20014, 0x8fa60028, 0x1000001c, -0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, -0xaf510018, 0x8f860120, 0x24020010, 0xafa20010, -0xafb10014, 0xafa30018, 0x8f42010c, 0x40f809, -0x24c6001c, 0x14400010, 0x0, 0x8f420330, -0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, -0xafa20010, 0x8f820124, 0x3c040001, 0x24842db4, -0x3c050009, 0xafa20014, 0x8fa60028, 0x34a50300, -0xc002a03, 0x2603821, 0x8f4202e0, 0x24420001, -0xaf4202e0, 0x8f4202e0, 0x3c040001, 0x248430f0, -0xafa00010, 0xafa00014, 0x8fa60028, 0x24052300, -0xc002a03, 0x3821, 0x10000004, 0x0, -0x8c020264, 0x10400005, 0x0, 0x8f8200a0, -0x30420004, 0x1440fffa, 0x0, 0x8f820044, -0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, -0xaf4202f8, 0x8f4202f8, 0x8f8200d8, 0x8f8300d4, -0x431023, 0x2442ff80, 0xaf420090, 0x8f420090, -0x2842ff81, 0x10400006, 0x24020001, 0x8f420090, -0x8f430138, 0x431021, 0xaf420090, 0x24020001, -0xaf42008c, 0x32c20008, 0x10400006, 0x0, -0x8f820214, 0x3c038100, 0x3042ffff, 0x431025, -0xaf820214, 0x3c020001, 0x8c423e24, 0x30420001, -0x10400009, 0x0, 0x3c040001, 0x248430fc, -0x3c050000, 0x24a56c40, 0x3c060000, 0x24c670e8, -0x10000008, 0xc53023, 0x3c040001, 0x2484310c, -0x3c050000, 0x24a56838, 0x3c060000, 0x24c66c38, -0xc53023, 0x27a70030, 0x27a20034, 0xc001750, -0xafa20010, 0x3c010001, 0xac223f18, 0x3c020001, -0x8c423f18, 0x3c030800, 0x21100, 0x21182, -0x431025, 0xae420040, 0x8f8200a0, 0xafa20010, -0x8f8200b0, 0xafa20014, 0x8f86005c, 0x8f87011c, -0x3c040001, 0x2484311c, 0x3c010001, 0xac363ef0, -0x3c010001, 0xac203ee0, 0x3c010001, 0xac3c3ed8, -0x3c010001, 0xac3b3f08, 0x3c010001, 0xac373f0c, -0x3c010001, 0xac3a3eec, 0xc002a03, 0x24052400, -0x8f820200, 0xafa20010, 0x8f820220, 0xafa20014, -0x8f860044, 0x8f870050, 0x3c040001, 0x24843128, -0xc002a03, 0x24052500, 0x8f830060, 0x74100b, -0x242000a, 0x200f821, 0x0, 0xd, -0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, -0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, -0x27bd0060, 0x27bdffe0, 0x3c040001, 0x24843134, -0x24052600, 0x3021, 0x3821, 0xafbf0018, -0xafa00010, 0xc002a03, 0xafa00014, 0x8fbf0018, -0x3e00008, 0x27bd0020, 0x3e00008, 0x0, -0x3e00008, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x3e00008, -0x0, 0x3e00008, 0x0, 0x27bdfde0, -0x27a50018, 0x3c04dead, 0x3484beef, 0xafbf0218, -0x8f820150, 0x3c03001f, 0x3463ffff, 0xafa40018, -0xa22823, 0xa32824, 0x8ca20000, 0x1044000a, -0x0, 0xafa50010, 0x8ca20000, 0xafa20014, -0x8f860150, 0x8f870250, 0x3c040001, 0x2484313c, -0xc002a03, 0x24052700, 0x8fbf0218, 0x3e00008, -0x27bd0220, 0x27bdffe0, 0x3c06abba, 0x34c6babe, -0xafb00018, 0x3c100004, 0x3c07007f, 0x34e7ffff, -0xafbf001c, 0x102840, 0x8e040000, 0x8ca30000, -0xaca00000, 0xae060000, 0x8ca20000, 0xaca30000, -0x10460005, 0xae040000, 0xa08021, 0xf0102b, -0x1040fff5, 0x102840, 0x3c040001, 0x24843148, -0x24052800, 0x2003021, 0x3821, 0xafa00010, -0xc002a03, 0xafa00014, 0x2001021, 0x8fbf001c, -0x8fb00018, 0x3e00008, 0x27bd0020, 0x8c020224, -0x3047003f, 0x10e00010, 0x803021, 0x2821, -0x24030020, 0xe31024, 0x10400002, 0x63042, -0xa62821, 0x31842, 0x1460fffb, 0xe31024, -0x2402f000, 0xa22824, 0x3403ffff, 0x65102b, -0x14400003, 0x851023, 0x10000006, 0x3c020001, -0x62102b, 0x14400003, 0xa01021, 0x3c02ffff, -0x821021, 0x3e00008, 0x0, 0x27bdffd0, -0xafb50028, 0x8fb50040, 0xafb20020, 0xa09021, -0xafb1001c, 0x24c60003, 0xafbf002c, 0xafb30024, -0xafb00018, 0x8ea20000, 0x2403fffc, 0xc38024, -0x50102b, 0x1440001b, 0xe08821, 0x8e330000, -0xafb00010, 0x8ea20000, 0xafa20014, 0x8e270000, -0x24053000, 0xc002a03, 0x2403021, 0x8e230000, -0x702021, 0x64102b, 0x10400007, 0x2402821, -0x8ca20000, 0xac620000, 0x24630004, 0x64102b, -0x1440fffb, 0x24a50004, 0x8ea20000, 0x501023, -0xaea20000, 0x8e220000, 0x501021, 0x1000000b, -0xae220000, 0x2402002d, 0xa0820000, 0xafb00010, -0x8ea20000, 0x2409821, 0xafa20014, 0x8e270000, -0x24053100, 0xc002a03, 0x2603021, 0x2601021, -0x8fbf002c, 0x8fb50028, 0x8fb30024, 0x8fb20020, -0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, -0x27bdffe8, 0x3c1cc000, 0x3c05fffe, 0x3c030001, -0x8c633ed0, 0x3c040001, 0x8c843edc, 0x34a5bf08, -0x24021ffc, 0x3c010001, 0xac223d70, 0x3c0200c0, -0x3c010001, 0xac223d74, 0x3c020020, 0xafbf0010, -0x3c0100c0, 0xac201ffc, 0x431023, 0x441023, -0x245bb000, 0x365b821, 0x3c1d0001, 0x8fbd3d6c, -0x3a0f021, 0x3c0400c0, 0x34840200, 0x3c1a00c0, -0x3c0300c0, 0x346307b8, 0x24021dfc, 0x3c010001, -0xac223d70, 0x24021844, 0x3c010001, 0xac243d74, -0x3c010001, 0xac223d70, 0x3c010001, 0xac233d74, -0xc0017ba, 0x375a0200, 0x8fbf0010, 0x3e00008, -0x27bd0018, 0x27bdffc8, 0x3c040001, 0x24843154, -0x24053200, 0x3c020001, 0x8c423d70, 0x3c030001, -0x8c633d74, 0x3021, 0x3603821, 0xafbf0030, -0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, -0xafa2001c, 0xafa30018, 0xafb70010, 0xc002a03, -0xafba0014, 0xc0018c2, 0x0, 0x8f820240, -0x34420004, 0xaf820240, 0x24020001, 0xaf420000, -0x3c020001, 0x571021, 0x904240f4, 0x10400092, -0x2403fffc, 0x3c100001, 0x2610a79b, 0x3c120001, -0x2652a374, 0x2121023, 0x438024, 0x8fa3001c, -0x3c040001, 0x24843160, 0x70102b, 0x1440001a, -0x27b30018, 0x8fb10018, 0x24053000, 0x2403021, -0xafb00010, 0xafa30014, 0xc002a03, 0x2203821, -0x8fa30018, 0x702021, 0x64102b, 0x10400007, -0x2403021, 0x8cc20000, 0xac620000, 0x24630004, -0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c, -0x501023, 0xafa2001c, 0x8e620000, 0x501021, -0x1000000a, 0xae620000, 0x2408821, 0x24053100, -0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021, -0x2402002d, 0xc002a03, 0xa0820000, 0x24070020, -0x8fa3001c, 0x3c040001, 0x2484317c, 0x24120020, -0x3c010001, 0xac313efc, 0x2c620020, 0x1440001d, -0x27b10018, 0x8fb00018, 0x24053000, 0x3c060001, -0x24c63f90, 0xafa70010, 0xafa30014, 0xc002a03, -0x2003821, 0x8fa30018, 0x3c040001, 0x24843f90, -0x24650020, 0x65102b, 0x10400007, 0x0, -0x8c820000, 0xac620000, 0x24630004, 0x65102b, -0x1440fffb, 0x24840004, 0x8fa2001c, 0x521023, -0xafa2001c, 0x8e220000, 0x521021, 0x1000000b, -0xae220000, 0x3c100001, 0x26103f90, 0x24053100, -0xafa70010, 0xafa30014, 0x8fa70018, 0x2003021, -0x2402002d, 0xc002a03, 0xa0820000, 0x24070020, -0x3c040001, 0x24843190, 0x8fa3001c, 0x24120020, -0x3c010001, 0xac303f30, 0x2c620020, 0x1440001d, -0x27b10018, 0x8fb00018, 0x24053000, 0x3c060001, -0x24c63fb0, 0xafa70010, 0xafa30014, 0xc002a03, -0x2003821, 0x8fa30018, 0x3c040001, 0x24843fb0, -0x24650020, 0x65102b, 0x10400007, 0x0, -0x8c820000, 0xac620000, 0x24630004, 0x65102b, -0x1440fffb, 0x24840004, 0x8fa2001c, 0x521023, -0xafa2001c, 0x8e220000, 0x521021, 0x1000000b, -0xae220000, 0x3c100001, 0x26103fb0, 0x24053100, -0xafa70010, 0xafa30014, 0x8fa70018, 0x2003021, -0x2402002d, 0xc002a03, 0xa0820000, 0x3c010001, -0x10000031, 0xac303f2c, 0x3c100000, 0x26107c8f, -0x3c120000, 0x26527b0c, 0x2121023, 0x438024, -0x8fa3001c, 0x3c040001, 0x248431a4, 0x70102b, +0x24842ed4, 0x3c050001, 0x24a52ba0, 0x3c060001, +0x24c62c18, 0xc53023, 0x8f420008, 0x27b30030, +0x2603821, 0x27b10034, 0x34420e00, 0xaf420008, +0xc001751, 0xafb10010, 0x3c040001, 0x24842eec, +0x3c050001, 0x24a5cffc, 0x3c060001, 0x24c6db04, +0xc53023, 0x2603821, 0xaf42010c, 0xc001751, +0xafb10010, 0x3c040001, 0x24842f04, 0x3c050001, +0x24a5df84, 0x3c060001, 0x24c6e6bc, 0xc53023, +0x2603821, 0x3c010001, 0xac223eb0, 0xc001751, +0xafb10010, 0x3c040001, 0x24842f1c, 0x10000027, +0x24052100, 0x3c040001, 0x24842f24, 0x3c050001, +0x24a599c8, 0x3c060001, 0x24c69b04, 0xc53023, +0x27b10030, 0x2203821, 0x27b30034, 0xc001751, +0xafb30010, 0x3c040001, 0x24842f34, 0x3c050001, +0x24a5c25c, 0x3c060001, 0x24c6cff4, 0xc53023, +0x2203821, 0xaf42010c, 0xc001751, 0xafb30010, +0x3c040001, 0x24842f44, 0x3c050001, 0x24a5de24, +0x3c060001, 0x24c6df7c, 0xc53023, 0x2203821, +0x3c010001, 0xac223eb0, 0xc001751, 0xafb30010, +0x3c040001, 0x24842f58, 0x24052150, 0x2c03021, +0x3821, 0x3c010001, 0xac223ebc, 0xafa00010, +0xc0029bb, 0xafa00014, 0x3c030001, 0x8c633eb0, +0x3c110fff, 0x3631ffff, 0x3c020001, 0x8c423ebc, +0x3c1e0800, 0x711824, 0x31882, 0x7e1825, +0x511024, 0x21082, 0x5e1025, 0xae430038, +0xae420078, 0x8c020218, 0x30420040, 0x14400004, +0x24020001, 0x3c010001, 0x370821, 0xa02240f4, +0x3c040001, 0x24842f64, 0x3c050001, 0x24a52ab4, +0x3c060001, 0x24c62b90, 0xc53023, 0x27b50030, +0x2a03821, 0x27b30034, 0xc001751, 0xafb30010, +0x3c010001, 0xac223ea8, 0x511024, 0x21082, +0x5e1025, 0xae420050, 0x32c22000, 0x10400005, +0x2a03821, 0x3c020000, 0x24425b74, 0x1000000d, +0x511024, 0x3c040001, 0x24842f78, 0x3c050001, +0x24a5db0c, 0x3c060001, 0x24c6dcbc, 0xc53023, +0xc001751, 0xafb30010, 0x3c010001, 0xac223ec0, +0x511024, 0x21082, 0x5e1025, 0xae420048, +0x32c24000, 0x10400005, 0x27a70030, 0x3c020000, +0x24425b74, 0x1000000e, 0x21100, 0x3c040001, +0x24842f90, 0x3c050001, 0x24a5dcc4, 0x3c060001, +0x24c6de1c, 0xc53023, 0x27a20034, 0xc001751, +0xafa20010, 0x3c010001, 0xac223eb4, 0x21100, +0x21182, 0x3c030800, 0x431025, 0xae420060, +0x3c040001, 0x24842fa8, 0x3c050000, 0x24a57c80, +0x3c060001, 0x24c680a4, 0xc53023, 0x27b10030, +0x2203821, 0x27b30034, 0xc001751, 0xafb30010, +0x3c1e0fff, 0x37deffff, 0x3c040001, 0x24842fb4, +0x3c050000, 0x24a56318, 0x3c060000, 0x24c6645c, +0xc53023, 0x2203821, 0x3c010001, 0xac223e88, +0x5e1024, 0x21082, 0x3c150800, 0x551025, +0xae4200b8, 0xc001751, 0xafb30010, 0x3c040001, +0x24842fc0, 0x3c050000, 0x24a56464, 0x3c060000, +0x24c666dc, 0xc53023, 0x2203821, 0x3c010001, +0xac223e7c, 0x5e1024, 0x21082, 0x551025, +0xae4200e8, 0xc001751, 0xafb30010, 0x3c040001, +0x24842fd8, 0x3c050000, 0x24a566e4, 0x3c060000, +0x24c66814, 0xc53023, 0x2203821, 0x3c010001, +0xac223e74, 0x5e1024, 0x21082, 0x551025, +0xae4200c0, 0xc001751, 0xafb30010, 0x3c040001, +0x24842ff0, 0x3c050001, 0x24a5efb0, 0x3c060001, +0x24c6f088, 0xc53023, 0x2203821, 0x3c010001, +0xac223e80, 0x5e1024, 0x21082, 0x551025, +0xae4200c8, 0xc001751, 0xafb30010, 0x3c040001, +0x24842ffc, 0x3c050001, 0x24a529f0, 0x3c060001, +0x24c62a78, 0xc53023, 0x2203821, 0xaf420110, +0xc001751, 0xafb30010, 0x3c040001, 0x2484300c, +0x3c050001, 0x24a52a80, 0x3c060001, 0x24c62aac, +0xc53023, 0x2203821, 0xaf420114, 0xc001751, +0xafb30010, 0x3c040001, 0x24843018, 0x3c050001, +0x24a5e820, 0x3c060001, 0x24c6ec24, 0xc53023, +0x2203821, 0xaf420118, 0xc001751, 0xafb30010, +0x3c010001, 0xac223ec4, 0x5e1024, 0x21082, +0x551025, 0xc003cfb, 0xae4200d0, 0xc0039b4, +0x0, 0xc002628, 0x0, 0xac000228, +0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038, +0x96e20460, 0xaf420080, 0x32c24000, 0x14400003, +0x0, 0x96e20480, 0xaf420084, 0x96e70490, +0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088, +0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000, +0x10400003, 0x24020400, 0x10e2000b, 0x0, +0x240e0001, 0x3c040001, 0x24843028, 0xa3ae003f, +0x96e60490, 0x24052170, 0x2c03821, 0xafa00010, +0xc0029bb, 0xafa00014, 0x8f43012c, 0x8f44012c, +0x24020001, 0xa34205b3, 0xaf430094, 0xaf440098, +0xafa00010, 0xafa00014, 0x8f460080, 0x8f470084, +0x3c040001, 0x24843034, 0xc0029bb, 0x24052200, +0xc002324, 0x3c110800, 0x3c1433d8, 0x3694cb58, +0x3c020800, 0x34420080, 0x3c040001, 0x24843040, +0x3c050000, 0x24a55bb8, 0x3c060000, 0x24c65bd4, +0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff, +0xaf820064, 0x27a20034, 0xc001751, 0xafa20010, +0x3c010001, 0xac223e64, 0x21100, 0x21182, +0x511025, 0xc0018a8, 0xae420000, 0x8f820240, +0x3c030001, 0x431025, 0xaf820240, 0x3c020000, +0x24424034, 0xaf820244, 0xaf800240, 0x8f820060, +0x511024, 0x14400005, 0x3c030800, 0x8f820060, +0x431024, 0x1040fffd, 0x0, 0xc0039c1, +0x8821, 0x3c020100, 0xafa20020, 0x8f530018, +0x240200ff, 0x56620001, 0x26710001, 0x8c020228, +0x1622000e, 0x1330c0, 0x8f42032c, 0x24420001, +0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, +0x24842d04, 0x3c050009, 0xafa00014, 0xafa20010, +0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, +0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, +0xc01821, 0x8f440168, 0x8f45016c, 0x1021, +0x24070004, 0xafa70010, 0xafb10014, 0x8f48000c, +0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c, +0x24070008, 0xa32821, 0xa3482b, 0x822021, +0x100f809, 0x892021, 0x1440000b, 0x24070008, +0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001, +0x24842d0c, 0x3c050009, 0xafa20014, 0x8fa60020, +0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, +0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010, +0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c, +0x40f809, 0x24c6001c, 0x14400010, 0x0, +0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, +0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001, +0x24842d14, 0x3c050009, 0xafa20014, 0x8fa60020, +0x34a50300, 0xc0029bb, 0x2603821, 0x8f4202d4, +0x24420001, 0xaf4202d4, 0x8f4202d4, 0x93a2003f, +0x10400069, 0x3c020700, 0x34423000, 0xafa20028, +0x8f530018, 0x240200ff, 0x12620002, 0x8821, +0x26710001, 0x8c020228, 0x1622000e, 0x1330c0, +0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, +0x8c020228, 0x3c040001, 0x24842d04, 0x3c050009, +0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f, +0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c, +0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, +0x8f45016c, 0x1021, 0x24070004, 0xafa70010, +0xafb10014, 0x8f48000c, 0x24c604c0, 0x2e63021, +0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, +0xa3482b, 0x822021, 0x100f809, 0x892021, +0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, +0x8f820124, 0x3c040001, 0x24842d0c, 0x3c050009, +0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200, +0x8f440150, 0x8f450154, 0x8f43000c, 0xaf510018, +0x8f860120, 0x24020010, 0xafa20010, 0xafb10014, +0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, +0x14400010, 0x0, 0x8f420330, 0x24420001, +0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, +0x8f820124, 0x3c040001, 0x24842d14, 0x3c050009, +0xafa20014, 0x8fa60028, 0x34a50300, 0xc0029bb, +0x2603821, 0x8f4202e0, 0x24420001, 0xaf4202e0, +0x8f4202e0, 0x3c040001, 0x24843050, 0xafa00010, +0xafa00014, 0x8fa60028, 0x24052300, 0xc0029bb, +0x3821, 0x10000004, 0x0, 0x8c020264, +0x10400005, 0x0, 0x8f8200a0, 0x30420004, +0x1440fffa, 0x0, 0x8f820044, 0x34420004, +0xaf820044, 0x8f4202f8, 0x24420001, 0xaf4202f8, +0x8f4202f8, 0x8f8200d8, 0x8f8300d4, 0x431023, +0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81, +0x10400006, 0x24020001, 0x8f420090, 0x8f430138, +0x431021, 0xaf420090, 0x24020001, 0xaf42008c, +0x32c20008, 0x10400006, 0x0, 0x8f820214, +0x3c038100, 0x3042ffff, 0x431025, 0xaf820214, +0x3c020001, 0x8c423d84, 0x30420001, 0x10400009, +0x0, 0x3c040001, 0x2484305c, 0x3c050000, +0x24a56c24, 0x3c060000, 0x24c670cc, 0x10000008, +0xc53023, 0x3c040001, 0x2484306c, 0x3c050000, +0x24a5681c, 0x3c060000, 0x24c66c1c, 0xc53023, +0x27a70030, 0x27a20034, 0xc001751, 0xafa20010, +0x3c010001, 0xac223e78, 0x3c020001, 0x8c423e78, +0x3c030800, 0x21100, 0x21182, 0x431025, +0xae420040, 0x8f8200a0, 0xafa20010, 0x8f8200b0, +0xafa20014, 0x8f86005c, 0x8f87011c, 0x3c040001, +0x2484307c, 0x3c010001, 0xac363e50, 0x3c010001, +0xac203e40, 0x3c010001, 0xac3c3e38, 0x3c010001, +0xac3b3e68, 0x3c010001, 0xac373e6c, 0x3c010001, +0xac3a3e4c, 0xc0029bb, 0x24052400, 0x8f820200, +0xafa20010, 0x8f820220, 0xafa20014, 0x8f860044, +0x8f870050, 0x3c040001, 0x24843088, 0xc0029bb, +0x24052500, 0x8f830060, 0x74100b, 0x242000a, +0x200f821, 0x0, 0xd, 0x8fbf0058, +0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, +0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060, +0x27bdffe0, 0x3c040001, 0x24843094, 0x24052600, +0x3021, 0x3821, 0xafbf0018, 0xafa00010, +0xc0029bb, 0xafa00014, 0x8fbf0018, 0x3e00008, +0x27bd0020, 0x3e00008, 0x0, 0x3e00008, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x3e00008, 0x0, +0x3e00008, 0x0, 0x27bdfde0, 0x27a50018, +0x3c04dead, 0x3484beef, 0xafbf0218, 0x8f820150, +0x3c03001f, 0x3463ffff, 0xafa40018, 0xa22823, +0xa32824, 0x8ca20000, 0x1044000a, 0x0, +0xafa50010, 0x8ca20000, 0xafa20014, 0x8f860150, +0x8f870250, 0x3c040001, 0x2484309c, 0xc0029bb, +0x24052700, 0x8fbf0218, 0x3e00008, 0x27bd0220, +0x27bdffe0, 0x3c06abba, 0x34c6babe, 0xafb00018, +0x3c100004, 0x3c07007f, 0x34e7ffff, 0xafbf001c, +0x102840, 0x8e040000, 0x8ca30000, 0xaca00000, +0xae060000, 0x8ca20000, 0xaca30000, 0x10460005, +0xae040000, 0xa08021, 0xf0102b, 0x1040fff5, +0x102840, 0x3c040001, 0x248430a8, 0x24052800, +0x2003021, 0x3821, 0xafa00010, 0xc0029bb, +0xafa00014, 0x2001021, 0x8fbf001c, 0x8fb00018, +0x3e00008, 0x27bd0020, 0x8c020224, 0x3047003f, +0x10e00010, 0x803021, 0x2821, 0x24030020, +0xe31024, 0x10400002, 0x63042, 0xa62821, +0x31842, 0x1460fffb, 0xe31024, 0x2402f000, +0xa22824, 0x3402ffff, 0x45102b, 0x14400003, +0x3c020001, 0x10000008, 0x3c020001, 0x3442ffff, +0x851823, 0x43102b, 0x14400003, 0xa01021, +0x3c02fffe, 0x821021, 0x3e00008, 0x0, +0x27bdffd0, 0xafb50028, 0x8fb50040, 0xafb20020, +0xa09021, 0xafb1001c, 0x24c60003, 0xafbf002c, +0xafb30024, 0xafb00018, 0x8ea20000, 0x2403fffc, +0xc38024, 0x50102b, 0x1440001b, 0xe08821, +0x8e330000, 0xafb00010, 0x8ea20000, 0xafa20014, +0x8e270000, 0x24053000, 0xc0029bb, 0x2403021, +0x8e230000, 0x702021, 0x64102b, 0x10400007, +0x2402821, 0x8ca20000, 0xac620000, 0x24630004, +0x64102b, 0x1440fffb, 0x24a50004, 0x8ea20000, +0x501023, 0xaea20000, 0x8e220000, 0x501021, +0x1000000b, 0xae220000, 0x2402002d, 0xa0820000, +0xafb00010, 0x8ea20000, 0x2409821, 0xafa20014, +0x8e270000, 0x24053100, 0xc0029bb, 0x2603021, +0x2601021, 0x8fbf002c, 0x8fb50028, 0x8fb30024, +0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, +0x27bd0030, 0x27bdffe8, 0x3c1cc000, 0x3c05fffe, +0x3c030001, 0x8c633e30, 0x3c040001, 0x8c843e3c, +0x34a5bf08, 0x24021ffc, 0x3c010001, 0xac223cd0, +0x3c0200c0, 0x3c010001, 0xac223cd4, 0x3c020020, +0xafbf0010, 0x3c0100c0, 0xac201ffc, 0x431023, +0x441023, 0x245bb000, 0x365b821, 0x3c1d0001, +0x8fbd3ccc, 0x3a0f021, 0x3c0400c0, 0x34840200, +0x3c1a00c0, 0x3c0300c0, 0x346307b8, 0x24021dfc, +0x3c010001, 0xac223cd0, 0x24021844, 0x3c010001, +0xac243cd4, 0x3c010001, 0xac223cd0, 0x3c010001, +0xac233cd4, 0xc0017bb, 0x375a0200, 0x8fbf0010, +0x3e00008, 0x27bd0018, 0x27bdffc8, 0x3c040001, +0x248430b4, 0x24053200, 0x3c020001, 0x8c423cd0, +0x3c030001, 0x8c633cd4, 0x3021, 0x3603821, +0xafbf0030, 0xafb3002c, 0xafb20028, 0xafb10024, +0xafb00020, 0xafa2001c, 0xafa30018, 0xafb70010, +0xc0029bb, 0xafba0014, 0xc0018c2, 0x0, +0x8f820240, 0x34420004, 0xaf820240, 0x24020001, +0xaf420000, 0x3c020001, 0x571021, 0x904240f4, +0x10400092, 0x2403fffc, 0x3c100001, 0x2610a673, +0x3c120001, 0x2652a24c, 0x2121023, 0x438024, +0x8fa3001c, 0x3c040001, 0x248430c0, 0x70102b, 0x1440001a, 0x27b30018, 0x8fb10018, 0x24053000, -0x2403021, 0xafb00010, 0xafa30014, 0xc002a03, +0x2403021, 0xafb00010, 0xafa30014, 0xc0029bb, 0x2203821, 0x8fa30018, 0x702021, 0x64102b, 0x10400007, 0x2403021, 0x8cc20000, 0xac620000, 0x24630004, 0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023, 0xafa2001c, 0x8e620000, 0x501021, 0x1000000a, 0xae620000, 0x2408821, 0x24053100, 0xafb00010, 0xafa30014, 0x8fa70018, -0x2203021, 0x2402002d, 0xc002a03, 0xa0820000, -0x3c010001, 0xac313efc, 0x3c030001, 0x8c633efc, -0x24020400, 0x60f809, 0xaf820070, 0x8fbf0030, -0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, -0x3e00008, 0x27bd0038, 0x0, 0x8f820040, +0x2203021, 0x2402002d, 0xc0029bb, 0xa0820000, +0x24070020, 0x8fa3001c, 0x3c040001, 0x248430dc, +0x24120020, 0x3c010001, 0xac313e5c, 0x2c620020, +0x1440001d, 0x27b10018, 0x8fb00018, 0x24053000, +0x3c060001, 0x24c63ef0, 0xafa70010, 0xafa30014, +0xc0029bb, 0x2003821, 0x8fa30018, 0x3c040001, +0x24843ef0, 0x24650020, 0x65102b, 0x10400007, +0x0, 0x8c820000, 0xac620000, 0x24630004, +0x65102b, 0x1440fffb, 0x24840004, 0x8fa2001c, +0x521023, 0xafa2001c, 0x8e220000, 0x521021, +0x1000000b, 0xae220000, 0x3c100001, 0x26103ef0, +0x24053100, 0xafa70010, 0xafa30014, 0x8fa70018, +0x2003021, 0x2402002d, 0xc0029bb, 0xa0820000, +0x24070020, 0x3c040001, 0x248430f0, 0x8fa3001c, +0x24120020, 0x3c010001, 0xac303e90, 0x2c620020, +0x1440001d, 0x27b10018, 0x8fb00018, 0x24053000, +0x3c060001, 0x24c63f10, 0xafa70010, 0xafa30014, +0xc0029bb, 0x2003821, 0x8fa30018, 0x3c040001, +0x24843f10, 0x24650020, 0x65102b, 0x10400007, +0x0, 0x8c820000, 0xac620000, 0x24630004, +0x65102b, 0x1440fffb, 0x24840004, 0x8fa2001c, +0x521023, 0xafa2001c, 0x8e220000, 0x521021, +0x1000000b, 0xae220000, 0x3c100001, 0x26103f10, +0x24053100, 0xafa70010, 0xafa30014, 0x8fa70018, +0x2003021, 0x2402002d, 0xc0029bb, 0xa0820000, +0x3c010001, 0x10000031, 0xac303e8c, 0x3c100000, +0x26107c73, 0x3c120000, 0x26527af0, 0x2121023, +0x438024, 0x8fa3001c, 0x3c040001, 0x24843104, +0x70102b, 0x1440001a, 0x27b30018, 0x8fb10018, +0x24053000, 0x2403021, 0xafb00010, 0xafa30014, +0xc0029bb, 0x2203821, 0x8fa30018, 0x702021, +0x64102b, 0x10400007, 0x2403021, 0x8cc20000, +0xac620000, 0x24630004, 0x64102b, 0x1440fffb, +0x24c60004, 0x8fa2001c, 0x501023, 0xafa2001c, +0x8e620000, 0x501021, 0x1000000a, 0xae620000, +0x2408821, 0x24053100, 0xafb00010, 0xafa30014, +0x8fa70018, 0x2203021, 0x2402002d, 0xc0029bb, +0xa0820000, 0x3c010001, 0xac313e5c, 0x3c030001, +0x8c633e5c, 0x24020400, 0x60f809, 0xaf820070, +0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, +0x8fb00020, 0x3e00008, 0x27bd0038, 0x8f820040, 0x3c03f000, 0x431024, 0x3c036000, 0x14430006, 0x0, 0x8f820050, 0x2403ff80, 0x431024, 0x34420055, 0xaf820050, 0x8f820054, 0x244203e8, @@ -5033,164 +5043,274 @@ 0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054, 0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024, 0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024, -0x36940040, 0x3c020001, 0x8c423e38, 0x10400027, -0x0, 0x3c020001, 0x8c423e24, 0x30420001, -0x14400010, 0x0, 0x3c020001, 0x8c423f68, -0x1040000c, 0x0, 0x3c020001, 0x8c423eb4, -0x14400008, 0x0, 0x8f830224, 0x3c020001, -0x8c42602c, 0x10620003, 0x0, 0xc003be0, -0x0, 0x934205b1, 0x10400012, 0x24020001, -0x934305b1, 0x14620004, 0x3c0208ff, 0x24020002, -0x1000000c, 0xa34205b1, 0x3442fffb, 0xa34005b1, -0x8f830220, 0x3c040200, 0x284a025, 0x621824, -0xaf830220, 0x10000004, 0x3c020200, 0xc003f57, -0x0, 0x3c020200, 0x2c21024, 0x10400003, -0x0, 0xc001de7, 0x0, 0x8f4200d8, -0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b, -0x14400003, 0x0, 0xaf4000d8, 0x36940080, -0x8c030238, 0x1060000c, 0x0, 0x8f4201a0, -0x244203e8, 0xaf4201a0, 0x43102b, 0x14400006, -0x0, 0x934205b6, 0x14400003, 0x0, -0xc001c3c, 0x0, 0x8fbf0010, 0x3e00008, -0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8, -0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059, -0x0, 0x3c020001, 0x571021, 0x904240f0, -0x10400026, 0x24070008, 0x8f440160, 0x8f450164, -0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010, -0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, -0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, -0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x24843248, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, -0x34a50900, 0x1000005c, 0x0, 0x8f4202f0, -0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, -0xa34005b2, 0x10000027, 0xaf420038, 0x8f440160, -0x8f450164, 0x8f43002c, 0x8f48000c, 0x8f860120, -0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, -0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, -0x24020001, 0x3c010001, 0x370821, 0xa02240f1, -0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, -0x24843254, 0xafa20014, 0x8f46002c, 0x8f870120, -0x3c050009, 0xc002a03, 0x34a51100, 0x10000036, -0x0, 0x8f4202f0, 0x8f43002c, 0x24420001, -0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, -0xaf430038, 0x3c010001, 0x370821, 0xa02040f1, -0x3c010001, 0x370821, 0xa02040f0, 0x10000026, -0xaf400034, 0x934205b2, 0x1040001d, 0x0, -0xa34005b2, 0x8f820040, 0x30420001, 0x14400008, -0x2021, 0x8c030104, 0x24020001, 0x50620005, -0x24040001, 0x8c020264, 0x10400003, 0x801021, -0x24040001, 0x801021, 0x10400006, 0x0, -0x8f4202fc, 0x24420001, 0xaf4202fc, 0x10000008, -0x8f4202fc, 0x8f820044, 0x34420004, 0xaf820044, -0x8f4202f8, 0x24420001, 0xaf4202f8, 0x8f4202f8, -0x3c010001, 0x370821, 0xa02040f0, 0x3c010001, -0x370821, 0xa02040f1, 0x8f420000, 0x10400007, -0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, -0x0, 0x10000005, 0x0, 0xaf800048, -0x8f820048, 0x1040fffd, 0x0, 0x8f820060, -0x3c03ff7f, 0x3463ffff, 0x431024, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x10000002, -0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008, -0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8, -0xafbf0020, 0x8f430044, 0x8f42007c, 0x10620029, -0x24070008, 0x8f440158, 0x8f45015c, 0x8f48000c, -0x8f860120, 0x24020040, 0xafa20010, 0xafa30014, +0x36940040, 0x3c020001, 0x8c423d98, 0x10400020, +0x3c020200, 0x934305b1, 0x10600007, 0x282a025, +0xa34005b1, 0x8f820220, 0x3c0308ff, 0x3463fffb, +0x431024, 0xaf820220, 0x3c020001, 0x8c423ec8, +0x10400016, 0x3c020200, 0x3c020001, 0x8c423e14, +0x14400012, 0x3c020200, 0x3c020001, 0x8c423d84, +0x30420001, 0x1440000d, 0x3c020200, 0x8f830224, +0x3c020001, 0x8c425f8c, 0x10620008, 0x3c020200, +0xc003b0b, 0x0, 0x10000004, 0x3c020200, +0xc003e84, 0x0, 0x3c020200, 0x2c21024, +0x10400003, 0x0, 0xc001de0, 0x0, +0x8f4200d8, 0x8f4300dc, 0x24420001, 0xaf4200d8, +0x43102b, 0x14400003, 0x0, 0xaf4000d8, +0x36940080, 0x8c030238, 0x1060000c, 0x0, +0x8f4201a0, 0x244203e8, 0xaf4201a0, 0x43102b, +0x14400006, 0x0, 0x934205b6, 0x14400003, +0x0, 0xc001c35, 0x0, 0x8fbf0010, +0x3e00008, 0x27bd0018, 0x3e00008, 0x0, +0x27bdffd8, 0xafbf0020, 0x8f43002c, 0x8f420038, +0x10620059, 0x0, 0x3c020001, 0x571021, +0x904240f0, 0x10400026, 0x24070008, 0x8f440160, +0x8f450164, 0x8f48000c, 0x8f860120, 0x24020020, +0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, +0x40f809, 0x24c6001c, 0x14400011, 0x24020001, +0x3c010001, 0x370821, 0xa02240f0, 0x8f820124, +0xafa20010, 0x8f820128, 0x3c040001, 0x248431a8, +0xafa20014, 0x8f46002c, 0x8f870120, 0x3c050009, +0xc0029bb, 0x34a50900, 0x1000005c, 0x0, +0x8f4202f0, 0x24420001, 0xaf4202f0, 0x8f4202f0, +0x8f42002c, 0xa34005b2, 0x10000027, 0xaf420038, +0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c, +0x8f860120, 0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, -0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x2484325c, 0xafa20014, 0x8f460044, -0x8f870120, 0x3c050009, 0xc002a03, 0x34a51300, -0x1000000f, 0x0, 0x8f4202f4, 0x24420001, -0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, -0x3c010001, 0x370821, 0xa02040f2, 0x10000004, -0xaf400078, 0x3c010001, 0x370821, 0xa02040f2, -0x8f420000, 0x10400007, 0x0, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x3c03feff, 0x3463ffff, -0x431024, 0xaf820060, 0x8f420000, 0x10400003, -0x0, 0x10000002, 0xaf80004c, 0xaf800048, -0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008, -0x0, 0x3c020001, 0x8c423e38, 0x27bdffa8, -0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, -0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5, -0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b, -0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002, -0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001, -0x8c633e28, 0x34420002, 0xaf420004, 0x24020001, -0x14620003, 0x3c020600, 0x10000002, 0x34423000, -0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034, -0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff, -0x11420002, 0x1821, 0x25430001, 0x8c020228, -0x609821, 0x1662000e, 0x3c050009, 0x8f42032c, -0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x8fa70034, 0x3c040001, 0x2484322c, 0xafa00014, -0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500, -0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020, -0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, +0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128, +0x3c040001, 0x248431b4, 0xafa20014, 0x8f46002c, +0x8f870120, 0x3c050009, 0xc0029bb, 0x34a51100, +0x10000036, 0x0, 0x8f4202f0, 0x8f43002c, +0x24420001, 0xaf4202f0, 0x8f4202f0, 0x24020001, +0xa34205b2, 0xaf430038, 0x3c010001, 0x370821, +0xa02040f1, 0x3c010001, 0x370821, 0xa02040f0, +0x10000026, 0xaf400034, 0x934205b2, 0x1040001d, +0x0, 0xa34005b2, 0x8f820040, 0x30420001, +0x14400008, 0x2021, 0x8c030104, 0x24020001, +0x50620005, 0x24040001, 0x8c020264, 0x10400003, +0x801021, 0x24040001, 0x801021, 0x10400006, +0x0, 0x8f4202fc, 0x24420001, 0xaf4202fc, +0x10000008, 0x8f4202fc, 0x8f820044, 0x34420004, +0xaf820044, 0x8f4202f8, 0x24420001, 0xaf4202f8, +0x8f4202f8, 0x3c010001, 0x370821, 0xa02040f0, +0x3c010001, 0x370821, 0xa02040f1, 0x8f420000, +0x10400007, 0x0, 0xaf80004c, 0x8f82004c, +0x1040fffd, 0x0, 0x10000005, 0x0, +0xaf800048, 0x8f820048, 0x1040fffd, 0x0, +0x8f820060, 0x3c03ff7f, 0x3463ffff, 0x431024, +0xaf820060, 0x8f420000, 0x10400003, 0x0, +0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0020, +0x3e00008, 0x27bd0028, 0x3e00008, 0x0, +0x27bdffd8, 0xafbf0020, 0x8f430044, 0x8f42007c, +0x10620029, 0x24070008, 0x8f440158, 0x8f45015c, +0x8f48000c, 0x8f860120, 0x24020040, 0xafa20010, +0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, +0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, +0x370821, 0xa02240f2, 0x8f820124, 0xafa20010, +0x8f820128, 0x3c040001, 0x248431bc, 0xafa20014, +0x8f460044, 0x8f870120, 0x3c050009, 0xc0029bb, +0x34a51300, 0x1000000f, 0x0, 0x8f4202f4, +0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044, +0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2, +0x10000004, 0xaf400078, 0x3c010001, 0x370821, +0xa02040f2, 0x8f420000, 0x10400007, 0x0, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x3c03feff, +0x3463ffff, 0x431024, 0xaf820060, 0x8f420000, +0x10400003, 0x0, 0x10000002, 0xaf80004c, +0xaf800048, 0x8fbf0020, 0x3e00008, 0x27bd0028, +0x3e00008, 0x0, 0x3c020001, 0x8c423d98, +0x27bdffa8, 0xafbf0050, 0xafbe004c, 0xafb50048, +0xafb30044, 0xafb20040, 0xafb1003c, 0xafb00038, +0x104000d5, 0x8f900044, 0x8f4200d0, 0x24430001, +0x2842000b, 0x144000e4, 0xaf4300d0, 0x8f420004, +0x30420002, 0x1440009c, 0xaf4000d0, 0x8f420004, +0x3c030001, 0x8c633d88, 0x34420002, 0xaf420004, +0x24020001, 0x14620003, 0x3c020600, 0x10000002, +0x34423000, 0x34421000, 0xafa20020, 0x8f4a0018, +0xafaa0034, 0x27aa0020, 0xafaa002c, 0x8faa0034, +0x240200ff, 0x11420002, 0x1821, 0x25430001, +0x8c020228, 0x609821, 0x1662000e, 0x3c050009, +0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, +0x8c020228, 0x8fa70034, 0x3c040001, 0x2484318c, +0xafa00014, 0xafa20010, 0x8fa60020, 0x10000070, +0x34a50500, 0x8faa0034, 0xa38c0, 0xf71021, +0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, +0x8f830054, 0x8f820054, 0x247103e8, 0x2221023, +0x2c4203e9, 0x1040001b, 0xa821, 0xe09021, +0x265e04c0, 0x8f440168, 0x8f45016c, 0x2401821, +0x240a0004, 0xafaa0010, 0xafb30014, 0x8f48000c, +0x1021, 0x2fe3021, 0xafa80018, 0x8f48010c, +0x24070008, 0xa32821, 0xa3482b, 0x822021, +0x100f809, 0x892021, 0x54400006, 0x24150001, +0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffe9, +0x0, 0x32a200ff, 0x54400018, 0xaf530018, +0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, +0x8f820120, 0x8faa002c, 0x8fa70034, 0xafa20010, +0x8f820124, 0x3c040001, 0x24843198, 0xafa20014, +0x8d460000, 0x3c050009, 0x10000035, 0x34a50600, +0x8f4202f8, 0x24150001, 0x24420001, 0xaf4202f8, +0x8f4202f8, 0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9, -0x1040001b, 0xa821, 0xe09021, 0x265e04c0, -0x8f440168, 0x8f45016c, 0x2401821, 0x240a0004, -0xafaa0010, 0xafb30014, 0x8f48000c, 0x1021, -0x2fe3021, 0xafa80018, 0x8f48010c, 0x24070008, -0xa32821, 0xa3482b, 0x822021, 0x100f809, -0x892021, 0x54400006, 0x24150001, 0x8f820054, -0x2221023, 0x2c4203e9, 0x1440ffe9, 0x0, -0x32a200ff, 0x54400018, 0xaf530018, 0x8f420368, +0x10400016, 0xa821, 0x3c1e0020, 0x24120010, +0x8f42000c, 0x8f440150, 0x8f450154, 0x8f860120, +0xafb20010, 0xafb30014, 0x5e1025, 0xafa20018, +0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c, +0x1440ffe3, 0x0, 0x8f820054, 0x2221023, +0x2c4203e9, 0x1440ffee, 0x0, 0x32a200ff, +0x14400011, 0x3c050009, 0x8f420368, 0x24420001, +0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, +0x8fa70034, 0xafa20010, 0x8f820124, 0x3c040001, +0x248431a0, 0xafa20014, 0x8d460000, 0x34a50700, +0xc0029bb, 0x0, 0x8f4202dc, 0x24420001, +0xaf4202dc, 0x8f4202dc, 0x8f420004, 0x30420001, +0x50400029, 0x36100040, 0x3c020400, 0x2c21024, +0x10400013, 0x2404ffdf, 0x8f420240, 0x8f430244, +0x8f4401a4, 0x14640006, 0x36100040, 0x8f420260, +0x8f430264, 0x8f4401a8, 0x10640007, 0x2402ffdf, +0x8f420240, 0x8f430244, 0x8f440260, 0x8f450264, +0x10000012, 0x3a100020, 0x1000002b, 0x2028024, +0x8f420240, 0x8f430244, 0x8f4501a4, 0x14650006, +0x2048024, 0x8f420260, 0x8f430264, 0x8f4401a8, +0x50640021, 0x36100040, 0x8f420240, 0x8f430244, +0x8f440260, 0x8f450264, 0x3a100040, 0xaf4301a4, +0x10000019, 0xaf4501a8, 0x8f4200d4, 0x24430001, +0x10000011, 0x28420033, 0x8f420004, 0x30420001, +0x10400009, 0x3c020400, 0x2c21024, 0x10400004, +0x2402ffdf, 0x2028024, 0x1000000b, 0x36100040, +0x10000009, 0x36100060, 0x8f4200d4, 0x36100040, +0x24430001, 0x284201f5, 0x14400003, 0xaf4300d4, +0xaf4000d4, 0x3a100020, 0xaf900044, 0x2402ff7f, +0x282a024, 0x8fbf0050, 0x8fbe004c, 0x8fb50048, +0x8fb30044, 0x8fb20040, 0x8fb1003c, 0x8fb00038, +0x3e00008, 0x27bd0058, 0x3e00008, 0x0, +0x3c020001, 0x8c423d98, 0x27bdffb0, 0xafbf0048, +0xafbe0044, 0xafb50040, 0xafb3003c, 0xafb20038, +0xafb10034, 0x104000de, 0xafb00030, 0x8f4200d0, +0x3c040001, 0x8c843d88, 0x24430001, 0x2842000b, +0xaf4400e8, 0x144000fe, 0xaf4300d0, 0x8f420004, +0x30420002, 0x14400095, 0xaf4000d0, 0x8f420004, +0x34420002, 0xaf420004, 0x24020001, 0x14820003, +0x3c020600, 0x10000002, 0x34423000, 0x34421000, +0xafa20020, 0x1821, 0x8f5e0018, 0x27aa0020, +0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001, +0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, +0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, +0x8c020228, 0x3c040001, 0x2484318c, 0x3c050009, +0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d, +0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, +0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, +0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b, +0x9821, 0xe08821, 0x263504c0, 0x8f440168, +0x8f45016c, 0x2201821, 0x240a0004, 0xafaa0010, +0xafb20014, 0x8f48000c, 0x1021, 0x2f53021, +0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, +0xa3482b, 0x822021, 0x100f809, 0x892021, +0x54400006, 0x24130001, 0x8f820054, 0x2021023, +0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, +0x54400017, 0xaf520018, 0x8f420368, 0x24420001, +0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843198, +0x3c050009, 0xafa20014, 0x8d460000, 0x10000035, +0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, +0xaf4202f8, 0x8f4202f8, 0x1000001e, 0x326200ff, +0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, +0x2c4203e9, 0x10400016, 0x9821, 0x3c150020, +0x24110010, 0x8f42000c, 0x8f440150, 0x8f450154, +0x8f860120, 0xafb10010, 0xafb20014, 0x551025, +0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, +0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054, +0x2021023, 0x2c4203e9, 0x1440ffee, 0x0, +0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, -0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843238, 0xafa20014, 0x8d460000, -0x3c050009, 0x10000035, 0x34a50600, 0x8f4202f8, -0x24150001, 0x24420001, 0xaf4202f8, 0x8f4202f8, -0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054, -0x247103e8, 0x2221023, 0x2c4203e9, 0x10400016, -0xa821, 0x3c1e0020, 0x24120010, 0x8f42000c, -0x8f440150, 0x8f450154, 0x8f860120, 0xafb20010, -0xafb30014, 0x5e1025, 0xafa20018, 0x8f42010c, -0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3, -0x0, 0x8f820054, 0x2221023, 0x2c4203e9, -0x1440ffee, 0x0, 0x32a200ff, 0x14400011, -0x3c050009, 0x8f420368, 0x24420001, 0xaf420368, -0x8f420368, 0x8f820120, 0x8faa002c, 0x8fa70034, -0xafa20010, 0x8f820124, 0x3c040001, 0x24843240, -0xafa20014, 0x8d460000, 0x34a50700, 0xc002a03, -0x0, 0x8f4202dc, 0x24420001, 0xaf4202dc, -0x8f4202dc, 0x8f420004, 0x30420001, 0x50400029, -0x36100040, 0x3c020400, 0x2c21024, 0x10400013, -0x2404ffdf, 0x8f420240, 0x8f430244, 0x8f4401a4, -0x14640006, 0x36100040, 0x8f420260, 0x8f430264, -0x8f4401a8, 0x10640007, 0x2402ffdf, 0x8f420240, -0x8f430244, 0x8f440260, 0x8f450264, 0x10000012, -0x3a100020, 0x1000002b, 0x2028024, 0x8f420240, -0x8f430244, 0x8f4501a4, 0x14650006, 0x2048024, -0x8f420260, 0x8f430264, 0x8f4401a8, 0x50640021, -0x36100040, 0x8f420240, 0x8f430244, 0x8f440260, -0x8f450264, 0x3a100040, 0xaf4301a4, 0x10000019, -0xaf4501a8, 0x8f4200d4, 0x24430001, 0x10000011, -0x28420033, 0x8f420004, 0x30420001, 0x10400009, -0x3c020400, 0x2c21024, 0x10400004, 0x2402ffdf, -0x2028024, 0x1000000b, 0x36100040, 0x10000009, -0x36100060, 0x8f4200d4, 0x36100040, 0x24430001, -0x284201f5, 0x14400003, 0xaf4300d4, 0xaf4000d4, -0x3a100020, 0xaf900044, 0x2402ff7f, 0x282a024, -0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, -0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, -0x27bd0058, 0x3e00008, 0x0, 0x3c020001, -0x8c423e38, 0x27bdffb0, 0xafbf0048, 0xafbe0044, -0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, -0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001, -0x8c843e28, 0x24430001, 0x2842000b, 0xaf4400e8, -0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002, -0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002, -0xaf420004, 0x24020001, 0x14820003, 0x3c020600, -0x10000002, 0x34423000, 0x34421000, 0xafa20020, +0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, +0x248431a0, 0x3c050009, 0xafa20014, 0x8d460000, +0x34a50700, 0xc0029bb, 0x3c03821, 0x8f4202dc, +0x24420001, 0xaf4202dc, 0x8f4202dc, 0x8f420004, +0x30420001, 0x10400033, 0x3c020400, 0x2c21024, +0x10400017, 0x0, 0x934205b0, 0x8f440240, +0x8f450244, 0x8f4301a4, 0x34420020, 0x14a30006, +0xa34205b0, 0x8f420260, 0x8f430264, 0x8f4401a8, +0x10640008, 0x0, 0x8f420240, 0x8f430244, +0x934405b0, 0x8f460260, 0x8f470264, 0x10000016, +0x38840040, 0x934205b0, 0x10000048, 0x304200bf, +0x934205b0, 0x8f440240, 0x8f450244, 0x8f4301a4, +0x304200bf, 0x14a30006, 0xa34205b0, 0x8f420260, +0x8f430264, 0x8f4401a8, 0x1064000b, 0x0, +0x8f420240, 0x8f430244, 0x934405b0, 0x8f460260, +0x8f470264, 0x38840020, 0xaf4301a4, 0xaf4701a8, +0x10000033, 0xa34405b0, 0x934205b0, 0x1000002f, +0x34420020, 0x934205b0, 0x8f4300d4, 0x34420020, +0xa34205b0, 0x24620001, 0x10000023, 0x28630033, +0x8f4200e4, 0x8f4300e0, 0x24420001, 0xaf4200e4, +0x43102a, 0x14400006, 0x24030001, 0x8f4200e8, +0x14430002, 0xaf4000e4, 0x24030004, 0xaf4300e8, +0x8f420004, 0x30420001, 0x1040000d, 0x3c020400, +0x2c21024, 0x10400007, 0x0, 0x934205b0, +0x34420040, 0xa34205b0, 0x934205b0, 0x1000000f, +0x304200df, 0x934205b0, 0x1000000c, 0x34420060, +0x934205b0, 0x8f4300d4, 0x34420020, 0xa34205b0, +0x24620001, 0x286300fb, 0x14600005, 0xaf4200d4, +0x934205b0, 0xaf4000d4, 0x38420040, 0xa34205b0, +0x934205b0, 0x8f4300e8, 0x3042007f, 0xa34205b0, +0x24020001, 0x14620005, 0x0, 0x934405b0, +0x42102, 0x10000003, 0x348400f0, 0x934405b0, +0x3484000f, 0xc004a60, 0x0, 0x2402ff7f, +0x282a024, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, +0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, +0x3e00008, 0x27bd0050, 0x3e00008, 0x0, +0x27bdffb0, 0x274401b0, 0x26e30028, 0x24650400, +0x65102b, 0xafbf0048, 0xafbe0044, 0xafb50040, +0xafb3003c, 0xafb20038, 0xafb10034, 0x10400007, +0xafb00030, 0x8c820000, 0xac620000, 0x24630004, +0x65102b, 0x1440fffb, 0x24840004, 0x8c020080, +0xaee20044, 0x8c0200c0, 0xaee20040, 0x8c020084, +0xaee20030, 0x8c020084, 0xaee2023c, 0x8c020088, +0xaee20240, 0x8c02008c, 0xaee20244, 0x8c020090, +0xaee20248, 0x8c020094, 0xaee2024c, 0x8c020098, +0xaee20250, 0x8c02009c, 0xaee20254, 0x8c0200a0, +0xaee20258, 0x8c0200a4, 0xaee2025c, 0x8c0200a8, +0xaee20260, 0x8c0200ac, 0xaee20264, 0x8c0200b0, +0xaee20268, 0x8c0200b4, 0xaee2026c, 0x8c0200b8, +0xaee20270, 0x8c0200bc, 0x24040001, 0xaee20274, +0xaee00034, 0x41080, 0x571021, 0x8ee30034, +0x8c42023c, 0x24840001, 0x621821, 0x2c82000f, +0xaee30034, 0x1440fff8, 0x41080, 0x8c0200cc, +0xaee20048, 0x8c0200d0, 0xaee2004c, 0x8c0200e0, +0xaee201f8, 0x8c0200e4, 0xaee201fc, 0x8c0200e8, +0xaee20200, 0x8c0200ec, 0xaee20204, 0x8c0200f0, +0xaee20208, 0x8ee400c0, 0x8ee500c4, 0x8c0200fc, +0x45102b, 0x1040000b, 0x0, 0x8ee200c0, +0x8ee300c4, 0x24040001, 0x24050000, 0x651821, +0x65302b, 0x441021, 0x461021, 0xaee200c0, +0xaee300c4, 0x8c0200fc, 0x8ee400c0, 0x8ee500c4, +0x2408ffff, 0x24090000, 0x401821, 0x1021, +0x882024, 0xa92824, 0x822025, 0xa32825, +0xaee400c0, 0xaee500c4, 0x8ee400d0, 0x8ee500d4, +0x8c0200f4, 0x45102b, 0x1040000b, 0x0, +0x8ee200d0, 0x8ee300d4, 0x24040001, 0x24050000, +0x651821, 0x65302b, 0x441021, 0x461021, +0xaee200d0, 0xaee300d4, 0x8c0200f4, 0x8ee400d0, +0x8ee500d4, 0x401821, 0x1021, 0x882024, +0xa92824, 0x822025, 0xa32825, 0xaee400d0, +0xaee500d4, 0x8ee400c8, 0x8ee500cc, 0x8c0200f8, +0x45102b, 0x1040000b, 0x0, 0x8ee200c8, +0x8ee300cc, 0x24040001, 0x24050000, 0x651821, +0x65302b, 0x441021, 0x461021, 0xaee200c8, +0xaee300cc, 0x8c0200f8, 0x8ee400c8, 0x8ee500cc, +0x401821, 0x1021, 0x882024, 0xa92824, +0x822025, 0xa32825, 0x24020008, 0xaee400c8, +0xaee500cc, 0xafa20010, 0xafa00014, 0x8f42000c, +0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c, +0x26e60028, 0x40f809, 0x24070400, 0x104000f0, +0x3c020400, 0xafa20020, 0x934205b7, 0x10400089, 0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x3c040001, 0x2484322c, 0x3c050009, 0xafa00014, -0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500, +0x3c040001, 0x2484318c, 0x3c050009, 0xafa00014, +0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b, 0x9821, @@ -5203,241 +5323,129 @@ 0x1440ffe9, 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x24843238, 0x3c050009, -0xafa20014, 0x8d460000, 0x10000035, 0x34a50600, +0x8f820124, 0x3c040001, 0x24843198, 0x3c050009, +0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, -0x8f4202f8, 0x1000001e, 0x326200ff, 0x8f830054, +0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, -0x10400016, 0x9821, 0x3c150020, 0x24110010, -0x8f42000c, 0x8f440150, 0x8f450154, 0x8f860120, -0xafb10010, 0xafb20014, 0x551025, 0xafa20018, -0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c, -0x1440ffe3, 0x0, 0x8f820054, 0x2021023, -0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff, -0x14400011, 0x0, 0x8f420368, 0x24420001, -0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, -0xafa20010, 0x8f820124, 0x3c040001, 0x24843240, -0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, -0xc002a03, 0x3c03821, 0x8f4202dc, 0x24420001, -0xaf4202dc, 0x8f4202dc, 0x8f420004, 0x30420001, -0x10400033, 0x3c020400, 0x2c21024, 0x10400017, -0x0, 0x934205b0, 0x8f440240, 0x8f450244, -0x8f4301a4, 0x34420020, 0x14a30006, 0xa34205b0, -0x8f420260, 0x8f430264, 0x8f4401a8, 0x10640008, -0x0, 0x8f420240, 0x8f430244, 0x934405b0, -0x8f460260, 0x8f470264, 0x10000016, 0x38840040, -0x934205b0, 0x10000048, 0x304200bf, 0x934205b0, -0x8f440240, 0x8f450244, 0x8f4301a4, 0x304200bf, -0x14a30006, 0xa34205b0, 0x8f420260, 0x8f430264, -0x8f4401a8, 0x1064000b, 0x0, 0x8f420240, -0x8f430244, 0x934405b0, 0x8f460260, 0x8f470264, -0x38840020, 0xaf4301a4, 0xaf4701a8, 0x10000033, -0xa34405b0, 0x934205b0, 0x1000002f, 0x34420020, -0x934205b0, 0x8f4300d4, 0x34420020, 0xa34205b0, -0x24620001, 0x10000023, 0x28630033, 0x8f4200e4, -0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a, -0x14400006, 0x24030001, 0x8f4200e8, 0x14430002, -0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004, -0x30420001, 0x1040000d, 0x3c020400, 0x2c21024, -0x10400007, 0x0, 0x934205b0, 0x34420040, -0xa34205b0, 0x934205b0, 0x1000000f, 0x304200df, -0x934205b0, 0x1000000c, 0x34420060, 0x934205b0, -0x8f4300d4, 0x34420020, 0xa34205b0, 0x24620001, -0x286300fb, 0x14600005, 0xaf4200d4, 0x934205b0, -0xaf4000d4, 0x38420040, 0xa34205b0, 0x934205b0, -0x8f4300e8, 0x3042007f, 0xa34205b0, 0x24020001, -0x14620005, 0x0, 0x934405b0, 0x42102, -0x10000003, 0x348400f0, 0x934405b0, 0x3484000f, -0xc004b34, 0x0, 0x2402ff7f, 0x282a024, -0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, -0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, -0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0, -0x274401b0, 0x26e30028, 0x24650400, 0x65102b, -0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c, -0xafb20038, 0xafb10034, 0x10400007, 0xafb00030, -0x8c820000, 0xac620000, 0x24630004, 0x65102b, -0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044, -0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030, -0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240, -0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248, -0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250, -0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258, -0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260, -0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268, -0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270, -0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034, -0x41080, 0x571021, 0x8ee30034, 0x8c42023c, -0x24840001, 0x621821, 0x2c82000f, 0xaee30034, -0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048, -0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8, -0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200, -0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208, -0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b, -0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4, -0x24040001, 0x24050000, 0x651821, 0x65302b, -0x441021, 0x461021, 0xaee200c0, 0xaee300c4, -0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff, -0x24090000, 0x401821, 0x1021, 0x882024, -0xa92824, 0x822025, 0xa32825, 0xaee400c0, -0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4, -0x45102b, 0x1040000b, 0x0, 0x8ee200d0, -0x8ee300d4, 0x24040001, 0x24050000, 0x651821, -0x65302b, 0x441021, 0x461021, 0xaee200d0, -0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4, -0x401821, 0x1021, 0x882024, 0xa92824, -0x822025, 0xa32825, 0xaee400d0, 0xaee500d4, -0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b, -0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc, -0x24040001, 0x24050000, 0x651821, 0x65302b, -0x441021, 0x461021, 0xaee200c8, 0xaee300cc, -0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821, -0x1021, 0x882024, 0xa92824, 0x822025, -0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc, -0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208, -0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028, -0x40f809, 0x24070400, 0x104000f0, 0x3c020400, -0xafa20020, 0x934205b7, 0x10400089, 0x1821, -0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, -0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, -0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, -0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, -0x2484322c, 0x3c050009, 0xafa00014, 0xafa20010, -0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, -0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, -0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, -0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, -0x263504c0, 0x8f440168, 0x8f45016c, 0x2201821, -0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c, -0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, -0x24070008, 0xa32821, 0xa3482b, 0x822021, -0x100f809, 0x892021, 0x54400006, 0x24130001, -0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, -0x0, 0x326200ff, 0x54400017, 0xaf520018, +0x10400014, 0x9821, 0x24110010, 0x8f42000c, +0x8f440150, 0x8f450154, 0x8f860120, 0xafb10010, +0xafb20014, 0xafa20018, 0x8f42010c, 0x24070008, +0x40f809, 0x24c6001c, 0x1440ffe5, 0x0, +0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffef, +0x0, 0x326200ff, 0x54400012, 0x24020001, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843238, 0x3c050009, 0xafa20014, -0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, -0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, -0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, -0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014, -0x9821, 0x24110010, 0x8f42000c, 0x8f440150, -0x8f450154, 0x8f860120, 0xafb10010, 0xafb20014, -0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, -0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054, -0x2021023, 0x2c4203e9, 0x1440ffef, 0x0, -0x326200ff, 0x54400012, 0x24020001, 0x8f420368, -0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, -0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, -0x24843240, 0x3c050009, 0xafa20014, 0x8d460000, -0x34a50700, 0xc002a03, 0x3c03821, 0x1021, -0x1440005b, 0x24020001, 0x10000065, 0x0, -0x8f510018, 0x240200ff, 0x12220002, 0x8021, -0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, -0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, -0x8c020228, 0x3c040001, 0x24843214, 0x3c050009, -0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, -0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, -0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, -0x8f45016c, 0x1021, 0x24070004, 0xafa70010, -0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021, -0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, -0xa3482b, 0x822021, 0x100f809, 0x892021, -0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x2484321c, 0x3c050009, -0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, -0x8f440150, 0x8f450154, 0x8f43000c, 0xaf500018, -0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, -0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, -0x54400011, 0x24020001, 0x8f420330, 0x24420001, -0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x24843224, 0x3c050009, -0xafa20014, 0x8fa60020, 0x34a50300, 0xc002a03, -0x2203821, 0x1021, 0x1040000d, 0x24020001, -0x8f4202d8, 0xa34005b7, 0xaf4001a0, 0x24420001, -0xaf4202d8, 0x8f4202d8, 0x8ee20150, 0x24420001, -0xaee20150, 0x10000003, 0x8ee20150, 0x24020001, -0xa34205b7, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, -0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, -0x3e00008, 0x27bd0050, 0x27bdffd8, 0xafbf0020, -0x8f8200b0, 0x30420004, 0x10400068, 0x0, -0x8f43011c, 0x8f820104, 0x14620005, 0x0, -0x8f430124, 0x8f8200b4, 0x10620006, 0x0, -0x8f820104, 0xaf42011c, 0x8f8200b4, 0x1000005b, -0xaf420124, 0x8f8200b0, 0x3c030080, 0x431024, -0x1040000d, 0x0, 0x8f82011c, 0x34420002, -0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024, -0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024, -0x1000004a, 0xaf82011c, 0x8f43011c, 0x8f820104, -0x14620005, 0x0, 0x8f430124, 0x8f8200b4, -0x10620010, 0x0, 0x8f820104, 0xaf42011c, -0x8f8200b4, 0x8f43011c, 0xaf420124, 0xafa30010, -0x8f420124, 0x3c040001, 0x24843264, 0xafa20014, -0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031, -0x34a50900, 0x8f42011c, 0xafa20010, 0x8f420124, -0x3c040001, 0x24843270, 0xafa20014, 0x8f86011c, -0x8f8700b0, 0x3c050005, 0xc002a03, 0x34a51000, -0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, -0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008, -0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c, -0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c, -0x26e60028, 0x40f809, 0x24070400, 0x8f82011c, -0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, -0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42011c, -0xafa20010, 0x8f420124, 0x3c040001, 0x2484327c, +0x3c040001, 0x248431a0, 0x3c050009, 0xafa20014, +0x8d460000, 0x34a50700, 0xc0029bb, 0x3c03821, +0x1021, 0x1440005b, 0x24020001, 0x10000065, +0x0, 0x8f510018, 0x240200ff, 0x12220002, +0x8021, 0x26300001, 0x8c020228, 0x1602000e, +0x1130c0, 0x8f42032c, 0x24420001, 0xaf42032c, +0x8f42032c, 0x8c020228, 0x3c040001, 0x24843174, +0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, +0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020, +0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821, +0x8f440168, 0x8f45016c, 0x1021, 0x24070004, +0xafa70010, 0xafb00014, 0x8f48000c, 0x24c604c0, +0x2e63021, 0xafa80018, 0x8f48010c, 0x24070008, +0xa32821, 0xa3482b, 0x822021, 0x100f809, +0x892021, 0x1440000b, 0x24070008, 0x8f820120, +0xafa20010, 0x8f820124, 0x3c040001, 0x2484317c, +0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c, +0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, +0xaf500018, 0x8f860120, 0x24020010, 0xafa20010, +0xafb00014, 0xafa30018, 0x8f42010c, 0x40f809, +0x24c6001c, 0x54400011, 0x24020001, 0x8f420330, +0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843184, +0x3c050009, 0xafa20014, 0x8fa60020, 0x34a50300, +0xc0029bb, 0x2203821, 0x1021, 0x1040000d, +0x24020001, 0x8f4202d8, 0xa34005b7, 0xaf4001a0, +0x24420001, 0xaf4202d8, 0x8f4202d8, 0x8ee20150, +0x24420001, 0xaee20150, 0x10000003, 0x8ee20150, +0x24020001, 0xa34205b7, 0x8fbf0048, 0x8fbe0044, +0x8fb50040, 0x8fb3003c, 0x8fb20038, 0x8fb10034, +0x8fb00030, 0x3e00008, 0x27bd0050, 0x27bdffd8, +0xafbf0020, 0x8f8200b0, 0x30420004, 0x10400068, +0x0, 0x8f43011c, 0x8f820104, 0x14620005, +0x0, 0x8f430124, 0x8f8200b4, 0x10620006, +0x0, 0x8f820104, 0xaf42011c, 0x8f8200b4, +0x1000005b, 0xaf420124, 0x8f8200b0, 0x3c030080, +0x431024, 0x1040000d, 0x0, 0x8f82011c, +0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb, +0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd, +0x431024, 0x1000004a, 0xaf82011c, 0x8f43011c, +0x8f820104, 0x14620005, 0x0, 0x8f430124, +0x8f8200b4, 0x10620010, 0x0, 0x8f820104, +0xaf42011c, 0x8f8200b4, 0x8f43011c, 0xaf420124, +0xafa30010, 0x8f420124, 0x3c040001, 0x248431c4, 0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005, -0x34a51100, 0xc002a03, 0x0, 0x8f8200a0, -0x30420004, 0x10400069, 0x0, 0x8f430120, -0x8f820124, 0x14620005, 0x0, 0x8f430128, -0x8f8200a4, 0x10620006, 0x0, 0x8f820124, -0xaf420120, 0x8f8200a4, 0x1000005c, 0xaf420128, -0x8f8200a0, 0x3c030080, 0x431024, 0x1040000d, -0x0, 0x8f82011c, 0x34420002, 0xaf82011c, -0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0, -0x8f82011c, 0x2403fffd, 0x431024, 0x1000004b, -0xaf82011c, 0x8f430120, 0x8f820124, 0x14620005, -0x0, 0x8f430128, 0x8f8200a4, 0x10620010, -0x0, 0x8f820124, 0xaf420120, 0x8f8200a4, -0x8f430120, 0xaf420128, 0xafa30010, 0x8f420128, -0x3c040001, 0x24843288, 0xafa20014, 0x8f86011c, -0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200, +0x10000031, 0x34a50900, 0x8f42011c, 0xafa20010, +0x8f420124, 0x3c040001, 0x248431d0, 0xafa20014, +0x8f86011c, 0x8f8700b0, 0x3c050005, 0xc0029bb, +0x34a51000, 0x8f82011c, 0x34420002, 0xaf82011c, +0x8f830104, 0x8f8200b0, 0x34420001, 0xaf8200b0, +0x24020008, 0xaf830104, 0xafa20010, 0xafa00014, +0x8f42000c, 0x8c040208, 0x8c05020c, 0xafa20018, +0x8f42010c, 0x26e60028, 0x40f809, 0x24070400, +0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, +0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc, +0x8f42011c, 0xafa20010, 0x8f420124, 0x3c040001, +0x248431dc, 0xafa20014, 0x8f86011c, 0x8f8700b0, +0x3c050005, 0x34a51100, 0xc0029bb, 0x0, +0x8f8200a0, 0x30420004, 0x10400069, 0x0, +0x8f430120, 0x8f820124, 0x14620005, 0x0, +0x8f430128, 0x8f8200a4, 0x10620006, 0x0, +0x8f820124, 0xaf420120, 0x8f8200a4, 0x1000005c, +0xaf420128, 0x8f8200a0, 0x3c030080, 0x431024, +0x1040000d, 0x0, 0x8f82011c, 0x34420002, +0xaf82011c, 0x8f8200a0, 0x2403fffb, 0x431024, +0xaf8200a0, 0x8f82011c, 0x2403fffd, 0x431024, +0x1000004b, 0xaf82011c, 0x8f430120, 0x8f820124, +0x14620005, 0x0, 0x8f430128, 0x8f8200a4, +0x10620010, 0x0, 0x8f820124, 0xaf420120, +0x8f8200a4, 0x8f430120, 0xaf420128, 0xafa30010, +0x8f420128, 0x3c040001, 0x248431e8, 0xafa20014, +0x8f86011c, 0x8f8700a0, 0x3c050005, 0x10000032, +0x34a51200, 0x8f420120, 0xafa20010, 0x8f420128, +0x3c040001, 0x248431f4, 0xafa20014, 0x8f86011c, +0x8f8700a0, 0x3c050005, 0xc0029bb, 0x34a51300, +0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830124, +0x8f8200a0, 0x34420001, 0xaf8200a0, 0x24020080, +0xaf830124, 0xafa20010, 0xafa00014, 0x8f420014, +0x8c040208, 0x8c05020c, 0xafa20018, 0x8f420108, +0x3c060001, 0x24c63e84, 0x40f809, 0x24070004, +0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, +0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420120, 0xafa20010, 0x8f420128, 0x3c040001, -0x24843294, 0xafa20014, 0x8f86011c, 0x8f8700a0, -0x3c050005, 0xc002a03, 0x34a51300, 0x8f82011c, -0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, -0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124, -0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208, -0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001, -0x24c63f24, 0x40f809, 0x24070004, 0x8f82011c, -0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, -0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420120, -0xafa20010, 0x8f420128, 0x3c040001, 0x248432a0, -0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005, -0x34a51400, 0xc002a03, 0x0, 0x8fbf0020, -0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001, -0x3c060080, 0x3c050100, 0x8f820070, 0x481024, -0x1040fffd, 0x0, 0x8f820054, 0x24420005, -0xaf820078, 0x8c040234, 0x10800016, 0x1821, -0x3c020001, 0x571021, 0x8c4240e8, 0x24420005, -0x3c010001, 0x370821, 0xac2240e8, 0x3c020001, -0x571021, 0x8c4240e8, 0x44102b, 0x14400009, -0x0, 0x3c030080, 0x3c010001, 0x370821, -0xac2040e8, 0x3c010001, 0x370821, 0x1000000b, -0xa02740f0, 0x3c020001, 0x571021, 0x904240f0, -0x54400006, 0x661825, 0x3c020001, 0x571021, -0x904240f1, 0x54400001, 0x661825, 0x8c040230, -0x10800013, 0x0, 0x3c020001, 0x571021, -0x8c4240ec, 0x24420005, 0x3c010001, 0x370821, -0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec, -0x44102b, 0x14400006, 0x0, 0x3c010001, -0x370821, 0xac2040ec, 0x10000006, 0x651825, -0x3c020001, 0x571021, 0x904240f2, 0x54400001, -0x651825, 0x1060ffbc, 0x0, 0x8f420000, -0x10400007, 0x0, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x431025, 0xaf820060, 0x8f420000, -0x10400003, 0x0, 0x1000ffa7, 0xaf80004c, -0x1000ffa5, 0xaf800048, 0x3e00008, 0x0, +0x24843200, 0xafa20014, 0x8f86011c, 0x8f8700a0, +0x3c050005, 0x34a51400, 0xc0029bb, 0x0, +0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3c081000, +0x24070001, 0x3c060080, 0x3c050100, 0x8f820070, +0x481024, 0x1040fffd, 0x0, 0x8f820054, +0x24420005, 0xaf820078, 0x8c040234, 0x10800016, +0x1821, 0x3c020001, 0x571021, 0x8c4240e8, +0x24420005, 0x3c010001, 0x370821, 0xac2240e8, +0x3c020001, 0x571021, 0x8c4240e8, 0x44102b, +0x14400009, 0x0, 0x3c030080, 0x3c010001, +0x370821, 0xac2040e8, 0x3c010001, 0x370821, +0x1000000b, 0xa02740f0, 0x3c020001, 0x571021, +0x904240f0, 0x54400006, 0x661825, 0x3c020001, +0x571021, 0x904240f1, 0x54400001, 0x661825, +0x8c040230, 0x10800013, 0x0, 0x3c020001, +0x571021, 0x8c4240ec, 0x24420005, 0x3c010001, +0x370821, 0xac2240ec, 0x3c020001, 0x571021, +0x8c4240ec, 0x44102b, 0x14400006, 0x0, +0x3c010001, 0x370821, 0xac2040ec, 0x10000006, +0x651825, 0x3c020001, 0x571021, 0x904240f2, +0x54400001, 0x651825, 0x1060ffbc, 0x0, +0x8f420000, 0x10400007, 0x0, 0xaf80004c, +0x8f82004c, 0x1040fffd, 0x0, 0x10000005, +0x0, 0xaf800048, 0x8f820048, 0x1040fffd, +0x0, 0x8f820060, 0x431025, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x1000ffa7, +0xaf80004c, 0x1000ffa5, 0xaf800048, 0x3e00008, 0x0, 0x0, 0x0, 0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f860064, 0x30c20004, 0x10400025, 0x24040004, 0x8c020114, 0xaf420020, @@ -5480,8 +5488,8 @@ 0x1000006b, 0xaf80004c, 0x10000069, 0xaf800048, 0x30c20001, 0x10400004, 0x24020001, 0xaf820064, 0x10000063, 0x0, 0x30c20002, 0x1440000b, -0x3c050003, 0x3c040001, 0x24843364, 0x34a50500, -0x3821, 0xafa00010, 0xc002a03, 0xafa00014, +0x3c050003, 0x3c040001, 0x248432c4, 0x34a50500, +0x3821, 0xafa00010, 0xc0029bb, 0xafa00014, 0x2402ffc0, 0x10000056, 0xaf820064, 0x8c10022c, 0x8c02010c, 0x12020047, 0x101080, 0x8c450300, 0x26020001, 0x3050003f, 0x24020003, 0xac10022c, @@ -5500,7 +5508,7 @@ 0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 0x8f820060, 0x34420100, 0xaf820060, 0x8f420000, 0x10400003, 0x0, 0x10000005, -0xaf80004c, 0x10000003, 0xaf800048, 0xc002033, +0xaf80004c, 0x10000003, 0xaf800048, 0xc00202b, 0xa02021, 0x8c02010c, 0x16020002, 0x24020002, 0xaf820064, 0x8f820064, 0x30420002, 0x14400004, 0x0, 0x8c02010c, 0x1602ffad, 0x0, @@ -5509,33 +5517,33 @@ 0x808021, 0x101602, 0x2442ffff, 0x304300ff, 0x2c620013, 0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, 0xafb20040, 0x104001e6, 0xafb1003c, -0x31080, 0x3c010001, 0x220821, 0x8c2233a8, +0x31080, 0x3c010001, 0x220821, 0x8c223308, 0x400008, 0x0, 0x101302, 0x30440fff, 0x24020001, 0x10820005, 0x24020002, 0x1082000a, 0x2402fffe, 0x10000021, 0x3c050003, 0x8f430004, -0x3c020001, 0x8c423f50, 0xaf4401f0, 0xaf4401f4, +0x3c020001, 0x8c423eb0, 0xaf4401f0, 0xaf4401f4, 0x10000007, 0x34630001, 0x8f430004, 0xaf4401f0, -0xaf4401f4, 0x621824, 0x3c020001, 0x2442c344, +0xaf4401f4, 0x621824, 0x3c020001, 0x2442c1b0, 0x21100, 0x21182, 0xaf430004, 0x3c030800, 0x431025, 0x3c010000, 0xac224138, 0x8f840054, 0x41442, 0x41c82, 0x431021, 0x41cc2, 0x431023, 0x41d02, 0x431021, 0x41d42, 0x431023, 0x10000009, 0xaf4201f8, 0x3c040001, -0x24843370, 0x34a51000, 0x2003021, 0x3821, -0xafa00010, 0xc002a03, 0xafa00014, 0x8f420290, +0x248432d0, 0x34a51000, 0x2003021, 0x3821, +0xafa00010, 0xc0029bb, 0xafa00014, 0x8f420290, 0x24420001, 0xaf420290, 0x10000215, 0x8f420290, -0x27b00028, 0x2002021, 0x24050210, 0xc002a87, -0x24060008, 0xc0023a0, 0x2002021, 0x1000020c, +0x27b00028, 0x2002021, 0x24050210, 0xc002a3f, +0x24060008, 0xc002398, 0x2002021, 0x1000020c, 0x0, 0x8c06022c, 0x27a40028, 0x61880, 0x24c20001, 0x3046003f, 0x8c650300, 0x61080, 0x8c430300, 0x24c20001, 0x3042003f, 0xac02022c, -0xafa50028, 0xc0023a0, 0xafa3002c, 0x100001fc, +0xafa50028, 0xc002398, 0xafa3002c, 0x100001fc, 0x0, 0x27b00028, 0x2002021, 0x24050210, -0xc002a87, 0x24060008, 0xc0024df, 0x2002021, +0xc002a3f, 0x24060008, 0xc0024d7, 0x2002021, 0x100001f3, 0x0, 0x8c06022c, 0x27a40028, 0x61880, 0x24c20001, 0x3046003f, 0x8c650300, 0x61080, 0x8c430300, 0x24c20001, 0x3042003f, -0xac02022c, 0xafa50028, 0xc0024df, 0xafa3002c, +0xac02022c, 0xafa50028, 0xc0024d7, 0xafa3002c, 0x100001e3, 0x0, 0x101302, 0x30430fff, 0x24020001, 0x10620005, 0x24020002, 0x1062001e, 0x3c020002, 0x10000033, 0x3c050003, 0x3c030002, @@ -5551,8 +5559,8 @@ 0xaf82022c, 0x3c020001, 0x571021, 0x8c4238e0, 0xaf820230, 0x3c020001, 0x571021, 0x8c4238e4, 0xaf820234, 0x3c02fffd, 0x3442ffff, 0x10000009, -0x2c2b024, 0x3c040001, 0x2484337c, 0x34a51100, -0x2003021, 0x3821, 0xafa00010, 0xc002a03, +0x2c2b024, 0x3c040001, 0x248432dc, 0x34a51100, +0x2003021, 0x3821, 0xafa00010, 0xc0029bb, 0xafa00014, 0x8f4202bc, 0x24420001, 0xaf4202bc, 0x1000019b, 0x8f4202bc, 0x101302, 0x30450fff, 0x24020001, 0x10a20005, 0x24020002, 0x10a2000d, @@ -5561,25 +5569,25 @@ 0x621824, 0x34630008, 0xaf830220, 0x10000012, 0xaf450288, 0x3484fff7, 0x3c03fffb, 0x8f820220, 0x3463ffff, 0x2c3b024, 0x441024, 0xaf820220, -0x10000009, 0xaf450288, 0x3c040001, 0x24843388, +0x10000009, 0xaf450288, 0x3c040001, 0x248432e8, 0x34a51200, 0x2003021, 0x3821, 0xafa00010, -0xc002a03, 0xafa00014, 0x8f4202ac, 0x24420001, +0xc0029bb, 0xafa00014, 0x8f4202ac, 0x24420001, 0xaf4202ac, 0x10000172, 0x8f4202ac, 0x27840208, -0x24050200, 0xc002a87, 0x24060008, 0x27440214, -0x24050200, 0xc002a87, 0x24060008, 0x8f4202b4, +0x24050200, 0xc002a3f, 0x24060008, 0x27440214, +0x24050200, 0xc002a3f, 0x24060008, 0x8f4202b4, 0x24420001, 0xaf4202b4, 0x10000165, 0x8f4202b4, 0x101302, 0x30430fff, 0x24020001, 0x10620011, 0x28620002, 0x50400005, 0x24020002, 0x10600007, 0x0, 0x10000017, 0x0, 0x1062000f, 0x0, 0x10000013, 0x0, 0x8c060248, -0x2021, 0xc0048a8, 0x24050004, 0x10000007, -0x0, 0x8c060248, 0x2021, 0xc0048a8, +0x2021, 0xc0047d4, 0x24050004, 0x10000007, +0x0, 0x8c060248, 0x2021, 0xc0047d4, 0x24050004, 0x10000010, 0x0, 0x8c06024c, -0x2021, 0xc0048a8, 0x24050001, 0x1000000a, -0x0, 0x3c040001, 0x24843394, 0x3c050003, +0x2021, 0xc0047d4, 0x24050001, 0x1000000a, +0x0, 0x3c040001, 0x248432f4, 0x3c050003, 0x34a51300, 0x2003021, 0x3821, 0xafa00010, -0xc002a03, 0xafa00014, 0x8f4202b0, 0x24420001, -0xaf4202b0, 0x10000136, 0x8f4202b0, 0xc0022b4, +0xc0029bb, 0xafa00014, 0x8f4202b0, 0x24420001, +0xaf4202b0, 0x10000136, 0x8f4202b0, 0xc0022ac, 0x0, 0x10000132, 0x0, 0x24020001, 0xa34205b6, 0x24100100, 0x8f440198, 0x8f45019c, 0xafb00010, 0xafa00014, 0x8f420014, 0xafa20018, @@ -5591,7 +5599,7 @@ 0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa0034, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, -0x8f42032c, 0x8c020228, 0x3c040001, 0x2484332c, +0x8f42032c, 0x8c020228, 0x3c040001, 0x2484328c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, @@ -5606,7 +5614,7 @@ 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa0034, 0xafa20010, 0x8f820124, 0x3c040001, -0x24843338, 0x3c050009, 0xafa20014, 0x8d460000, +0x24843298, 0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8, @@ -5618,26 +5626,26 @@ 0x2c4203e9, 0x1440ffef, 0x0, 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa0034, -0xafa20010, 0x8f820124, 0x3c040001, 0x24843340, +0xafa20010, 0x8f820124, 0x3c040001, 0x248432a0, 0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, -0xc002a03, 0x3c03821, 0x8f4202a0, 0x24420001, +0xc0029bb, 0x3c03821, 0x8f4202a0, 0x24420001, 0xaf4202a0, 0x8f4202a0, 0x8f4202e8, 0x24420001, 0xaf4202e8, 0x1000008a, 0x8f4202e8, 0x8c02025c, 0x27440214, 0xaf4201e0, 0x8c020260, 0x24050200, -0x24060008, 0xc002a87, 0xaf4201e8, 0x8f820220, +0x24060008, 0xc002a3f, 0xaf4201e8, 0x8f820220, 0x30420008, 0x14400002, 0x24020001, 0x24020002, 0xaf420288, 0x8f42029c, 0x24420001, 0xaf42029c, 0x10000077, 0x8f42029c, 0x3c0200ff, 0x3442ffff, 0x2021824, 0x32c20180, 0x14400006, 0x3402fffb, 0x43102b, 0x14400003, 0x0, 0x1000006c, -0xaf4300bc, 0x3c040001, 0x248433a0, 0x3c050003, +0xaf4300bc, 0x3c040001, 0x24843300, 0x3c050003, 0x34a51500, 0x2003021, 0x3821, 0xafa00010, -0xc002a03, 0xafa00014, 0x3c020700, 0x34421000, +0xc0029bb, 0xafa00014, 0x3c020700, 0x34421000, 0x101e02, 0x621825, 0xafa30020, 0x8f510018, 0x240200ff, 0x12220002, 0x8021, 0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x3c040001, 0x24843314, 0x3c050009, 0xafa00014, +0x3c040001, 0x24843274, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c, @@ -5646,15 +5654,15 @@ 0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 0x822021, 0x100f809, 0x892021, 0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x2484331c, 0x3c050009, 0xafa20014, +0x3c040001, 0x2484327c, 0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 0xaf500018, 0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, 0x0, 0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843324, 0x3c050009, 0xafa20014, -0x8fa60020, 0x34a50300, 0xc002a03, 0x2203821, +0x3c040001, 0x24843284, 0x3c050009, 0xafa20014, +0x8fa60020, 0x34a50300, 0xc0029bb, 0x2203821, 0x8f4202d0, 0x24420001, 0xaf4202d0, 0x8f4202d0, 0x8f4202e0, 0x24420001, 0xaf4202e0, 0x8f4202e0, 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, @@ -5674,21 +5682,21 @@ 0x431024, 0x34420004, 0xaf820200, 0x8f53034c, 0x8f550350, 0x8f5e0354, 0x8f470358, 0xafa70014, 0x8f4202c0, 0x274401b0, 0x24420001, 0xaf4202c0, -0x8f5002c0, 0x8f5101f4, 0x8f5201f0, 0xc002a70, +0x8f5002c0, 0x8f5101f4, 0x8f5201f0, 0xc002a28, 0x24050400, 0xaf53034c, 0xaf550350, 0xaf5e0354, 0x8fa70014, 0xaf470358, 0xaf5002c0, 0xaf5101f4, 0xaf5201f0, 0x8c02025c, 0x27440214, 0xaf4201e0, 0x8c020260, 0x24050200, 0x24060008, 0xaf4201e8, -0x24020006, 0xc002a87, 0xaf4201e4, 0x3c023b9a, +0x24020006, 0xc002a3f, 0xaf4201e4, 0x3c023b9a, 0x3442ca00, 0xaf4201ec, 0x240203e8, 0x24040002, 0x24030001, 0xaf420284, 0xaf440280, 0xaf43028c, 0x8f820220, 0x30420008, 0x10400004, 0x0, 0xaf430288, 0x10000003, 0x3021, 0xaf440288, -0x3021, 0x3c030001, 0x661821, 0x90633d90, +0x3021, 0x3c030001, 0x661821, 0x90633cf0, 0x3461021, 0x24c60001, 0xa043021c, 0x2cc2000f, 0x1440fff8, 0x3461821, 0x24c60001, 0x8f820040, 0x24040080, 0x24050080, 0x21702, 0x24420030, -0xa062021c, 0x3461021, 0xc002a70, 0xa040021c, +0xa062021c, 0x3461021, 0xc002a28, 0xa040021c, 0x8fa7001c, 0x30e20004, 0x14400006, 0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220, 0x8fa70024, 0x30e20004, 0x14400006, @@ -5712,7 +5720,7 @@ 0x2c450001, 0xa01021, 0x14400009, 0x24840008, 0x86102b, 0x1440fff0, 0x1021, 0x304200ff, 0x14400030, 0x24020001, 0x1000002e, 0x1021, -0x1000fffa, 0x24020001, 0x2002021, 0xc00229a, +0x1000fffa, 0x24020001, 0x2002021, 0xc002292, 0x24050006, 0x3042007f, 0x218c0, 0x2e31021, 0x3c010001, 0x220821, 0x942230d0, 0x1040fff2, 0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0, @@ -5727,7 +5735,7 @@ 0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0, 0x801021, 0xafb00030, 0x24500002, 0x2002021, 0x24050006, 0xafb10034, 0x408821, 0xafbf0048, -0xafbe0044, 0xafb50040, 0xafb3003c, 0xc00229a, +0xafbe0044, 0xafb50040, 0xafb3003c, 0xc002292, 0xafb20038, 0x3047007f, 0x710c0, 0x2e21021, 0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c, 0xa03021, 0x3c090001, 0x352934d2, 0x96280002, @@ -5740,15 +5748,15 @@ 0x10c00014, 0x610c0, 0x571821, 0x3c010001, 0x230821, 0x8c2334d0, 0x571021, 0xafa30010, 0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001, -0x248434b4, 0xafa20014, 0x8e260000, 0x8e270004, -0x3c050004, 0xc002a03, 0x34a50400, 0x10000063, +0x24843414, 0xafa20014, 0x8e260000, 0x8e270004, +0x3c050004, 0xc0029bb, 0x34a50400, 0x10000063, 0x3c020800, 0x8f450100, 0x10a00006, 0x510c0, 0x2e21021, 0x3c010001, 0x220821, 0x942234d0, 0xaf420100, 0xa03021, 0x14c00011, 0x628c0, 0x710c0, 0x2e21021, 0xafa70010, 0x3c010001, -0x220821, 0x942230d0, 0x3c040001, 0x248434c0, +0x220821, 0x942230d0, 0x3c040001, 0x24843420, 0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004, -0xc002a03, 0x34a50500, 0x10000048, 0x3c020800, +0xc0029bb, 0x34a50500, 0x10000048, 0x3c020800, 0xb71821, 0x3c020001, 0x96040000, 0x344234d2, 0x621821, 0xa4640000, 0x8e020002, 0x720c0, 0xac620002, 0x2e41021, 0x3c030001, 0x621821, @@ -5771,7 +5779,7 @@ 0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, -0x8c020228, 0x3c040001, 0x2484347c, 0x3c050009, +0x8c020228, 0x3c040001, 0x248433dc, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, @@ -5785,7 +5793,7 @@ 0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, -0xafa20010, 0x8f820124, 0x3c040001, 0x24843488, +0xafa20010, 0x8f820124, 0x3c040001, 0x248433e8, 0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, @@ -5798,8 +5806,8 @@ 0x1440ffef, 0x0, 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x24843490, 0x3c050009, -0xafa20014, 0x8d460000, 0x34a50700, 0xc002a03, +0x8f820124, 0x3c040001, 0x248433f0, 0x3c050009, +0xafa20014, 0x8d460000, 0x34a50700, 0xc0029bb, 0x3c03821, 0x8f4202a4, 0x24420001, 0xaf4202a4, 0x8f4202a4, 0x8f4202e4, 0x24420001, 0xaf4202e4, 0x8f4202e4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, @@ -5807,7 +5815,7 @@ 0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021, 0xafb00040, 0x24500002, 0x2002021, 0x24050006, 0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054, -0xafb50050, 0xafb3004c, 0xc00229a, 0xafb20048, +0xafb50050, 0xafb3004c, 0xc002292, 0xafb20048, 0x3048007f, 0x810c0, 0x2e21021, 0x3c060001, 0xc23021, 0x94c630d0, 0x10c0001c, 0x3821, 0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0, @@ -5819,8 +5827,8 @@ 0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011, 0xafa70028, 0x810c0, 0x2e21021, 0xafa80010, 0x3c010001, 0x220821, 0x942230d0, 0x3c040001, -0x248434cc, 0xafa20014, 0x8e260000, 0x8e270004, -0x3c050004, 0xc002a03, 0x34a50900, 0x10000075, +0x2484342c, 0xafa20014, 0x8e260000, 0x8e270004, +0x3c050004, 0xc0029bb, 0x34a50900, 0x10000075, 0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021, 0x3c030001, 0x621821, 0x946334d0, 0x710c0, 0x2e21021, 0x3c010001, 0x220821, 0xa42334d0, @@ -5855,7 +5863,7 @@ 0xafab0034, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, -0x2484347c, 0x3c050009, 0xafa00014, 0xafa20010, +0x248433dc, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, @@ -5869,7 +5877,7 @@ 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843488, 0x3c050009, 0xafa20014, +0x3c040001, 0x248433e8, 0x3c050009, 0xafa20014, 0x8d660000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, @@ -5882,14 +5890,14 @@ 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001, -0x24843490, 0x3c050009, 0xafa20014, 0x8d660000, -0x34a50700, 0xc002a03, 0x3c03821, 0x8f4202a8, +0x248433f0, 0x3c050009, 0xafa20014, 0x8d660000, +0x34a50700, 0xc0029bb, 0x3c03821, 0x8f4202a8, 0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f4202e4, 0x24420001, 0xaf4202e4, 0x8f4202e4, 0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060, 0x0, 0x0, 0x0, 0x27bdffe0, -0x27644000, 0xafbf0018, 0xc002a70, 0x24051000, +0x27644000, 0xafbf0018, 0xc002a28, 0x24051000, 0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8, 0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100, 0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114, @@ -5898,15 +5906,15 @@ 0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4, 0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021, 0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c, -0x3c040001, 0x24843590, 0x3c050001, 0x34420001, +0x3c040001, 0x248434f0, 0x3c050001, 0x34420001, 0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, -0x34a50100, 0xc002a03, 0x3821, 0x8c020218, +0x34a50100, 0xc0029bb, 0x3821, 0x8c020218, 0x30420040, 0x10400014, 0x0, 0x8f82011c, -0x3c040001, 0x2484359c, 0x3c050001, 0x34420004, +0x3c040001, 0x248434fc, 0x3c050001, 0x34420004, 0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, -0x10000007, 0x34a50200, 0x3c040001, 0x248435a4, +0x10000007, 0x34a50200, 0x3c040001, 0x24843504, 0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300, -0xc002a03, 0x3821, 0x8fbf0018, 0x3e00008, +0xc0029bb, 0x3821, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014, 0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002, 0x24680020, 0x27684800, 0x8f820128, 0x11020004, @@ -5927,237 +5935,221 @@ 0x24820008, 0x3c020001, 0x34422ec8, 0x2e21021, 0x402021, 0x24020001, 0xaf4400f4, 0xac890000, 0xac820004, 0x24020001, 0x3e00008, 0x0, -0x3e00008, 0x0, 0x8fa90010, 0x8faa0014, -0x8f830120, 0x8fab0018, 0x27624fe0, 0x14620002, -0x24680020, 0x27684800, 0x8f820128, 0x1102000f, -0x24620016, 0xac640000, 0xac650004, 0xac660008, -0xa467000e, 0xac690018, 0xac6a001c, 0xac620014, -0xac6b0010, 0xaf880120, 0x8f4300fc, 0x24020001, -0x2463ffff, 0x10000006, 0xaf4300fc, 0x8f430324, -0x1021, 0x24630001, 0xaf430324, 0x8f430324, -0x3e00008, 0x0, 0x3e00008, 0x0, -0x8fa90010, 0x8f83010c, 0x8faa0014, 0x8fab0018, -0x1060000a, 0x276247e0, 0x14620002, 0x24680020, -0x27684000, 0x8f820108, 0x11020004, 0x0, -0x8f820104, 0x15020007, 0x0, 0x8f430328, -0x1021, 0x24630001, 0xaf430328, 0x10000035, -0x8f430328, 0xac640000, 0xac650004, 0xac660008, -0xa467000e, 0xac690018, 0xac6a001c, 0xac6b0010, -0xac620014, 0xaf880100, 0x8f4400ec, 0x8c820000, -0x30420006, 0x10400019, 0x31220006, 0x10400018, -0x3c020001, 0x8c830004, 0x2c620010, 0x10400013, -0x3c020001, 0x24630001, 0xac830004, 0x8f4300f0, -0x34422ec0, 0x2e21021, 0x54620004, 0x24620008, -0x3c020001, 0x34422cc0, 0x2e21021, 0x14440015, -0x24020001, 0x8f820108, 0x24420020, 0xaf820108, -0x8f820108, 0x1000000f, 0x24020001, 0x3c020001, -0x34422ec0, 0x2e21021, 0x54820004, 0x24820008, -0x3c020001, 0x34422cc0, 0x2e21021, 0x402021, -0x24020001, 0xaf4400ec, 0xac890000, 0xac820004, -0x24020001, 0x3e00008, 0x0, 0x3e00008, -0x0, 0x8fa30010, 0x8faa0014, 0x8f880100, -0x8fab0018, 0x276247e0, 0x15020002, 0x25090020, -0x27694000, 0x8f820108, 0x1122000d, 0x0, -0xad030018, 0x25030016, 0xad040000, 0xad050004, -0xad060008, 0xa507000e, 0xad0a001c, 0xad030014, -0xad0b0010, 0xaf890100, 0x10000006, 0x24020001, -0x8f430328, 0x1021, 0x24630001, 0xaf430328, -0x8f430328, 0x3e00008, 0x0, 0x3e00008, -0x0, 0x27bdffd8, 0x3c040001, 0x248435ac, -0x3c050001, 0xafbf0024, 0xafb20020, 0xafb1001c, -0xafb00018, 0x8f900104, 0x8f9100b0, 0x8f92011c, -0x34a52500, 0x8f820100, 0x2403021, 0x2203821, -0xafa20010, 0xc002a03, 0xafb00014, 0x8e020008, -0xafa20010, 0x8e02000c, 0x3c040001, 0x248435b8, -0xafa20014, 0x8e060000, 0x8e070004, 0x3c050001, -0xc002a03, 0x34a52510, 0x8e020018, 0xafa20010, -0x8e02001c, 0x3c040001, 0x248435c4, 0xafa20014, -0x8e060010, 0x8e070014, 0x3c050001, 0xc002a03, -0x34a52520, 0x3c027f00, 0x2221024, 0x3c030800, -0x54430016, 0x3c030200, 0x8f82009c, 0x3042ffff, -0x14400012, 0x3c030200, 0x3c040001, 0x248435d0, -0x3c050002, 0x34a5f030, 0x3021, 0x3821, -0x36420002, 0xaf82011c, 0x36220001, 0xaf8200b0, -0xaf900104, 0xaf92011c, 0xafa00010, 0xc002a03, -0xafa00014, 0x10000024, 0x0, 0x2c31024, -0x1040000d, 0x2231024, 0x1040000b, 0x36420002, -0xaf82011c, 0x36220001, 0xaf8200b0, 0xaf900104, -0xaf92011c, 0x8f420320, 0x24420001, 0xaf420320, -0x10000015, 0x8f420320, 0x3c040001, 0x248435d8, -0x240202a2, 0xafa20010, 0xafa00014, 0x8f860144, -0x3c070001, 0x24e735e0, 0xc002a03, 0x3405dead, -0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220, -0x34420004, 0xaf820220, 0x8f820140, 0x3c030001, -0x431025, 0xaf820140, 0x8fbf0024, 0x8fb20020, -0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, -0x27bdffd8, 0x3c040001, 0x24843608, 0x3c050001, -0xafbf0024, 0xafb20020, 0xafb1001c, 0xafb00018, -0x8f900124, 0x8f9100a0, 0x8f92011c, 0x34a52600, -0x8f820120, 0x2403021, 0x2203821, 0xafa20010, -0xc002a03, 0xafb00014, 0x8e020008, 0xafa20010, -0x8e02000c, 0x3c040001, 0x24843614, 0xafa20014, -0x8e060000, 0x8e070004, 0x3c050001, 0xc002a03, -0x34a52610, 0x8e020018, 0xafa20010, 0x8e02001c, -0x3c040001, 0x24843620, 0xafa20014, 0x8e060010, -0x8e070014, 0x3c050001, 0xc002a03, 0x34a52620, -0x3c027f00, 0x2221024, 0x3c030800, 0x54430016, -0x3c030200, 0x8f8200ac, 0x3042ffff, 0x14400012, -0x3c030200, 0x3c040001, 0x2484362c, 0x3c050001, -0x34a5f030, 0x3021, 0x3821, 0x36420002, -0xaf82011c, 0x36220001, 0xaf8200a0, 0xaf900124, -0xaf92011c, 0xafa00010, 0xc002a03, 0xafa00014, -0x10000024, 0x0, 0x2c31024, 0x1040000d, -0x2231024, 0x1040000b, 0x36420002, 0xaf82011c, -0x36220001, 0xaf8200a0, 0xaf900124, 0xaf92011c, -0x8f42031c, 0x24420001, 0xaf42031c, 0x10000015, -0x8f42031c, 0x3c040001, 0x248435d8, 0x240202db, -0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001, -0x24e735e0, 0xc002a03, 0x3405dead, 0x8f82011c, -0x34420002, 0xaf82011c, 0x8f820220, 0x34420004, -0xaf820220, 0x8f820140, 0x3c030001, 0x431025, -0xaf820140, 0x8fbf0024, 0x8fb20020, 0x8fb1001c, -0x8fb00018, 0x3e00008, 0x27bd0028, 0x6021, -0x5021, 0x3021, 0x2821, 0x6821, -0x4821, 0x7821, 0x7021, 0x8f880124, -0x8f870104, 0x1580002e, 0x8f8b011c, 0x11a00014, -0x31620800, 0x8f820120, 0x10460029, 0x0, -0x3c040001, 0x8c843f30, 0x8cc20000, 0x8cc30004, +0x3e00008, 0x0, 0x8fa90010, 0x8f83010c, +0x8faa0014, 0x8fab0018, 0x1060000a, 0x276247e0, +0x14620002, 0x24680020, 0x27684000, 0x8f820108, +0x11020004, 0x0, 0x8f820104, 0x15020007, +0x0, 0x8f430328, 0x1021, 0x24630001, +0xaf430328, 0x10000035, 0x8f430328, 0xac640000, +0xac650004, 0xac660008, 0xa467000e, 0xac690018, +0xac6a001c, 0xac6b0010, 0xac620014, 0xaf880100, +0x8f4400ec, 0x8c820000, 0x30420006, 0x10400019, +0x31220006, 0x10400018, 0x3c020001, 0x8c830004, +0x2c620010, 0x10400013, 0x3c020001, 0x24630001, +0xac830004, 0x8f4300f0, 0x34422ec0, 0x2e21021, +0x54620004, 0x24620008, 0x3c020001, 0x34422cc0, +0x2e21021, 0x14440015, 0x24020001, 0x8f820108, +0x24420020, 0xaf820108, 0x8f820108, 0x1000000f, +0x24020001, 0x3c020001, 0x34422ec0, 0x2e21021, +0x54820004, 0x24820008, 0x3c020001, 0x34422cc0, +0x2e21021, 0x402021, 0x24020001, 0xaf4400ec, +0xac890000, 0xac820004, 0x24020001, 0x3e00008, +0x0, 0x3e00008, 0x0, 0x27bdffd8, +0x3c040001, 0x2484350c, 0x3c050001, 0xafbf0024, +0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104, +0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100, +0x2403021, 0x2203821, 0xafa20010, 0xc0029bb, +0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c, +0x3c040001, 0x24843518, 0xafa20014, 0x8e060000, +0x8e070004, 0x3c050001, 0xc0029bb, 0x34a52510, +0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001, +0x24843524, 0xafa20014, 0x8e060010, 0x8e070014, +0x3c050001, 0xc0029bb, 0x34a52520, 0x3c027f00, +0x2221024, 0x3c030800, 0x54430016, 0x3c030200, +0x8f82009c, 0x3042ffff, 0x14400012, 0x3c030200, +0x3c040001, 0x24843530, 0x3c050002, 0x34a5f030, +0x3021, 0x3821, 0x36420002, 0xaf82011c, +0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c, +0xafa00010, 0xc0029bb, 0xafa00014, 0x10000024, +0x0, 0x2c31024, 0x1040000d, 0x2231024, +0x1040000b, 0x36420002, 0xaf82011c, 0x36220001, +0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420320, +0x24420001, 0xaf420320, 0x10000015, 0x8f420320, +0x3c040001, 0x24843538, 0x240202a9, 0xafa20010, +0xafa00014, 0x8f860144, 0x3c070001, 0x24e73540, +0xc0029bb, 0x3405dead, 0x8f82011c, 0x34420002, +0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220, +0x8f820140, 0x3c030001, 0x431025, 0xaf820140, +0x8fbf0024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, +0x3e00008, 0x27bd0028, 0x27bdffd8, 0x3c040001, +0x24843568, 0x3c050001, 0xafbf0024, 0xafb20020, +0xafb1001c, 0xafb00018, 0x8f900124, 0x8f9100a0, +0x8f92011c, 0x34a52600, 0x8f820120, 0x2403021, +0x2203821, 0xafa20010, 0xc0029bb, 0xafb00014, +0x8e020008, 0xafa20010, 0x8e02000c, 0x3c040001, +0x24843574, 0xafa20014, 0x8e060000, 0x8e070004, +0x3c050001, 0xc0029bb, 0x34a52610, 0x8e020018, +0xafa20010, 0x8e02001c, 0x3c040001, 0x24843580, +0xafa20014, 0x8e060010, 0x8e070014, 0x3c050001, +0xc0029bb, 0x34a52620, 0x3c027f00, 0x2221024, +0x3c030800, 0x54430016, 0x3c030200, 0x8f8200ac, +0x3042ffff, 0x14400012, 0x3c030200, 0x3c040001, +0x2484358c, 0x3c050001, 0x34a5f030, 0x3021, +0x3821, 0x36420002, 0xaf82011c, 0x36220001, +0xaf8200a0, 0xaf900124, 0xaf92011c, 0xafa00010, +0xc0029bb, 0xafa00014, 0x10000024, 0x0, +0x2c31024, 0x1040000d, 0x2231024, 0x1040000b, +0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0, +0xaf900124, 0xaf92011c, 0x8f42031c, 0x24420001, +0xaf42031c, 0x10000015, 0x8f42031c, 0x3c040001, +0x24843538, 0x240202e2, 0xafa20010, 0xafa00014, +0x8f860144, 0x3c070001, 0x24e73540, 0xc0029bb, +0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, +0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, +0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024, +0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, +0x27bd0028, 0x6021, 0x5021, 0x3021, +0x2821, 0x6821, 0x4821, 0x7821, +0x7021, 0x8f880124, 0x8f870104, 0x1580002e, +0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120, +0x10460029, 0x0, 0x3c040001, 0x8c843e90, +0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, +0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, +0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, +0x10000012, 0x24c60020, 0x10400017, 0x0, +0x3c040001, 0x8c843e90, 0x8d020000, 0x8d030004, +0xac820000, 0xac830004, 0x8d020008, 0xac820008, +0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, +0xac820010, 0x8d020014, 0x240c0001, 0xc01821, +0xac820014, 0x27624fe0, 0x43102b, 0x54400001, +0x27634800, 0x603021, 0x1540002f, 0x31620100, +0x11200014, 0x31628000, 0x8f820100, 0x1045002a, +0x31620100, 0x3c040001, 0x8c843e8c, 0x8ca20000, +0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, +0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, +0x240a0001, 0xac820010, 0x8ca20014, 0x10000012, +0x24a50020, 0x10400018, 0x31620100, 0x3c040001, +0x8c843e8c, 0x8ce20000, 0x8ce30004, 0xac820000, +0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, +0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, +0x8ce20014, 0x240a0001, 0xa01821, 0xac820014, +0x276247e0, 0x43102b, 0x54400001, 0x27634000, +0x602821, 0x31620100, 0x5440001d, 0x31621000, +0x11a00009, 0x31a20800, 0x10400004, 0x25020020, +0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, +0x8f880124, 0x6821, 0x11800011, 0x31621000, +0x3c040001, 0x8c843e90, 0x8c820000, 0x8c830004, +0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, +0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, +0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000, +0x1440ff82, 0x0, 0x1120000f, 0x31220800, +0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, +0x3c020002, 0x1221024, 0x10400004, 0x24e20020, +0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, +0x8f870104, 0x4821, 0x1140ff70, 0x0, +0x3c040001, 0x8c843e8c, 0x8c820000, 0x8c830004, +0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, +0x9482000e, 0xaf82009c, 0x8c820010, 0x5021, +0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014, +0x3e00008, 0x0, 0x6021, 0x5821, +0x3021, 0x2821, 0x6821, 0x5021, +0x7821, 0x7021, 0x8f880124, 0x8f870104, +0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014, +0x31220800, 0x8f820120, 0x10460029, 0x0, +0x3c040001, 0x8c843e90, 0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, 0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, 0x10000012, 0x24c60020, -0x10400017, 0x0, 0x3c040001, 0x8c843f30, +0x10400017, 0x0, 0x3c040001, 0x8c843e90, 0x8d020000, 0x8d030004, 0xac820000, 0xac830004, 0x8d020008, 0xac820008, 0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, 0xac820010, 0x8d020014, 0x240c0001, 0xc01821, 0xac820014, 0x27624fe0, 0x43102b, 0x54400001, 0x27634800, 0x603021, -0x1540002f, 0x31620100, 0x11200014, 0x31628000, -0x8f820100, 0x1045002a, 0x31620100, 0x3c040001, -0x8c843f2c, 0x8ca20000, 0x8ca30004, 0xac820000, +0x1560002f, 0x31220100, 0x11400014, 0x31228000, +0x8f820100, 0x1045002a, 0x31220100, 0x3c040001, +0x8c843e8c, 0x8ca20000, 0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e, -0xa482000e, 0x8ca20010, 0x240a0001, 0xac820010, +0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010, 0x8ca20014, 0x10000012, 0x24a50020, 0x10400018, -0x31620100, 0x3c040001, 0x8c843f2c, 0x8ce20000, +0x31220100, 0x3c040001, 0x8c843e8c, 0x8ce20000, 0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010, -0x24e50020, 0xac820010, 0x8ce20014, 0x240a0001, +0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001, 0xa01821, 0xac820014, 0x276247e0, 0x43102b, -0x54400001, 0x27634000, 0x602821, 0x31620100, -0x5440001d, 0x31621000, 0x11a00009, 0x31a20800, +0x54400001, 0x27634000, 0x602821, 0x31220100, +0x5440001d, 0x31221000, 0x11a00009, 0x31a20800, 0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, 0x8f880124, 0x6821, -0x11800011, 0x31621000, 0x3c040001, 0x8c843f30, +0x11800011, 0x31221000, 0x3c040001, 0x8c843e90, 0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010, -0x8c8f0014, 0x31621000, 0x1440ff82, 0x0, -0x1120000f, 0x31220800, 0x10400004, 0x3c020002, -0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1221024, +0x8c8f0014, 0x31221000, 0x14400022, 0x0, +0x1140000f, 0x31420800, 0x10400004, 0x3c020002, +0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024, 0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4, -0x24e20020, 0xaf820104, 0x8f870104, 0x4821, -0x1140ff70, 0x0, 0x3c040001, 0x8c843f2c, +0x24e20020, 0xaf820104, 0x8f870104, 0x5021, +0x11600010, 0x0, 0x3c040001, 0x8c843e8c, 0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c, -0x8c820010, 0x5021, 0xaf8200b0, 0x8c890010, -0x1000ff60, 0x8c8e0014, 0x3e00008, 0x0, -0x6021, 0x5821, 0x3021, 0x2821, -0x6821, 0x5021, 0x7821, 0x7021, -0x8f880124, 0x8f870104, 0x3c180100, 0x1580002e, -0x8f89011c, 0x11a00014, 0x31220800, 0x8f820120, -0x10460029, 0x0, 0x3c040001, 0x8c843f30, -0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, -0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, -0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, -0x10000012, 0x24c60020, 0x10400017, 0x0, -0x3c040001, 0x8c843f30, 0x8d020000, 0x8d030004, -0xac820000, 0xac830004, 0x8d020008, 0xac820008, -0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, -0xac820010, 0x8d020014, 0x240c0001, 0xc01821, -0xac820014, 0x27624fe0, 0x43102b, 0x54400001, -0x27634800, 0x603021, 0x1560002f, 0x31220100, -0x11400014, 0x31228000, 0x8f820100, 0x1045002a, -0x31220100, 0x3c040001, 0x8c843f2c, 0x8ca20000, -0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, -0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, -0x240b0001, 0xac820010, 0x8ca20014, 0x10000012, -0x24a50020, 0x10400018, 0x31220100, 0x3c040001, -0x8c843f2c, 0x8ce20000, 0x8ce30004, 0xac820000, -0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, -0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, -0x8ce20014, 0x240b0001, 0xa01821, 0xac820014, -0x276247e0, 0x43102b, 0x54400001, 0x27634000, -0x602821, 0x31220100, 0x5440001d, 0x31221000, -0x11a00009, 0x31a20800, 0x10400004, 0x25020020, -0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, -0x8f880124, 0x6821, 0x11800011, 0x31221000, -0x3c040001, 0x8c843f30, 0x8c820000, 0x8c830004, -0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, -0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, -0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31221000, -0x14400022, 0x0, 0x1140000f, 0x31420800, -0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, -0x3c020002, 0x1421024, 0x10400004, 0x24e20020, -0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, -0x8f870104, 0x5021, 0x11600010, 0x0, -0x3c040001, 0x8c843f2c, 0x8c820000, 0x8c830004, -0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, -0x9482000e, 0xaf82009c, 0x8c820010, 0x5821, -0xaf8200b0, 0x8c8a0010, 0x8c8e0014, 0x8f820070, -0x3c031000, 0x431024, 0x1040ff5c, 0x0, -0x8f820054, 0x24420005, 0xaf820078, 0x8c040234, -0x10800016, 0x1821, 0x3c020001, 0x571021, -0x8c4240e8, 0x24420005, 0x3c010001, 0x370821, -0xac2240e8, 0x3c020001, 0x571021, 0x8c4240e8, -0x44102b, 0x14400009, 0x24020001, 0x3c030080, -0x3c010001, 0x370821, 0xac2040e8, 0x3c010001, -0x370821, 0x1000000c, 0xa02240f0, 0x3c020001, -0x571021, 0x904240f0, 0x14400006, 0x3c020080, -0x3c020001, 0x571021, 0x904240f1, 0x10400002, -0x3c020080, 0x621825, 0x8c040230, 0x10800013, -0x0, 0x3c020001, 0x571021, 0x8c4240ec, -0x24420005, 0x3c010001, 0x370821, 0xac2240ec, -0x3c020001, 0x571021, 0x8c4240ec, 0x44102b, -0x14400006, 0x0, 0x3c010001, 0x370821, -0xac2040ec, 0x10000006, 0x781825, 0x3c020001, -0x571021, 0x904240f2, 0x54400001, 0x781825, -0x1060ff1a, 0x0, 0x8f420000, 0x10400007, -0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, -0x0, 0x10000005, 0x0, 0xaf800048, -0x8f820048, 0x1040fffd, 0x0, 0x8f820060, -0x431025, 0xaf820060, 0x8f420000, 0x10400003, -0x0, 0x1000ff05, 0xaf80004c, 0x1000ff03, -0xaf800048, 0x3e00008, 0x0, 0x3c020001, -0x8c423db8, 0x27bdffe8, 0xafbf0014, 0x14400012, -0xafb00010, 0x3c100001, 0x26103fd0, 0x2002021, -0xc002a70, 0x24052000, 0x26021fe0, 0x3c010001, -0xac223f38, 0x3c010001, 0xac223f34, 0xac020250, +0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010, +0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024, +0x1040ff5c, 0x0, 0x8f820054, 0x24420005, +0xaf820078, 0x8c040234, 0x10800016, 0x1821, +0x3c020001, 0x571021, 0x8c4240e8, 0x24420005, +0x3c010001, 0x370821, 0xac2240e8, 0x3c020001, +0x571021, 0x8c4240e8, 0x44102b, 0x14400009, +0x24020001, 0x3c030080, 0x3c010001, 0x370821, +0xac2040e8, 0x3c010001, 0x370821, 0x1000000c, +0xa02240f0, 0x3c020001, 0x571021, 0x904240f0, +0x14400006, 0x3c020080, 0x3c020001, 0x571021, +0x904240f1, 0x10400002, 0x3c020080, 0x621825, +0x8c040230, 0x10800013, 0x0, 0x3c020001, +0x571021, 0x8c4240ec, 0x24420005, 0x3c010001, +0x370821, 0xac2240ec, 0x3c020001, 0x571021, +0x8c4240ec, 0x44102b, 0x14400006, 0x0, +0x3c010001, 0x370821, 0xac2040ec, 0x10000006, +0x781825, 0x3c020001, 0x571021, 0x904240f2, +0x54400001, 0x781825, 0x1060ff1a, 0x0, +0x8f420000, 0x10400007, 0x0, 0xaf80004c, +0x8f82004c, 0x1040fffd, 0x0, 0x10000005, +0x0, 0xaf800048, 0x8f820048, 0x1040fffd, +0x0, 0x8f820060, 0x431025, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x1000ff05, +0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008, +0x0, 0x0, 0x0, 0x3c020001, +0x8c423d18, 0x27bdffe8, 0xafbf0014, 0x14400012, +0xafb00010, 0x3c100001, 0x26103f30, 0x2002021, +0xc002a28, 0x24052000, 0x26021fe0, 0x3c010001, +0xac223e98, 0x3c010001, 0xac223e94, 0xac020250, 0x24022000, 0xac100254, 0xac020258, 0x24020001, -0x3c010001, 0xac223db8, 0x8fbf0014, 0x8fb00010, -0x3e00008, 0x27bd0018, 0x3c090001, 0x8d293f38, +0x3c010001, 0xac223d18, 0x8fbf0014, 0x8fb00010, +0x3e00008, 0x27bd0018, 0x3c090001, 0x8d293e98, 0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000, 0x8c820004, 0xad250008, 0xad220004, 0x8f820054, 0xad260010, 0xad270014, 0xad230018, 0xad28001c, -0xad22000c, 0x2529ffe0, 0x3c020001, 0x24423fd0, +0xad22000c, 0x2529ffe0, 0x3c020001, 0x24423f30, 0x122102b, 0x10400003, 0x0, 0x3c090001, -0x8d293f34, 0x3c020001, 0x8c423da0, 0xad220000, -0x3c020001, 0x8c423da0, 0x3c010001, 0xac293f38, +0x8d293e94, 0x3c020001, 0x8c423d00, 0xad220000, +0x3c020001, 0x8c423d00, 0x3c010001, 0xac293e98, 0xad220004, 0xac090250, 0x3e00008, 0x0, -0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e103f38, -0x3c020001, 0x8c423da0, 0xafb10014, 0x808821, +0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e103e98, +0x3c020001, 0x8c423d00, 0xafb10014, 0x808821, 0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018, 0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c, -0xae020000, 0x3c020001, 0x8c423da0, 0xc09821, +0xae020000, 0x3c020001, 0x8c423d00, 0xc09821, 0xe0a821, 0x10800006, 0xae020004, 0x26050008, -0xc002a7b, 0x24060018, 0x10000005, 0x2610ffe0, -0x26040008, 0xc002a70, 0x24050018, 0x2610ffe0, -0x3c030001, 0x24633fd0, 0x203102b, 0x10400003, -0x0, 0x3c100001, 0x8e103f34, 0x8e220000, +0xc002a33, 0x24060018, 0x10000005, 0x2610ffe0, +0x26040008, 0xc002a28, 0x24050018, 0x2610ffe0, +0x3c030001, 0x24633f30, 0x203102b, 0x10400003, +0x0, 0x3c100001, 0x8e103e94, 0x8e220000, 0xae020000, 0x8e220004, 0xae120008, 0xae020004, 0x8f820054, 0xae130010, 0xae150014, 0xae1e0018, 0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0, 0x203102b, 0x10400003, 0x0, 0x3c100001, -0x8e103f34, 0x3c020001, 0x8c423da0, 0xae020000, -0x3c020001, 0x8c423da0, 0x3c010001, 0xac303f38, +0x8e103e94, 0x3c020001, 0x8c423d00, 0xae020000, +0x3c020001, 0x8c423d00, 0x3c010001, 0xac303e98, 0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024, 0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821, @@ -6342,8 +6334,8 @@ 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x248438e4, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, +0x8f820128, 0x3c040001, 0x24843844, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029bb, 0x34a51100, 0x10000036, 0x0, 0x8f4202f0, 0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, 0x10000026, 0xaf430038, @@ -6352,8 +6344,8 @@ 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x248438d8, 0xafa20014, 0x8f46002c, -0x8f870120, 0x3c050009, 0xc002a03, 0x34a50900, +0x3c040001, 0x24843838, 0xafa20014, 0x8f46002c, +0x8f870120, 0x3c050009, 0xc0029bb, 0x34a50900, 0x1000000f, 0x0, 0x8f4202f0, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, 0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, @@ -6381,7 +6373,7 @@ 0x441021, 0xaf420358, 0x3c020800, 0x2c21024, 0x5040001a, 0x36940040, 0x10000018, 0x0, 0x30a20100, 0x10400015, 0x0, 0x3c020001, -0x8c423d64, 0x1040000c, 0x0, 0x274301b0, +0x8c423cc4, 0x1040000c, 0x0, 0x274301b0, 0x24650400, 0x65102b, 0x10400007, 0x26e40028, 0x8c820000, 0xac620000, 0x24630004, 0x65102b, 0x1440fffb, 0x24840004, 0x8f4202cc, 0xa34005b6, @@ -6414,8 +6406,8 @@ 0x431021, 0x904c0009, 0x318900ff, 0x39230006, 0x3182b, 0x39220011, 0x2102b, 0x621824, 0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001, -0x248438f4, 0xafa20010, 0x8f4200a0, 0x34a54600, -0x1203821, 0xc002a03, 0xafa20014, 0x1000004e, +0x24843854, 0xafa20010, 0x8f4200a0, 0x34a54600, +0x1203821, 0xc0029bb, 0xafa20014, 0x1000004e, 0x0, 0x32c20004, 0x14400013, 0x2821, 0x316200ff, 0x14400004, 0x0, 0x95020002, 0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e, @@ -6513,8 +6505,8 @@ 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x248438e4, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, +0x8f820128, 0x3c040001, 0x24843844, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029bb, 0x34a51100, 0x10000036, 0x0, 0x8f4202f0, 0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, 0x10000026, 0xaf430038, @@ -6523,8 +6515,8 @@ 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x248438d8, 0xafa20014, 0x8f46002c, -0x8f870120, 0x3c050009, 0xc002a03, 0x34a50900, +0x3c040001, 0x24843838, 0xafa20014, 0x8f46002c, +0x8f870120, 0x3c050009, 0xc0029bb, 0x34a50900, 0x1000000f, 0x0, 0x8f4202f0, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, 0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, @@ -6554,785 +6546,750 @@ 0x32420048, 0x10400007, 0x24150001, 0x8e22001c, 0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd78, 0xae22001c, 0x32420100, 0x10400015, 0x0, -0x3c020001, 0x8c423d64, 0x1040000c, 0x0, +0x3c020001, 0x8c423cc4, 0x1040000c, 0x0, 0x274301b0, 0x24650400, 0x65102b, 0x10400007, 0x26e40028, 0x8c820000, 0xac620000, 0x24630004, 0x65102b, 0x1440fffb, 0x24840004, 0x8f4202cc, 0xa34005b6, 0x24420001, 0xaf4202cc, 0x8f4202cc, 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, -0x27bd0058, 0x3e00008, 0x0, 0x8f8600e4, -0x8f8200e0, 0x2403fff8, 0x431024, 0x10c20007, -0x803821, 0x8cc20000, 0x8cc30004, 0xace20000, -0xace30004, 0x10000002, 0x24020001, 0x1021, -0x3e00008, 0x0, 0x3e00008, 0x0, -0x8f8300e4, 0x27623ff8, 0x14620002, 0x24620008, -0x27623000, 0x401821, 0xaf8300e8, 0xaf8300e4, -0x3e00008, 0x0, 0x3e00008, 0x0, -0x8f8400e0, 0x8f8800c4, 0x8f8300e8, 0x2402fff8, -0x823824, 0xe32023, 0x2c821000, 0x50400001, -0x24841000, 0x420c2, 0x801821, 0x8f440248, -0x8f45024c, 0x1021, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xaf440248, 0xaf45024c, -0x8f8300c8, 0x8f42013c, 0x1032023, 0x82102b, -0x14400004, 0x801821, 0x8f42013c, 0x822021, -0x801821, 0x8f440240, 0x8f450244, 0x1021, -0xa32821, 0xa3302b, 0x822021, 0x862021, -0xaf440240, 0xaf450244, 0xaf8800c8, 0xaf8700e4, -0xaf8700e8, 0x3e00008, 0x0, 0x27bdff30, -0x240a0001, 0xafbf00c8, 0xafbe00c4, 0xafb500c0, -0xafb300bc, 0xafb200b8, 0xafb100b4, 0xafb000b0, -0xa3a00097, 0xafa00044, 0xafaa005c, 0x934205b5, -0xa7a0008e, 0x1040000a, 0xa7a00086, 0x8f4b00c4, -0xafab0064, 0x8f4a00c0, 0xafaa006c, 0x8f4b00cc, -0xafab0074, 0x8f4a00c8, 0x10000125, 0xafaa007c, -0x8f420114, 0x40f809, 0x27a40020, 0x304200ff, -0x1040033b, 0x0, 0x8fab0024, 0x8faa0020, -0x3162ffff, 0x2442fffc, 0xafa2006c, 0x3c020006, -0x2c21024, 0xafab007c, 0x14400015, 0xafaa0064, -0x91420000, 0x30420001, 0x10400011, 0x2402ffff, -0x8d430000, 0x14620004, 0x3402ffff, 0x95430004, -0x1062000b, 0x0, 0xc002343, 0x8fa40064, -0x304200ff, 0x14400006, 0x0, 0x8f420118, -0x40f809, 0x0, 0x1000031d, 0x0, -0x8fa20024, 0x3c03ffbf, 0x3463ffff, 0x431024, -0x3c03ffff, 0x431824, 0x14600003, 0xafa20024, -0x10000040, 0x1821, 0x3c020080, 0x621024, -0x10400007, 0x0, 0x8f42037c, 0x24420001, -0xaf42037c, 0x8f42037c, 0x10000036, 0x24030001, -0x8f420200, 0x24420001, 0xaf420200, 0x8f420200, -0x3c020001, 0x621024, 0x10400006, 0x3c020002, -0x8f4201b4, 0x24420001, 0xaf4201b4, 0x8f4201b4, -0x3c020002, 0x621024, 0x10400006, 0x3c020004, -0x8f42036c, 0x24420001, 0xaf42036c, 0x8f42036c, -0x3c020004, 0x621024, 0x10400006, 0x3c020008, -0x8f420370, 0x24420001, 0xaf420370, 0x8f420370, -0x3c020008, 0x621024, 0x10400006, 0x3c020010, -0x8f420374, 0x24420001, 0xaf420374, 0x8f420374, -0x3c020010, 0x621024, 0x10400006, 0x3c020020, -0x8f4201b0, 0x24420001, 0xaf4201b0, 0x8f4201b0, -0x3c020020, 0x621024, 0x10400006, 0x24030001, -0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, -0x24030001, 0x8c020260, 0x8fab006c, 0x4b102b, -0x10400014, 0x307000ff, 0x8f4201d8, 0x24420001, -0xaf4201d8, 0x8f4201d8, 0x8faa007c, 0x8f8200e0, -0x354a0100, 0xafaa007c, 0xafa20010, 0x8f8200e4, -0x24100001, 0x3c040001, 0x248439b4, 0xafa20014, -0x8fa60020, 0x8fa70024, 0x3c050007, 0xc002a03, -0x34a50800, 0x12000010, 0x3c020080, 0x2c21024, -0x1440000e, 0x32c20400, 0x8fab007c, 0x3c020080, -0x34420100, 0x1621024, 0x10400005, 0x0, -0x8f4201fc, 0x24420001, 0xaf4201fc, 0x8f4201fc, -0x100002a0, 0x8fa3006c, 0x32c20400, 0x10400015, -0x34028100, 0x8faa0064, 0x9543000c, 0x14620012, -0x3c020100, 0x240b0200, 0xa7ab008e, 0x9542000e, -0x8d430008, 0x8d440004, 0x8d450000, 0x8faa006c, -0x8fab0064, 0x254afffc, 0xafaa006c, 0xa7a20086, -0xad63000c, 0xad640008, 0xad650004, 0x256b0004, -0xafab0064, 0x3c020100, 0x2c21024, 0x10400004, -0x0, 0x8faa006c, 0x254a0004, 0xafaa006c, -0x8f4200bc, 0x5040000a, 0xafa00074, 0x8fab006c, -0x4b102b, 0x50400006, 0xafa00074, 0x8f4200bc, -0x1621023, 0xafa20074, 0x8f4a00bc, 0xafaa006c, -0x8f420080, 0x8fab006c, 0x4b102b, 0x10400056, -0x32c28000, 0x1040005e, 0x240a0003, 0x32c21000, -0x1040005b, 0xafaa005c, 0x10000058, 0x240b0004, -0x8f420340, 0x2403ffbf, 0x283a024, 0x24420001, -0xaf420340, 0x1000023f, 0x8f420340, 0x2c2b025, -0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, -0x248439e4, 0x26620001, 0xafa20014, 0xafa30010, -0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, -0x34a52250, 0x1000022f, 0x0, 0x2c2b025, -0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, -0x248439e4, 0x24020002, 0xafa20014, 0xafa30010, -0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, -0x34a52450, 0x1000021f, 0x0, 0x8ea20000, -0x8ea30004, 0x3c040001, 0x248439fc, 0xafb00010, -0xafbe0014, 0x8ea70018, 0x34a52800, 0xc002a03, -0x603021, 0x10000213, 0x0, 0xa6b1000a, -0x8f820124, 0x3c040001, 0x24843a04, 0xafbe0014, -0xafa20010, 0x8f460044, 0x8f870120, 0x3c050007, -0xc002a03, 0x34a53000, 0x10000206, 0x0, -0xa6b1000a, 0xa6b2000e, 0x8f820124, 0x3c040001, -0x24843a10, 0xafbe0014, 0xafa20010, 0x8f460044, -0x8f870120, 0x3c050007, 0xc002a03, 0x34a53200, -0x100001f8, 0x0, 0x8f420084, 0x8faa006c, -0x4a102b, 0x14400007, 0x3c020001, 0x2c21024, -0x10400004, 0x0, 0x240b0002, 0xafab005c, -0x8faa006c, 0x1140020b, 0x27ab0020, 0xafab00a4, -0x3c0a001f, 0x354affff, 0xafaa009c, 0x8fab005c, -0x240a0001, 0x156a0021, 0x24020002, 0x8f430054, -0x8f420050, 0x1062000b, 0x274b0054, 0x8f5e0054, -0x3403ecc0, 0xafab004c, 0x27c20001, 0x304201ff, -0xafa20054, 0x1e1140, 0x431021, 0x1000006b, +0x27bd0058, 0x3e00008, 0x0, 0x8f8400e0, +0x8f8800c4, 0x8f8300e8, 0x2402fff8, 0x823824, +0xe32023, 0x2c821000, 0x50400001, 0x24841000, +0x420c2, 0x801821, 0x8f440248, 0x8f45024c, +0x1021, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xaf440248, 0xaf45024c, 0x8f8300c8, +0x8f42013c, 0x1032023, 0x82102b, 0x14400004, +0x801821, 0x8f42013c, 0x822021, 0x801821, +0x8f440240, 0x8f450244, 0x1021, 0xa32821, +0xa3302b, 0x822021, 0x862021, 0xaf440240, +0xaf450244, 0xaf8800c8, 0xaf8700e4, 0xaf8700e8, +0x3e00008, 0x0, 0x27bdff30, 0x240a0001, +0xafbf00c8, 0xafbe00c4, 0xafb500c0, 0xafb300bc, +0xafb200b8, 0xafb100b4, 0xafb000b0, 0xa3a00097, +0xafa00044, 0xafaa005c, 0x934205b5, 0xa7a0008e, +0x1040000a, 0xa7a00086, 0x8f4b00c4, 0xafab0064, +0x8f4a00c0, 0xafaa006c, 0x8f4b00cc, 0xafab0074, +0x8f4a00c8, 0x10000129, 0xafaa007c, 0x8f420114, +0x40f809, 0x0, 0x403021, 0x10c0033f, +0x0, 0x8cc20000, 0x8cc30004, 0xafa20020, +0xafa30024, 0x8fab0024, 0x8faa0020, 0x3162ffff, +0x2442fffc, 0xafa2006c, 0x3c020006, 0x2c21024, +0xafab007c, 0x14400015, 0xafaa0064, 0x91420000, +0x30420001, 0x10400011, 0x2402ffff, 0x8d430000, +0x14620004, 0x3402ffff, 0x95430004, 0x1062000b, +0x0, 0xc00233b, 0x8fa40064, 0x304200ff, +0x14400006, 0x0, 0x8f420118, 0x40f809, +0x0, 0x1000031d, 0x0, 0x8fa20024, +0x3c03ffbf, 0x3463ffff, 0x431024, 0x3c03ffff, +0x431824, 0x14600003, 0xafa20024, 0x10000040, +0x1821, 0x3c020080, 0x621024, 0x10400007, +0x0, 0x8f42037c, 0x24420001, 0xaf42037c, +0x8f42037c, 0x10000036, 0x24030001, 0x8f420200, +0x24420001, 0xaf420200, 0x8f420200, 0x3c020001, +0x621024, 0x10400006, 0x3c020002, 0x8f4201b4, +0x24420001, 0xaf4201b4, 0x8f4201b4, 0x3c020002, +0x621024, 0x10400006, 0x3c020004, 0x8f42036c, +0x24420001, 0xaf42036c, 0x8f42036c, 0x3c020004, +0x621024, 0x10400006, 0x3c020008, 0x8f420370, +0x24420001, 0xaf420370, 0x8f420370, 0x3c020008, +0x621024, 0x10400006, 0x3c020010, 0x8f420374, +0x24420001, 0xaf420374, 0x8f420374, 0x3c020010, +0x621024, 0x10400006, 0x3c020020, 0x8f4201b0, +0x24420001, 0xaf4201b0, 0x8f4201b0, 0x3c020020, +0x621024, 0x10400006, 0x24030001, 0x8f420378, +0x24420001, 0xaf420378, 0x8f420378, 0x24030001, +0x8c020260, 0x8fab006c, 0x4b102b, 0x10400014, +0x307000ff, 0x8f4201d8, 0x24420001, 0xaf4201d8, +0x8f4201d8, 0x8faa007c, 0x8f8200e0, 0x354a0100, +0xafaa007c, 0xafa20010, 0x8f8200e4, 0x24100001, +0x3c040001, 0x24843914, 0xafa20014, 0x8fa60020, +0x8fa70024, 0x3c050007, 0xc0029bb, 0x34a50800, +0x12000010, 0x3c020080, 0x2c21024, 0x1440000e, +0x32c20400, 0x8fab007c, 0x3c020080, 0x34420100, +0x1621024, 0x10400005, 0x0, 0x8f4201fc, +0x24420001, 0xaf4201fc, 0x8f4201fc, 0x100002a0, +0x8fa3006c, 0x32c20400, 0x10400015, 0x34028100, +0x8faa0064, 0x9543000c, 0x14620012, 0x3c020100, +0x240b0200, 0xa7ab008e, 0x9542000e, 0x8d430008, +0x8d440004, 0x8d450000, 0x8faa006c, 0x8fab0064, +0x254afffc, 0xafaa006c, 0xa7a20086, 0xad63000c, +0xad640008, 0xad650004, 0x256b0004, 0xafab0064, +0x3c020100, 0x2c21024, 0x10400004, 0x0, +0x8faa006c, 0x254a0004, 0xafaa006c, 0x8f4200bc, +0x5040000a, 0xafa00074, 0x8fab006c, 0x4b102b, +0x50400006, 0xafa00074, 0x8f4200bc, 0x1621023, +0xafa20074, 0x8f4a00bc, 0xafaa006c, 0x8f420080, +0x8fab006c, 0x4b102b, 0x10400056, 0x32c28000, +0x1040005e, 0x240a0003, 0x32c21000, 0x1040005b, +0xafaa005c, 0x10000058, 0x240b0004, 0x8f420340, +0x2403ffbf, 0x283a024, 0x24420001, 0xaf420340, +0x1000023f, 0x8f420340, 0x2c2b025, 0x2402ffbf, +0x282a024, 0x8f830128, 0x3c040001, 0x24843944, +0x26620001, 0xafa20014, 0xafa30010, 0x8f860120, +0x8f870124, 0x3c050007, 0xc0029bb, 0x34a52250, +0x1000022f, 0x0, 0x2c2b025, 0x2402ffbf, +0x282a024, 0x8f830128, 0x3c040001, 0x24843944, +0x24020002, 0xafa20014, 0xafa30010, 0x8f860120, +0x8f870124, 0x3c050007, 0xc0029bb, 0x34a52450, +0x1000021f, 0x0, 0x8ea20000, 0x8ea30004, +0x3c040001, 0x2484395c, 0xafb00010, 0xafbe0014, +0x8ea70018, 0x34a52800, 0xc0029bb, 0x603021, +0x10000213, 0x0, 0xa6b1000a, 0x8f820124, +0x3c040001, 0x24843964, 0xafbe0014, 0xafa20010, +0x8f460044, 0x8f870120, 0x3c050007, 0xc0029bb, +0x34a53000, 0x10000206, 0x0, 0xa6b1000a, +0xa6b2000e, 0x8f820124, 0x3c040001, 0x24843970, +0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120, +0x3c050007, 0xc0029bb, 0x34a53200, 0x100001f8, +0x0, 0x8f420084, 0x8faa006c, 0x4a102b, +0x14400007, 0x3c020001, 0x2c21024, 0x10400004, +0x0, 0x240b0002, 0xafab005c, 0x8faa006c, +0x1140020b, 0x27ab0020, 0xafab00a4, 0x3c0a001f, +0x354affff, 0xafaa009c, 0x8fab005c, 0x240a0001, +0x156a0021, 0x24020002, 0x8f430054, 0x8f420050, +0x1062000b, 0x274b0054, 0x8f5e0054, 0x3403ecc0, +0xafab004c, 0x27c20001, 0x304201ff, 0xafa20054, +0x1e1140, 0x431021, 0x1000006b, 0x2e2a821, +0x8f420044, 0x8faa006c, 0x3c040001, 0x24843920, +0xafaa0014, 0xafa20010, 0x8f460054, 0x8f470050, +0x3c050007, 0xc0029bb, 0x34a51300, 0x8f430340, +0x2402ffbf, 0x282a024, 0x24630001, 0xaf430340, +0x100001c3, 0x8f420340, 0x1562001d, 0x0, +0x8f430074, 0x8f420070, 0x1062000a, 0x274a0074, +0x8f5e0074, 0xafaa004c, 0x27c20001, 0x304203ff, +0xafa20054, 0x1e1140, 0x24426cc0, 0x1000004a, +0x2e2a821, 0x8f420044, 0x8fab006c, 0x3c040001, +0x2484392c, 0x3c050007, 0xafab0014, 0xafa20010, +0x8f460074, 0x8f470070, 0x34a51500, 0x240a0001, +0xc0029bb, 0xafaa005c, 0x1000ffc3, 0x0, +0x8f430064, 0x8f420060, 0x1062001a, 0x274b0064, +0x8f5e0064, 0x8faa005c, 0xafab004c, 0x27c20001, +0x304200ff, 0xafa20054, 0x24020004, 0x1542000e, +0x1e1140, 0x1e1180, 0x24420cc0, 0x2e21021, +0xafa20044, 0x9442002a, 0x8fab0044, 0x8faa006c, +0x4a102b, 0x10400024, 0x25750020, 0x240b0001, +0x10000021, 0xa3ab0097, 0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044, 0x8faa006c, 0x3c040001, -0x248439c0, 0xafaa0014, 0xafa20010, 0x8f460054, -0x8f470050, 0x3c050007, 0xc002a03, 0x34a51300, -0x8f430340, 0x2402ffbf, 0x282a024, 0x24630001, -0xaf430340, 0x100001c3, 0x8f420340, 0x1562001d, -0x0, 0x8f430074, 0x8f420070, 0x1062000a, -0x274a0074, 0x8f5e0074, 0xafaa004c, 0x27c20001, -0x304203ff, 0xafa20054, 0x1e1140, 0x24426cc0, -0x1000004a, 0x2e2a821, 0x8f420044, 0x8fab006c, -0x3c040001, 0x248439cc, 0x3c050007, 0xafab0014, -0xafa20010, 0x8f460074, 0x8f470070, 0x34a51500, -0x240a0001, 0xc002a03, 0xafaa005c, 0x1000ffc3, -0x0, 0x8f430064, 0x8f420060, 0x1062001a, -0x274b0064, 0x8f5e0064, 0x8faa005c, 0xafab004c, -0x27c20001, 0x304200ff, 0xafa20054, 0x24020004, -0x1542000e, 0x1e1140, 0x1e1180, 0x24420cc0, -0x2e21021, 0xafa20044, 0x9442002a, 0x8fab0044, -0x8faa006c, 0x4a102b, 0x10400024, 0x25750020, -0x240b0001, 0x10000021, 0xa3ab0097, 0x24424cc0, -0x1000001e, 0x2e2a821, 0x8f420044, 0x8faa006c, -0x3c040001, 0x248439d8, 0xafaa0014, 0xafa20010, -0x8f460064, 0x8f470060, 0x3c050007, 0xc002a03, -0x34a51800, 0x3c020008, 0x2c21024, 0x1440ff34, -0x0, 0x8f420360, 0x240b0001, 0xafab005c, -0x24420001, 0xaf420360, 0x1000ff90, 0x8f420360, -0x27a30036, 0x131040, 0x621821, 0x94620000, -0x441021, 0x10000020, 0xa4620000, 0x8faa0064, -0xaeaa0018, 0x93a20097, 0x10400072, 0x9821, -0x8fab0044, 0x8fa4006c, 0x8fa300a4, 0x25620020, -0xafa20028, 0x25620008, 0xafa20030, 0x25620010, -0xafab002c, 0xafa20034, 0x9562002a, 0xa7a20038, -0x95620018, 0xa7a2003a, 0x9562001a, 0xa7a2003c, -0x9562001c, 0xa7a2003e, 0x94620018, 0x24630002, -0x822023, 0x1880ffde, 0x26730001, 0x2e620004, -0x1440fff9, 0x0, 0x8f4200fc, 0x26650001, -0xa2102a, 0x1440002b, 0x24030001, 0x8f83012c, -0x10600023, 0x0, 0x8f820124, 0x431023, -0x22143, 0x58800001, 0x24840040, 0x8f820128, -0x431023, 0x21943, 0x58600001, 0x24630040, -0x64102a, 0x54400001, 0x602021, 0xaf4400fc, -0x8f4200fc, 0xa2102a, 0x10400011, 0x24030001, -0x10000015, 0x306200ff, 0x8faa0064, 0x96070018, -0xafaa0010, 0x8e220008, 0x3c040001, 0x248439f0, -0x8c430004, 0x8c420000, 0x34a52400, 0x2403021, -0xc002a03, 0xafa30014, 0x1000002b, 0x0, -0x8f420324, 0x1821, 0x24420001, 0xaf420324, -0x8f420324, 0x306200ff, 0x5040fedc, 0x3c020800, -0x12600021, 0x9021, 0x8fb100a4, 0x2208021, -0x8e220008, 0x96070018, 0x8fa60064, 0x8c440000, -0x8c450004, 0x240b0001, 0xafab0010, 0xafbe0014, -0x8f420008, 0xafa20018, 0x8f42010c, 0x40f809, -0x0, 0x1040ffd8, 0x3c050007, 0x96020018, -0x8faa0064, 0x8fab009c, 0x1425021, 0x16a102b, -0x10400004, 0xafaa0064, 0x8f42013c, 0x1425023, -0xafaa0064, 0x26100002, 0x26520001, 0x253102b, -0x1440ffe3, 0x26310004, 0x8fb0006c, 0x10000036, -0x97b10038, 0x8f4200fc, 0x24050002, 0xa2102a, -0x1440001b, 0x24030001, 0x8f83012c, 0x10600013, +0x24843938, 0xafaa0014, 0xafa20010, 0x8f460064, +0x8f470060, 0x3c050007, 0xc0029bb, 0x34a51800, +0x3c020008, 0x2c21024, 0x1440ff34, 0x0, +0x8f420360, 0x240b0001, 0xafab005c, 0x24420001, +0xaf420360, 0x1000ff90, 0x8f420360, 0x27a30036, +0x131040, 0x621821, 0x94620000, 0x441021, +0x10000020, 0xa4620000, 0x8faa0064, 0xaeaa0018, +0x93a20097, 0x10400072, 0x9821, 0x8fab0044, +0x8fa4006c, 0x8fa300a4, 0x25620020, 0xafa20028, +0x25620008, 0xafa20030, 0x25620010, 0xafab002c, +0xafa20034, 0x9562002a, 0xa7a20038, 0x95620018, +0xa7a2003a, 0x9562001a, 0xa7a2003c, 0x9562001c, +0xa7a2003e, 0x94620018, 0x24630002, 0x822023, +0x1880ffde, 0x26730001, 0x2e620004, 0x1440fff9, +0x0, 0x8f4200fc, 0x26650001, 0xa2102a, +0x1440002b, 0x24030001, 0x8f83012c, 0x10600023, 0x0, 0x8f820124, 0x431023, 0x22143, 0x58800001, 0x24840040, 0x8f820128, 0x431023, 0x21943, 0x58600001, 0x24630040, 0x64102a, 0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc, -0xa2102a, 0x14400006, 0x24030001, 0x8f420324, +0xa2102a, 0x10400011, 0x24030001, 0x10000015, +0x306200ff, 0x8faa0064, 0x96070018, 0xafaa0010, +0x8e220008, 0x3c040001, 0x24843950, 0x8c430004, +0x8c420000, 0x34a52400, 0x2403021, 0xc0029bb, +0xafa30014, 0x1000002b, 0x0, 0x8f420324, 0x1821, 0x24420001, 0xaf420324, 0x8f420324, -0x306200ff, 0x1040fea5, 0x3c020800, 0x96b1000a, -0x8fb0006c, 0x3223ffff, 0x70102b, 0x54400001, -0x608021, 0x8ea40000, 0x8ea50004, 0x240a0001, -0xafaa0010, 0xafbe0014, 0x8f420008, 0x8fa60064, -0xafa20018, 0x8f42010c, 0x40f809, 0x2003821, -0x1040fea2, 0x3c050007, 0x96a3000e, 0x97ab008e, -0x11600007, 0x609021, 0x934205b5, 0x14400004, -0x0, 0x97aa0086, 0x6b1825, 0xa6aa0016, -0x8fab007c, 0x3c02ffff, 0x1621024, 0x10400003, -0xb1402, 0x34630400, 0xa6a20014, 0x8faa006c, -0x560a0072, 0xa6a3000e, 0x34620004, 0xa6a2000e, -0x8fab0074, 0x14b1021, 0xa6a2000a, 0x8f430044, +0x306200ff, 0x5040fedc, 0x3c020800, 0x12600021, +0x9021, 0x8fb100a4, 0x2208021, 0x8e220008, +0x96070018, 0x8fa60064, 0x8c440000, 0x8c450004, +0x240b0001, 0xafab0010, 0xafbe0014, 0x8f420008, +0xafa20018, 0x8f42010c, 0x40f809, 0x0, +0x1040ffd8, 0x3c050007, 0x96020018, 0x8faa0064, +0x8fab009c, 0x1425021, 0x16a102b, 0x10400004, +0xafaa0064, 0x8f42013c, 0x1425023, 0xafaa0064, +0x26100002, 0x26520001, 0x253102b, 0x1440ffe3, +0x26310004, 0x8fb0006c, 0x10000036, 0x97b10038, +0x8f4200fc, 0x24050002, 0xa2102a, 0x1440001b, +0x24030001, 0x8f83012c, 0x10600013, 0x0, +0x8f820124, 0x431023, 0x22143, 0x58800001, +0x24840040, 0x8f820128, 0x431023, 0x21943, +0x58600001, 0x24630040, 0x64102a, 0x54400001, +0x602021, 0xaf4400fc, 0x8f4200fc, 0xa2102a, +0x14400006, 0x24030001, 0x8f420324, 0x1821, +0x24420001, 0xaf420324, 0x8f420324, 0x306200ff, +0x1040fea5, 0x3c020800, 0x96b1000a, 0x8fb0006c, +0x3223ffff, 0x70102b, 0x54400001, 0x608021, +0x8ea40000, 0x8ea50004, 0x240a0001, 0xafaa0010, +0xafbe0014, 0x8f420008, 0x8fa60064, 0xafa20018, +0x8f42010c, 0x40f809, 0x2003821, 0x1040fea2, +0x3c050007, 0x96a3000e, 0x97ab008e, 0x11600007, +0x609021, 0x934205b5, 0x14400004, 0x0, +0x97aa0086, 0x6b1825, 0xa6aa0016, 0x8fab007c, +0x3c02ffff, 0x1621024, 0x10400003, 0xb1402, +0x34630400, 0xa6a20014, 0x8faa006c, 0x560a0072, +0xa6a3000e, 0x34620004, 0xa6a2000e, 0x8fab0074, +0x14b1021, 0xa6a2000a, 0x8f430044, 0x8f440190, +0x8f450194, 0x34028000, 0xafa20010, 0x8f420044, +0x2a03021, 0x24070020, 0xafa20014, 0x8f42000c, +0x31940, 0x604821, 0xafa20018, 0x8f42010c, +0x4021, 0xa92821, 0xa9182b, 0x882021, +0x40f809, 0x832021, 0x5040fe7f, 0xa6b2000e, +0x8f420358, 0xafa0006c, 0xa34005b5, 0x2442ffff, +0xaf420358, 0x8faa005c, 0x240b0001, 0x8f420358, +0x154b0006, 0x24020002, 0x8f42034c, 0x2442ffff, +0xaf42034c, 0x1000000c, 0x8f42034c, 0x15420006, +0x0, 0x8f420354, 0x2442ffff, 0xaf420354, +0x10000005, 0x8f420354, 0x8f420350, 0x2442ffff, +0xaf420350, 0x8f420350, 0x8faa0054, 0x8fab004c, +0xad6a0000, 0x8f420044, 0x8f440088, 0x8f430078, +0x24420001, 0x441024, 0x24630001, 0xaf420044, +0xaf430078, 0x8c020240, 0x62182b, 0x14600065, +0x24070008, 0x8f440158, 0x8f45015c, 0x8f430044, +0x8f48000c, 0x8f860120, 0x24020040, 0xafa20010, +0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, +0x24c6001c, 0x14400011, 0x240b0001, 0x3c010001, +0x370821, 0xa02b40f2, 0x8f820124, 0xafa20010, +0x8f820128, 0x3c040001, 0x2484390c, 0xafa20014, +0x8f460044, 0x8f870120, 0x3c050009, 0xc0029bb, +0x34a51300, 0x1000000b, 0x0, 0x8f4202f4, +0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044, +0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2, +0xaf400078, 0x8f420308, 0x24420001, 0xaf420308, +0x10000038, 0x8f420308, 0xa6b0000a, 0x8f430044, 0x8f440190, 0x8f450194, 0x34028000, 0xafa20010, 0x8f420044, 0x2a03021, 0x24070020, 0xafa20014, 0x8f42000c, 0x31940, 0x604821, 0xafa20018, 0x8f42010c, 0x4021, 0xa92821, 0xa9182b, -0x882021, 0x40f809, 0x832021, 0x5040fe7f, -0xa6b2000e, 0x8f420358, 0xafa0006c, 0xa34005b5, -0x2442ffff, 0xaf420358, 0x8faa005c, 0x240b0001, -0x8f420358, 0x154b0006, 0x24020002, 0x8f42034c, -0x2442ffff, 0xaf42034c, 0x1000000c, 0x8f42034c, -0x15420006, 0x0, 0x8f420354, 0x2442ffff, -0xaf420354, 0x10000005, 0x8f420354, 0x8f420350, -0x2442ffff, 0xaf420350, 0x8f420350, 0x8faa0054, -0x8fab004c, 0xad6a0000, 0x8f420044, 0x8f440088, -0x8f430078, 0x24420001, 0x441024, 0x24630001, -0xaf420044, 0xaf430078, 0x8c020240, 0x62182b, -0x14600065, 0x24070008, 0x8f440158, 0x8f45015c, -0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040, -0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, -0x40f809, 0x24c6001c, 0x14400011, 0x240b0001, -0x3c010001, 0x370821, 0xa02b40f2, 0x8f820124, -0xafa20010, 0x8f820128, 0x3c040001, 0x248439ac, -0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009, -0xc002a03, 0x34a51300, 0x1000000b, 0x0, -0x8f4202f4, 0x24420001, 0xaf4202f4, 0x8f4202f4, -0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, -0xa02040f2, 0xaf400078, 0x8f420308, 0x24420001, -0xaf420308, 0x10000038, 0x8f420308, 0xa6b0000a, -0x8f430044, 0x8f440190, 0x8f450194, 0x34028000, -0xafa20010, 0x8f420044, 0x2a03021, 0x24070020, -0xafa20014, 0x8f42000c, 0x31940, 0x604821, -0xafa20018, 0x8f42010c, 0x4021, 0xa92821, -0xa9182b, 0x882021, 0x40f809, 0x832021, -0x1040fe1f, 0x240a0001, 0xa34a05b5, 0x8fab006c, -0x8faa0064, 0x1705823, 0xafab006c, 0x8fab009c, -0x1505021, 0x16a102b, 0x10400004, 0xafaa0064, -0x8f42013c, 0x1425023, 0xafaa0064, 0x8f420358, -0x2442ffff, 0xaf420358, 0x8f420358, 0x8f42034c, -0x2442ffff, 0xaf42034c, 0x8fab0054, 0x8faa004c, -0x8f42034c, 0xad4b0000, 0x8f420044, 0x8f440088, -0x8f430078, 0x24420001, 0x441024, 0x24630001, -0xaf420044, 0xaf430078, 0x8faa006c, 0x1540fe1b, -0x0, 0x8fab006c, 0x1160001e, 0x0, -0x934205b5, 0x10400009, 0x0, 0x8faa0064, -0xaf4a00c4, 0xaf4b00c0, 0x8fab007c, 0xaf4b00c8, -0x8faa0074, 0x1000000e, 0xaf4a00cc, 0x97ab008e, -0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c, -0xa443000c, 0x97aa0086, 0x8c440004, 0x8c450008, -0xa44a000e, 0xac440000, 0xac450004, 0xac460008, -0x8f42033c, 0x24420001, 0xaf42033c, 0x10000010, -0x8f42033c, 0x8fab007c, 0x3164ffff, 0x2484fffc, -0x801821, 0x8f440240, 0x8f450244, 0x8f460118, -0x1021, 0xa32821, 0xa3382b, 0x822021, -0x872021, 0xaf440240, 0xc0f809, 0xaf450244, -0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0, 0x8fb300bc, -0x8fb200b8, 0x8fb100b4, 0x8fb000b0, 0x3e00008, -0x27bd00d0, 0x3e00008, 0x0, 0x27bdff38, -0x240b0001, 0xafbf00c0, 0xafbe00bc, 0xafb500b8, -0xafb300b4, 0xafb200b0, 0xafb100ac, 0xafb000a8, -0xa3a00087, 0xafa00044, 0xafab005c, 0x934205b5, -0xa7a00076, 0x10400007, 0xa7a0007e, 0x8f4c00c0, -0xafac0064, 0x8f4b00c8, 0x8f5e00c4, 0x10000129, -0xafab006c, 0x8f420114, 0x40f809, 0x27a40020, -0x304200ff, 0x1040029a, 0x0, 0x8fac0024, -0x8fbe0020, 0x3182ffff, 0x2442fffc, 0xafa20064, -0x3c020006, 0x2c21024, 0x14400015, 0xafac006c, -0x93c20000, 0x30420001, 0x10400011, 0x2402ffff, -0x8fc30000, 0x14620004, 0x3402ffff, 0x97c30004, -0x1062000b, 0x0, 0xc002343, 0x3c02021, -0x304200ff, 0x14400006, 0x0, 0x8f420118, -0x40f809, 0x0, 0x1000027d, 0x0, -0x8fa20024, 0x3c03ffbf, 0x3463ffff, 0x431024, -0x3c03ffff, 0x431824, 0x14600003, 0xafa20024, -0x10000040, 0x8021, 0x3c020080, 0x621024, -0x10400007, 0x0, 0x8f42037c, 0x24420001, -0xaf42037c, 0x8f42037c, 0x10000036, 0x24100001, -0x8f420200, 0x24420001, 0xaf420200, 0x8f420200, -0x3c020001, 0x621024, 0x10400006, 0x3c020002, -0x8f4201b4, 0x24420001, 0xaf4201b4, 0x8f4201b4, -0x3c020002, 0x621024, 0x10400006, 0x3c020004, -0x8f42036c, 0x24420001, 0xaf42036c, 0x8f42036c, -0x3c020004, 0x621024, 0x10400006, 0x3c020008, -0x8f420370, 0x24420001, 0xaf420370, 0x8f420370, -0x3c020008, 0x621024, 0x10400006, 0x3c020010, -0x8f420374, 0x24420001, 0xaf420374, 0x8f420374, -0x3c020010, 0x621024, 0x10400006, 0x3c020020, -0x8f4201b0, 0x24420001, 0xaf4201b0, 0x8f4201b0, -0x3c020020, 0x621024, 0x10400006, 0x24100001, -0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, -0x24100001, 0x8c020260, 0x8fab0064, 0x4b102b, -0x10400015, 0x320200ff, 0x8f4201d8, 0x24420001, -0xaf4201d8, 0x8f4201d8, 0x8fac006c, 0x8f8200e0, -0x358c0100, 0xafac006c, 0xafa20010, 0x8f8200e4, -0x24100001, 0x3c040001, 0x248439b4, 0xafa20014, -0x8fa60020, 0x8fa70024, 0x3c050007, 0xc002a03, -0x34a53600, 0x320200ff, 0x10400010, 0x3c020080, -0x2c21024, 0x1440000e, 0x32c20400, 0x8fab006c, -0x3c020080, 0x34420100, 0x1621024, 0x10400005, -0x0, 0x8f4201fc, 0x24420001, 0xaf4201fc, -0x8f4201fc, 0x100001ff, 0x8fa30064, 0x32c20400, -0x10400012, 0x34028100, 0x97c3000c, 0x1462000f, -0x0, 0x240c0200, 0xa7ac0076, 0x97c2000e, -0x8fc30008, 0x8fc40004, 0x8fab0064, 0x8fc50000, -0x256bfffc, 0xafab0064, 0xa7a2007e, 0xafc3000c, -0xafc40008, 0xafc50004, 0x27de0004, 0x8fa70064, -0x320200ff, 0x14400031, 0x3c020100, 0x97c3000c, -0x2c6205dd, 0x10400015, 0x2821, 0x32c20800, -0x10400015, 0x24020800, 0x97c30014, 0x14620012, -0x3402aaaa, 0x97c3000e, 0x14620007, 0x2021, -0x97c30010, 0x24020300, 0x14620004, 0x801021, -0x97c20012, 0x2c440001, 0x801021, 0x54400006, -0x24050016, 0x10000004, 0x0, 0x24020800, -0x50620001, 0x2405000e, 0x10a00013, 0x3c52021, -0x24830009, 0x3c02001f, 0x3442ffff, 0x43102b, -0x10400003, 0x0, 0x8f42013c, 0x621823, -0x90620000, 0x38430006, 0x2c630001, 0x38420011, -0x2c420001, 0x621825, 0x10600004, 0x3c020100, -0x94820002, 0x453821, 0x3c020100, 0x2c21024, -0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008, -0x3c050007, 0x3c040001, 0x24843a1c, 0x8fa60064, -0x34a54000, 0xafa00010, 0xc002a03, 0xafa00014, -0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080, -0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000, -0x10400034, 0x240b0003, 0x32c21000, 0x10400031, -0xafab005c, 0x1000002e, 0x240c0004, 0x8f420340, -0x2403ffbf, 0x283a024, 0x24420001, 0xaf420340, -0x10000173, 0x8f420340, 0x3c020800, 0x2c2b025, -0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, -0x248439e4, 0x26620001, 0xafa20014, 0xafa30010, -0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, -0x34a55300, 0x10000162, 0x0, 0x8ea20000, -0x8ea30004, 0x3c040001, 0x248439fc, 0xafb00010, -0xafb10014, 0x8ea70018, 0x34a55900, 0xc002a03, -0x603021, 0x10000156, 0x0, 0x8f420084, -0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001, -0x2c21024, 0x10400004, 0x0, 0x240c0002, -0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020, -0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021, -0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b, -0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c, -0x26220001, 0x304201ff, 0xafa20054, 0x111140, -0x431021, 0x1000006b, 0x2e2a821, 0x8f420044, -0x8fac0064, 0x3c040001, 0x248439c0, 0xafac0014, -0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007, -0xc002a03, 0x34a54300, 0x8f430340, 0x2402ffbf, -0x282a024, 0x24630001, 0xaf430340, 0x10000124, -0x8f420340, 0x156c001d, 0x0, 0x8f430074, -0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074, -0xafab004c, 0x26220001, 0x304203ff, 0xafa20054, -0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821, -0x8f420044, 0x8fac0064, 0x3c040001, 0x248439cc, -0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074, -0x8f470070, 0x34a54500, 0x240b0001, 0xc002a03, -0xafab005c, 0x1000ffc3, 0x0, 0x8f430064, -0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064, -0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff, -0xafa20054, 0x24020004, 0x1562000e, 0x111140, -0x111180, 0x24420cc0, 0x2e21021, 0xafa20044, -0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b, -0x10400024, 0x25950020, 0x240c0001, 0x10000021, -0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821, -0x8f420044, 0x8fab0064, 0x3c040001, 0x248439d8, -0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060, -0x3c050007, 0xc002a03, 0x34a54800, 0x3c020008, -0x2c21024, 0x1440ff61, 0x0, 0x8f420360, -0x240c0001, 0xafac005c, 0x24420001, 0xaf420360, -0x1000ff90, 0x8f420360, 0x27a30036, 0x131040, -0x621821, 0x94620000, 0x441021, 0x1000001f, -0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084, -0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c, -0x25620020, 0xafa20028, 0x25620008, 0xafa20030, -0x25620010, 0xafab002c, 0xafa20034, 0x9562002a, -0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a, -0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018, -0x24630002, 0x822023, 0x1880ffdf, 0x26730001, -0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc, -0x262102a, 0x14400030, 0x24030001, 0x8f83012c, -0x10600028, 0x0, 0x8f820124, 0x431023, -0x22143, 0x58800001, 0x24840040, 0x8f820128, -0x431023, 0x21943, 0x58600001, 0x24630040, -0x64102a, 0x54400001, 0x602021, 0xaf4400fc, -0x8f4200fc, 0x262102a, 0x10400016, 0x24030001, -0x1000001a, 0x306200ff, 0x8fac008c, 0x101040, -0x4c1021, 0x94470018, 0x101080, 0x4c1021, -0xafbe0010, 0x8c420008, 0x3c040001, 0x248439f0, -0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500, -0x2003021, 0xc002a03, 0xafa30014, 0x10000039, -0x0, 0x8f420324, 0x1821, 0x24420001, -0xaf420324, 0x8f420324, 0x306200ff, 0x1040ff06, -0x8021, 0x8f430008, 0x2402fbff, 0x1260002d, -0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c, -0x2669ffff, 0x2209021, 0x8e420008, 0x96270018, -0x8c440000, 0x8c450004, 0x56090004, 0x240b0001, -0x240c0002, 0x10000002, 0xafac0010, 0xafab0010, -0x16000004, 0xafa80014, 0x8f420008, 0x10000002, -0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021, -0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0, -0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2, -0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021, -0x5e102b, 0x10400003, 0x26310002, 0x8f42013c, -0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda, -0x26520004, 0x8fb00064, 0x1000001a, 0x0, -0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001, -0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c, -0x240c0002, 0xafac0010, 0x934305b5, 0xb1700, -0x10600003, 0x2223025, 0x3c020800, 0xc23025, -0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c, -0x3c03021, 0x40f809, 0x2003821, 0x1040fecb, -0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e, -0x934205b5, 0x14400004, 0x0, 0x97ab007e, -0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff, -0x1821024, 0x10400003, 0xc1402, 0x34630400, -0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006, -0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e, -0x1000000d, 0xa34005b5, 0x8fac0064, 0x3c02001f, -0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064, -0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05b5, -0x8f42013c, 0x3c2f023, 0x8fab0054, 0x8fac004c, -0xad8b0000, 0x8fac0064, 0x1580feba, 0x0, -0x8fab0064, 0x1160001b, 0x0, 0x934205b5, -0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0, -0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076, -0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c, -0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008, -0xa44c000e, 0xac440000, 0xac450004, 0xac460008, -0x8f42033c, 0x24420001, 0xaf42033c, 0x10000010, -0x8f42033c, 0x8fab006c, 0x3164ffff, 0x2484fffc, -0x801821, 0x8f440240, 0x8f450244, 0x8f460118, -0x1021, 0xa32821, 0xa3382b, 0x822021, -0x872021, 0xaf440240, 0xc0f809, 0xaf450244, -0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4, -0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008, -0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8, -0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048, -0x10620034, 0x0, 0x8f430048, 0x8f42004c, -0x622023, 0x4820001, 0x24840200, 0x8f430054, -0x8f42004c, 0x43102b, 0x14400004, 0x24020200, -0x8f43004c, 0x10000005, 0x431023, 0x8f420054, -0x8f43004c, 0x431023, 0x2442ffff, 0x405021, -0x8a102a, 0x54400001, 0x805021, 0x8f49004c, -0x8f48004c, 0x8f440178, 0x8f45017c, 0x8f46004c, -0x24071000, 0xafa70010, 0x84140, 0x1001821, -0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014, -0x1021, 0x63140, 0xafa70018, 0xa32821, -0xa3382b, 0x822021, 0x872021, 0x3402ecc0, -0xc23021, 0x8f420108, 0x2e63021, 0x40f809, -0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c, -0x8f420048, 0x14620018, 0x0, 0x8f420000, +0x882021, 0x40f809, 0x832021, 0x1040fe1f, +0x240a0001, 0xa34a05b5, 0x8fab006c, 0x8faa0064, +0x1705823, 0xafab006c, 0x8fab009c, 0x1505021, +0x16a102b, 0x10400004, 0xafaa0064, 0x8f42013c, +0x1425023, 0xafaa0064, 0x8f420358, 0x2442ffff, +0xaf420358, 0x8f420358, 0x8f42034c, 0x2442ffff, +0xaf42034c, 0x8fab0054, 0x8faa004c, 0x8f42034c, +0xad4b0000, 0x8f420044, 0x8f440088, 0x8f430078, +0x24420001, 0x441024, 0x24630001, 0xaf420044, +0xaf430078, 0x8faa006c, 0x1540fe1b, 0x0, +0x8fab006c, 0x1160001e, 0x0, 0x934205b5, +0x10400009, 0x0, 0x8faa0064, 0xaf4a00c4, +0xaf4b00c0, 0x8fab007c, 0xaf4b00c8, 0x8faa0074, +0x1000000e, 0xaf4a00cc, 0x97ab008e, 0x1160000b, +0x34038100, 0x8fa20020, 0x8c46000c, 0xa443000c, +0x97aa0086, 0x8c440004, 0x8c450008, 0xa44a000e, +0xac440000, 0xac450004, 0xac460008, 0x8f42033c, +0x24420001, 0xaf42033c, 0x10000010, 0x8f42033c, +0x8fab007c, 0x3164ffff, 0x2484fffc, 0x801821, +0x8f440240, 0x8f450244, 0x8f460118, 0x1021, +0xa32821, 0xa3382b, 0x822021, 0x872021, +0xaf440240, 0xc0f809, 0xaf450244, 0x8fbf00c8, +0x8fbe00c4, 0x8fb500c0, 0x8fb300bc, 0x8fb200b8, +0x8fb100b4, 0x8fb000b0, 0x3e00008, 0x27bd00d0, +0x3e00008, 0x0, 0x27bdff38, 0x240b0001, +0xafbf00c0, 0xafbe00bc, 0xafb500b8, 0xafb300b4, +0xafb200b0, 0xafb100ac, 0xafb000a8, 0xa3a00087, +0xafa00044, 0xafab005c, 0x934205b5, 0xa7a00076, +0x10400007, 0xa7a0007e, 0x8f4c00c0, 0xafac0064, +0x8f4b00c8, 0x8f5e00c4, 0x1000012d, 0xafab006c, +0x8f420114, 0x40f809, 0x0, 0x403021, +0x10c0029e, 0x0, 0x8cc20000, 0x8cc30004, +0xafa20020, 0xafa30024, 0x8fac0024, 0x8fbe0020, +0x3182ffff, 0x2442fffc, 0xafa20064, 0x3c020006, +0x2c21024, 0x14400015, 0xafac006c, 0x93c20000, +0x30420001, 0x10400011, 0x2402ffff, 0x8fc30000, +0x14620004, 0x3402ffff, 0x97c30004, 0x1062000b, +0x0, 0xc00233b, 0x3c02021, 0x304200ff, +0x14400006, 0x0, 0x8f420118, 0x40f809, +0x0, 0x1000027d, 0x0, 0x8fa20024, +0x3c03ffbf, 0x3463ffff, 0x431024, 0x3c03ffff, +0x431824, 0x14600003, 0xafa20024, 0x10000040, +0x8021, 0x3c020080, 0x621024, 0x10400007, +0x0, 0x8f42037c, 0x24420001, 0xaf42037c, +0x8f42037c, 0x10000036, 0x24100001, 0x8f420200, +0x24420001, 0xaf420200, 0x8f420200, 0x3c020001, +0x621024, 0x10400006, 0x3c020002, 0x8f4201b4, +0x24420001, 0xaf4201b4, 0x8f4201b4, 0x3c020002, +0x621024, 0x10400006, 0x3c020004, 0x8f42036c, +0x24420001, 0xaf42036c, 0x8f42036c, 0x3c020004, +0x621024, 0x10400006, 0x3c020008, 0x8f420370, +0x24420001, 0xaf420370, 0x8f420370, 0x3c020008, +0x621024, 0x10400006, 0x3c020010, 0x8f420374, +0x24420001, 0xaf420374, 0x8f420374, 0x3c020010, +0x621024, 0x10400006, 0x3c020020, 0x8f4201b0, +0x24420001, 0xaf4201b0, 0x8f4201b0, 0x3c020020, +0x621024, 0x10400006, 0x24100001, 0x8f420378, +0x24420001, 0xaf420378, 0x8f420378, 0x24100001, +0x8c020260, 0x8fab0064, 0x4b102b, 0x10400015, +0x320200ff, 0x8f4201d8, 0x24420001, 0xaf4201d8, +0x8f4201d8, 0x8fac006c, 0x8f8200e0, 0x358c0100, +0xafac006c, 0xafa20010, 0x8f8200e4, 0x24100001, +0x3c040001, 0x24843914, 0xafa20014, 0x8fa60020, +0x8fa70024, 0x3c050007, 0xc0029bb, 0x34a53600, +0x320200ff, 0x10400010, 0x3c020080, 0x2c21024, +0x1440000e, 0x32c20400, 0x8fab006c, 0x3c020080, +0x34420100, 0x1621024, 0x10400005, 0x0, +0x8f4201fc, 0x24420001, 0xaf4201fc, 0x8f4201fc, +0x100001ff, 0x8fa30064, 0x32c20400, 0x10400012, +0x34028100, 0x97c3000c, 0x1462000f, 0x0, +0x240c0200, 0xa7ac0076, 0x97c2000e, 0x8fc30008, +0x8fc40004, 0x8fab0064, 0x8fc50000, 0x256bfffc, +0xafab0064, 0xa7a2007e, 0xafc3000c, 0xafc40008, +0xafc50004, 0x27de0004, 0x8fa70064, 0x320200ff, +0x14400031, 0x3c020100, 0x97c3000c, 0x2c6205dd, +0x10400015, 0x2821, 0x32c20800, 0x10400015, +0x24020800, 0x97c30014, 0x14620012, 0x3402aaaa, +0x97c3000e, 0x14620007, 0x2021, 0x97c30010, +0x24020300, 0x14620004, 0x801021, 0x97c20012, +0x2c440001, 0x801021, 0x54400006, 0x24050016, +0x10000004, 0x0, 0x24020800, 0x50620001, +0x2405000e, 0x10a00013, 0x3c52021, 0x24830009, +0x3c02001f, 0x3442ffff, 0x43102b, 0x10400003, +0x0, 0x8f42013c, 0x621823, 0x90620000, +0x38430006, 0x2c630001, 0x38420011, 0x2c420001, +0x621825, 0x10600004, 0x3c020100, 0x94820002, +0x453821, 0x3c020100, 0x2c21024, 0x5040000e, +0xafa70064, 0x8fac0064, 0x10ec0008, 0x3c050007, +0x3c040001, 0x2484397c, 0x8fa60064, 0x34a54000, +0xafa00010, 0xc0029bb, 0xafa00014, 0x8fab0064, +0x256b0004, 0xafab0064, 0x8f420080, 0x8fac0064, +0x4c102b, 0x1040002c, 0x32c28000, 0x10400034, +0x240b0003, 0x32c21000, 0x10400031, 0xafab005c, +0x1000002e, 0x240c0004, 0x8f420340, 0x2403ffbf, +0x283a024, 0x24420001, 0xaf420340, 0x10000173, +0x8f420340, 0x3c020800, 0x2c2b025, 0x2402ffbf, +0x282a024, 0x8f830128, 0x3c040001, 0x24843944, +0x26620001, 0xafa20014, 0xafa30010, 0x8f860120, +0x8f870124, 0x3c050007, 0xc0029bb, 0x34a55300, +0x10000162, 0x0, 0x8ea20000, 0x8ea30004, +0x3c040001, 0x2484395c, 0xafb00010, 0xafb10014, +0x8ea70018, 0x34a55900, 0xc0029bb, 0x603021, +0x10000156, 0x0, 0x8f420084, 0x8fab0064, +0x4b102b, 0x14400007, 0x3c020001, 0x2c21024, +0x10400004, 0x0, 0x240c0002, 0xafac005c, +0x8fab0064, 0x11600166, 0x27ac0020, 0xafac008c, +0x8fab005c, 0x240c0001, 0x556c0021, 0x240c0002, +0x8f430054, 0x8f420050, 0x1062000b, 0x274b0054, +0x8f510054, 0x3403ecc0, 0xafab004c, 0x26220001, +0x304201ff, 0xafa20054, 0x111140, 0x431021, +0x1000006b, 0x2e2a821, 0x8f420044, 0x8fac0064, +0x3c040001, 0x24843920, 0xafac0014, 0xafa20010, +0x8f460054, 0x8f470050, 0x3c050007, 0xc0029bb, +0x34a54300, 0x8f430340, 0x2402ffbf, 0x282a024, +0x24630001, 0xaf430340, 0x10000124, 0x8f420340, +0x156c001d, 0x0, 0x8f430074, 0x8f420070, +0x1062000a, 0x274b0074, 0x8f510074, 0xafab004c, +0x26220001, 0x304203ff, 0xafa20054, 0x111140, +0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044, +0x8fac0064, 0x3c040001, 0x2484392c, 0x3c050007, +0xafac0014, 0xafa20010, 0x8f460074, 0x8f470070, +0x34a54500, 0x240b0001, 0xc0029bb, 0xafab005c, +0x1000ffc3, 0x0, 0x8f430064, 0x8f420060, +0x1062001a, 0x274c0064, 0x8f510064, 0x8fab005c, +0xafac004c, 0x26220001, 0x304200ff, 0xafa20054, +0x24020004, 0x1562000e, 0x111140, 0x111180, +0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a, +0x8fac0044, 0x8fab0064, 0x4b102b, 0x10400024, +0x25950020, 0x240c0001, 0x10000021, 0xa3ac0087, +0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044, +0x8fab0064, 0x3c040001, 0x24843938, 0xafab0014, +0xafa20010, 0x8f460064, 0x8f470060, 0x3c050007, +0xc0029bb, 0x34a54800, 0x3c020008, 0x2c21024, +0x1440ff61, 0x0, 0x8f420360, 0x240c0001, +0xafac005c, 0x24420001, 0xaf420360, 0x1000ff90, +0x8f420360, 0x27a30036, 0x131040, 0x621821, +0x94620000, 0x441021, 0x1000001f, 0xa4620000, +0xaebe0018, 0x93a20087, 0x10400084, 0x9821, +0x8fab0044, 0x8fa40064, 0x8fa3008c, 0x25620020, +0xafa20028, 0x25620008, 0xafa20030, 0x25620010, +0xafab002c, 0xafa20034, 0x9562002a, 0xa7a20038, +0x95620018, 0xa7a2003a, 0x9562001a, 0xa7a2003c, +0x9562001c, 0xa7a2003e, 0x94620018, 0x24630002, +0x822023, 0x1880ffdf, 0x26730001, 0x2e620004, +0x1440fff9, 0x0, 0x8f4200fc, 0x262102a, +0x14400030, 0x24030001, 0x8f83012c, 0x10600028, +0x0, 0x8f820124, 0x431023, 0x22143, +0x58800001, 0x24840040, 0x8f820128, 0x431023, +0x21943, 0x58600001, 0x24630040, 0x64102a, +0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc, +0x262102a, 0x10400016, 0x24030001, 0x1000001a, +0x306200ff, 0x8fac008c, 0x101040, 0x4c1021, +0x94470018, 0x101080, 0x4c1021, 0xafbe0010, +0x8c420008, 0x3c040001, 0x24843950, 0x3c050007, +0x8c430004, 0x8c420000, 0x34a55500, 0x2003021, +0xc0029bb, 0xafa30014, 0x10000039, 0x0, +0x8f420324, 0x1821, 0x24420001, 0xaf420324, +0x8f420324, 0x306200ff, 0x1040ff06, 0x8021, +0x8f430008, 0x2402fbff, 0x1260002d, 0x625024, +0x3c0b4000, 0x22b4025, 0x8fb1008c, 0x2669ffff, +0x2209021, 0x8e420008, 0x96270018, 0x8c440000, +0x8c450004, 0x56090004, 0x240b0001, 0x240c0002, +0x10000002, 0xafac0010, 0xafab0010, 0x16000004, +0xafa80014, 0x8f420008, 0x10000002, 0xafa20018, +0xafaa0018, 0x8f42010c, 0x3c03021, 0xafa80098, +0xafa9009c, 0x40f809, 0xafaa00a0, 0x8fa80098, +0x8fa9009c, 0x8faa00a0, 0x1040ffc2, 0x3c02001f, +0x96230018, 0x3442ffff, 0x3c3f021, 0x5e102b, +0x10400003, 0x26310002, 0x8f42013c, 0x3c2f023, +0x26100001, 0x213102b, 0x1440ffda, 0x26520004, +0x8fb00064, 0x1000001a, 0x0, 0x96a3000a, +0x8fb00064, 0x70102b, 0x54400001, 0x608021, +0x8ea40000, 0x8ea50004, 0x8fab005c, 0x240c0002, +0xafac0010, 0x934305b5, 0xb1700, 0x10600003, +0x2223025, 0x3c020800, 0xc23025, 0xafa60014, +0x8f420008, 0xafa20018, 0x8f42010c, 0x3c03021, +0x40f809, 0x2003821, 0x1040fecb, 0x3c050007, +0x97ac0076, 0x11800007, 0x96a3000e, 0x934205b5, +0x14400004, 0x0, 0x97ab007e, 0x6c1825, +0xa6ab0016, 0x8fac006c, 0x3c02ffff, 0x1821024, +0x10400003, 0xc1402, 0x34630400, 0xa6a20014, +0xa6b0000a, 0x8fab0064, 0x560b0006, 0x3d0f021, +0x34620004, 0xafa00064, 0xa6a2000e, 0x1000000d, +0xa34005b5, 0x8fac0064, 0x3c02001f, 0x3442ffff, +0x5e102b, 0x1906023, 0xafac0064, 0xa6a3000e, +0x240b0001, 0x10400003, 0xa34b05b5, 0x8f42013c, +0x3c2f023, 0x8fab0054, 0x8fac004c, 0xad8b0000, +0x8fac0064, 0x1580feba, 0x0, 0x8fab0064, +0x1160001b, 0x0, 0x934205b5, 0x10400006, +0x0, 0xaf5e00c4, 0xaf4b00c0, 0x8fac006c, +0x1000000e, 0xaf4c00c8, 0x97ab0076, 0x1160000b, +0x34038100, 0x8fa20020, 0x8c46000c, 0xa443000c, +0x97ac007e, 0x8c440004, 0x8c450008, 0xa44c000e, +0xac440000, 0xac450004, 0xac460008, 0x8f42033c, +0x24420001, 0xaf42033c, 0x10000010, 0x8f42033c, +0x8fab006c, 0x3164ffff, 0x2484fffc, 0x801821, +0x8f440240, 0x8f450244, 0x8f460118, 0x1021, +0xa32821, 0xa3382b, 0x822021, 0x872021, +0xaf440240, 0xc0f809, 0xaf450244, 0x8fbf00c0, +0x8fbe00bc, 0x8fb500b8, 0x8fb300b4, 0x8fb200b0, +0x8fb100ac, 0x8fb000a8, 0x3e00008, 0x27bd00c8, +0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, +0xafb00020, 0x8f43005c, 0x8f420058, 0x10620049, +0x0, 0x8f430058, 0x8f42005c, 0x622023, +0x4820001, 0x24840100, 0x8f430064, 0x8f42005c, +0x43102b, 0x14400004, 0x24020100, 0x8f43005c, +0x10000005, 0x431023, 0x8f420064, 0x8f43005c, +0x431023, 0x2442ffff, 0x403821, 0x87102a, +0x54400001, 0x803821, 0x8f42005c, 0x471021, +0x305000ff, 0x32c21000, 0x10400015, 0x24082000, +0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c, +0x73980, 0xafa80010, 0xafb00014, 0x8f480014, +0x94980, 0x1201821, 0x1021, 0xa32821, +0xa3482b, 0x822021, 0x892021, 0x63180, +0xafa80018, 0x8f420108, 0x10000014, 0x24c60cc0, +0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c, +0x73940, 0xafa80010, 0xafb00014, 0x8f480014, +0x94940, 0x1201821, 0x1021, 0xa32821, +0xa3482b, 0x822021, 0x892021, 0x63140, +0xafa80018, 0x8f420108, 0x24c64cc0, 0x40f809, +0x2e63021, 0x54400001, 0xaf50005c, 0x8f43005c, +0x8f420058, 0x14620018, 0x0, 0x8f420000, 0x10400007, 0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x2403fdff, 0x431024, 0xaf820060, +0x8f820060, 0x2403feff, 0x431024, 0xaf820060, 0x8f420000, 0x10400003, 0x0, 0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, 0x3e00008, 0x0, -0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c, -0x8f420058, 0x10620049, 0x0, 0x8f430058, -0x8f42005c, 0x622023, 0x4820001, 0x24840100, -0x8f430064, 0x8f42005c, 0x43102b, 0x14400004, -0x24020100, 0x8f43005c, 0x10000005, 0x431023, -0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff, -0x403821, 0x87102a, 0x54400001, 0x803821, -0x8f42005c, 0x471021, 0x305000ff, 0x32c21000, -0x10400015, 0x24082000, 0x8f49005c, 0x8f440180, -0x8f450184, 0x8f46005c, 0x73980, 0xafa80010, -0xafb00014, 0x8f480014, 0x94980, 0x1201821, -0x1021, 0xa32821, 0xa3482b, 0x822021, -0x892021, 0x63180, 0xafa80018, 0x8f420108, -0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440180, -0x8f450184, 0x8f46005c, 0x73940, 0xafa80010, -0xafb00014, 0x8f480014, 0x94940, 0x1201821, -0x1021, 0xa32821, 0xa3482b, 0x822021, -0x892021, 0x63140, 0xafa80018, 0x8f420108, -0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001, -0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018, -0x0, 0x8f420000, 0x10400007, 0x0, -0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, -0x10000005, 0x0, 0xaf800048, 0x8f820048, -0x1040fffd, 0x0, 0x8f820060, 0x2403feff, -0x431024, 0xaf820060, 0x8f420000, 0x10400003, -0x0, 0x10000002, 0xaf80004c, 0xaf800048, -0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, -0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, -0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033, -0x0, 0x8f430068, 0x8f42006c, 0x622023, -0x4820001, 0x24840400, 0x8f430074, 0x8f42006c, -0x43102b, 0x14400004, 0x24020400, 0x8f43006c, -0x10000005, 0x431023, 0x8f420074, 0x8f43006c, -0x431023, 0x2442ffff, 0x405021, 0x8a102a, -0x54400001, 0x805021, 0x8f49006c, 0x8f48006c, -0x8f440188, 0x8f45018c, 0x8f46006c, 0x24074000, -0xafa70010, 0x84140, 0x1001821, 0x12a4821, -0x313003ff, 0xafb00014, 0x8f470014, 0x1021, -0x63140, 0x24c66cc0, 0xafa70018, 0xa32821, -0xa3382b, 0x822021, 0x872021, 0x8f420108, -0x2e63021, 0x40f809, 0xa3940, 0x54400001, -0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018, -0x0, 0x8f420000, 0x10400007, 0x0, -0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, -0x10000005, 0x0, 0xaf800048, 0x8f820048, -0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff, -0x431024, 0xaf820060, 0x8f420000, 0x10400003, -0x0, 0x10000002, 0xaf80004c, 0xaf800048, -0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, -0x3e00008, 0x0, 0x8f4200fc, 0x3c030001, -0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc, -0x8f850128, 0x2e31021, 0x54820004, 0x24820008, -0x3c020001, 0x34422ec8, 0x2e21021, 0x401821, -0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004, -0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128, -0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004, -0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021, -0x401821, 0x8c620004, 0x21140, 0xa21021, -0xaf820128, 0xac600000, 0x8ca30018, 0x30620070, -0x1040002d, 0x30620020, 0x10400004, 0x3c020010, -0x2c21024, 0x1040000d, 0x0, 0x30620040, -0x10400004, 0x3c020020, 0x2c21024, 0x10400007, -0x0, 0x30620010, 0x1040001f, 0x3c020040, -0x2c21024, 0x1440001c, 0x0, 0x8f820040, -0x30420001, 0x14400008, 0x2021, 0x8c030104, -0x24020001, 0x50620005, 0x24040001, 0x8c020264, -0x10400003, 0x801021, 0x24040001, 0x801021, -0x10400006, 0x0, 0x8f4202fc, 0x24420001, -0xaf4202fc, 0x10000008, 0x8f4202fc, 0x8f820044, -0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, -0xaf4202f8, 0x8f4202f8, 0x3e00008, 0x0, -0x3e00008, 0x0, 0x27bdffa0, 0xafbf0058, -0xafbe0054, 0xafb50050, 0xafb3004c, 0xafb20048, -0xafb10044, 0xafb00040, 0x8f4200fc, 0x24420001, -0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128, -0x8d030018, 0x30620070, 0x1040002e, 0x30620020, +0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43006c, +0x8f420068, 0x10620033, 0x0, 0x8f430068, +0x8f42006c, 0x622023, 0x4820001, 0x24840400, +0x8f430074, 0x8f42006c, 0x43102b, 0x14400004, +0x24020400, 0x8f43006c, 0x10000005, 0x431023, +0x8f420074, 0x8f43006c, 0x431023, 0x2442ffff, +0x405021, 0x8a102a, 0x54400001, 0x805021, +0x8f49006c, 0x8f48006c, 0x8f440188, 0x8f45018c, +0x8f46006c, 0x24074000, 0xafa70010, 0x84140, +0x1001821, 0x12a4821, 0x313003ff, 0xafb00014, +0x8f470014, 0x1021, 0x63140, 0x24c66cc0, +0xafa70018, 0xa32821, 0xa3382b, 0x822021, +0x872021, 0x8f420108, 0x2e63021, 0x40f809, +0xa3940, 0x54400001, 0xaf50006c, 0x8f43006c, +0x8f420068, 0x14620018, 0x0, 0x8f420000, +0x10400007, 0x0, 0xaf80004c, 0x8f82004c, +0x1040fffd, 0x0, 0x10000005, 0x0, +0xaf800048, 0x8f820048, 0x1040fffd, 0x0, +0x8f820060, 0x2403f7ff, 0x431024, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000002, +0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, +0x3e00008, 0x27bd0028, 0x3e00008, 0x0, +0x8f4200fc, 0x3c030001, 0x8f4400f8, 0x346330c8, +0x24420001, 0xaf4200fc, 0x8f850128, 0x2e31021, +0x54820004, 0x24820008, 0x3c020001, 0x34422ec8, +0x2e21021, 0x401821, 0xaf4300f8, 0xac600000, +0x8f4200f4, 0x14620004, 0x3c020001, 0x24a20020, +0x1000000f, 0xaf820128, 0x8f4300f8, 0x344230c8, +0x2e21021, 0x54620004, 0x24620008, 0x3c020001, +0x34422ec8, 0x2e21021, 0x401821, 0x8c620004, +0x21140, 0xa21021, 0xaf820128, 0xac600000, +0x8ca30018, 0x30620070, 0x1040002d, 0x30620020, 0x10400004, 0x3c020010, 0x2c21024, 0x1040000d, 0x0, 0x30620040, 0x10400004, 0x3c020020, 0x2c21024, 0x10400007, 0x0, 0x30620010, -0x10400193, 0x3c020040, 0x2c21024, 0x14400190, +0x1040001f, 0x3c020040, 0x2c21024, 0x1440001c, 0x0, 0x8f820040, 0x30420001, 0x14400008, 0x2021, 0x8c030104, 0x24020001, 0x50620005, 0x24040001, 0x8c020264, 0x10400003, 0x801021, 0x24040001, 0x801021, 0x10400006, 0x0, -0x8f4202fc, 0x24420001, 0xaf4202fc, 0x1000017c, +0x8f4202fc, 0x24420001, 0xaf4202fc, 0x10000008, 0x8f4202fc, 0x8f820044, 0x34420004, 0xaf820044, -0x8f4202f8, 0x24420001, 0xaf4202f8, 0x10000174, -0x8f4202f8, 0x30620002, 0x10400135, 0x3c020800, -0x8d0a001c, 0x1422024, 0xafaa0024, 0xa5702, -0xafaa0034, 0x8faa0024, 0x314affff, 0xafaa0024, -0x950a0016, 0xafaa002c, 0x8faa0034, 0x24020001, -0x15420007, 0x24020002, 0x8faa0024, 0xa1140, -0x3403ecc0, 0x431021, 0x10000014, 0x2e2a821, -0x15420006, 0x24020003, 0x8faa0024, 0xa1140, -0x24426cc0, 0x1000000d, 0x2e2a821, 0x8faa0034, -0x15420006, 0x0, 0x8faa0024, 0xa1140, -0x24424cc0, 0x10000005, 0x2e2a821, 0x8faa0024, -0xa1180, 0x571021, 0x24550ce0, 0x96a2000e, -0x305efffc, 0x30420400, 0x144000c5, 0x8821, -0x10800004, 0x24091000, 0x97b1002e, 0x100000c1, -0x0, 0x8eb30018, 0x9663000c, 0x2c6205dd, +0x8f4202f8, 0x24420001, 0xaf4202f8, 0x8f4202f8, +0x3e00008, 0x0, 0x3e00008, 0x0, +0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb50058, +0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048, +0x8f4200fc, 0x24420001, 0xaf4200fc, 0x8f880128, +0x25020020, 0xaf820128, 0x8d030018, 0x30620070, +0x1040002e, 0x30620020, 0x10400004, 0x3c020010, +0x2c21024, 0x1040000d, 0x0, 0x30620040, +0x10400004, 0x3c020020, 0x2c21024, 0x10400007, +0x0, 0x30620010, 0x104001a6, 0x3c020040, +0x2c21024, 0x144001a3, 0x0, 0x8f820040, +0x30420001, 0x14400008, 0x2021, 0x8c030104, +0x24020001, 0x50620005, 0x24040001, 0x8c020264, +0x10400003, 0x801021, 0x24040001, 0x801021, +0x10400006, 0x0, 0x8f4202fc, 0x24420001, +0xaf4202fc, 0x1000018f, 0x8f4202fc, 0x8f820044, +0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, +0xaf4202f8, 0x10000187, 0x8f4202f8, 0x30620002, +0x10400148, 0x3c020800, 0x8d0a001c, 0x1422024, +0xafaa0024, 0xa5702, 0xafaa0034, 0x8faa0024, +0x314affff, 0xafaa0024, 0x950a0016, 0xafaa002c, +0x8faa0034, 0x24020001, 0x15420007, 0x24020002, +0x8faa0024, 0xa1140, 0x3403ecc0, 0x431021, +0x10000014, 0x2e2a821, 0x15420006, 0x24020003, +0x8faa0024, 0xa1140, 0x24426cc0, 0x1000000d, +0x2e2a821, 0x8faa0034, 0x15420006, 0x0, +0x8faa0024, 0xa1140, 0x24424cc0, 0x10000005, +0x2e2a821, 0x8faa0024, 0xa1180, 0x571021, +0x24550ce0, 0x96a2000e, 0x305efffc, 0x30420400, +0x144000d8, 0x8821, 0x10800004, 0x24091000, +0x97b1002e, 0x100000d4, 0x0, 0x8eb30018, +0x966a000c, 0xa7aa003e, 0x97a3003e, 0x2c6205dd, 0x10400015, 0x2021, 0x32c20800, 0x10400015, 0x24020800, 0x96630014, 0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007, 0x2821, 0x96630010, 0x24020300, 0x14620004, 0xa01021, 0x96620012, 0x2c450001, 0xa01021, 0x54400006, 0x24040016, 0x10000004, 0x0, 0x24020800, 0x50620001, -0x2404000e, 0x108000a2, 0x2649021, 0x92420000, +0x2404000e, 0x108000b3, 0x2649021, 0x92420000, 0x3042000f, 0x28080, 0x32c20100, 0x1040001e, 0x2501821, 0x3c020020, 0x43102b, 0x1440000e, 0x2402021, 0x2821, 0x94820000, 0x24840002, 0xa22821, 0x83102b, 0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821, 0x51c02, 0x30a2ffff, 0x10000009, 0x622821, 0x8f47013c, 0x8f420110, -0x102842, 0x3c060020, 0x40f809, 0xafa80038, -0x3045ffff, 0x8fa80038, 0x50a00001, 0x3405ffff, +0x102842, 0x3c060020, 0x40f809, 0xafa80040, +0x3045ffff, 0x8fa80040, 0x50a00001, 0x3405ffff, 0x10000002, 0x37de0002, 0x2821, 0x32c20080, -0x1040007b, 0xa6a50010, 0x26430009, 0x3c02001f, +0x1040008c, 0xa6a50010, 0x26430009, 0x3c02001f, 0x3442ffff, 0x43102b, 0x10400003, 0x0, 0x8f42013c, 0x621823, 0x90660000, 0x30c200ff, 0x38430006, 0x2c630001, 0x38420011, 0x2c420001, -0x621825, 0x1060006b, 0x24091000, 0x8821, -0x2602021, 0x94820000, 0x24840002, 0x2228821, -0x92102b, 0x1440fffb, 0x111c02, 0x3222ffff, -0x628821, 0x111c02, 0x3222ffff, 0x628821, -0x32c20200, 0x10400003, 0x26440006, 0x1000003e, -0x8021, 0x3c05001f, 0x34a5ffff, 0xa4102b, -0x10400003, 0x0, 0x8f42013c, 0x822023, -0x94820000, 0x30421fff, 0x10400004, 0x2644000c, -0x96420002, 0x10000030, 0x508023, 0x96420002, -0x26430014, 0x508023, 0x3c020020, 0x43102b, -0x1440000a, 0xd08021, 0x9642000c, 0x2028021, -0x9642000e, 0x96430010, 0x96440012, 0x2028021, -0x2038021, 0x10000020, 0x2048021, 0xa4102b, -0x10400003, 0x0, 0x8f42013c, 0x822023, -0x94820000, 0x24840002, 0x2028021, 0xa4102b, -0x10400003, 0x0, 0x8f42013c, 0x822023, -0x94820000, 0x24840002, 0x2028021, 0xa4102b, -0x10400003, 0x0, 0x8f42013c, 0x822023, -0x94820000, 0x24840002, 0x2028021, 0xa4102b, -0x10400003, 0x0, 0x8f42013c, 0x822023, -0x94820000, 0x2028021, 0x3c020100, 0x2c21024, -0x1040000c, 0x33c20004, 0x1040000a, 0x0, -0x9504000e, 0x2642021, 0xc003cf8, 0x2484fffc, -0x3042ffff, 0x2228821, 0x111c02, 0x3222ffff, -0x628821, 0x8faa002c, 0x1518823, 0x111402, -0x2228821, 0x2308821, 0x111402, 0x2228821, -0x3231ffff, 0x52200001, 0x3411ffff, 0x37de0001, -0x24091000, 0x33c20004, 0xa6b10012, 0x10400002, -0xa6be000e, 0x34098000, 0x8f480044, 0x8f440190, -0x8f450194, 0xafa90010, 0x8f490044, 0x84140, -0x1001821, 0xafa90014, 0x8f48000c, 0x2a03021, -0x24070020, 0xafa80018, 0x8f48010c, 0x1021, -0xa32821, 0xa3482b, 0x822021, 0x100f809, -0x892021, 0x1440000c, 0x0, 0x8f820128, -0x8faa0024, 0x3c040001, 0x24843a28, 0xafaa0014, -0xafa20010, 0x8f860124, 0x8f870120, 0x3c050007, -0xc002a03, 0x34a59920, 0x8f420358, 0x2442ffff, -0xaf420358, 0x8f420044, 0x8f430088, 0x24420001, -0x431024, 0xaf420044, 0x8faa0034, 0x8f440358, -0x24020001, 0x15420006, 0x24020002, 0x8f42034c, -0x2442ffff, 0xaf42034c, 0x10000049, 0x8f42034c, -0x15420006, 0x0, 0x8f420354, 0x2442ffff, -0xaf420354, 0x10000042, 0x8f420354, 0x8f420350, -0x2442ffff, 0xaf420350, 0x1000003d, 0x8f420350, -0x30621000, 0x10400005, 0x30628000, 0x8f420078, -0x24420001, 0x10000036, 0xaf420078, 0x10400034, -0x0, 0x8f420078, 0x24420001, 0xaf420078, -0x8c030240, 0x43102b, 0x1440002d, 0x24070008, -0x8f440158, 0x8f45015c, 0x8f430044, 0x8f48000c, -0x8f860120, 0x24020040, 0xafa20010, 0xafa30014, -0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, -0x14400011, 0x24020001, 0x3c010001, 0x370821, -0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x248439ac, 0xafa20014, 0x8f460044, -0x8f870120, 0x3c050009, 0xc002a03, 0x34a51300, -0x1000000b, 0x0, 0x8f4202f4, 0x24420001, -0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, -0x3c010001, 0x370821, 0xa02040f2, 0xaf400078, -0x8f420308, 0x24420001, 0xaf420308, 0x8f420308, -0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, -0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, -0x27bd0060, 0x3e00008, 0x0, 0x8f420130, +0x621825, 0x1060007b, 0x24020800, 0x8821, +0x97a3003e, 0x1462000f, 0x2602021, 0x96710000, +0x96620002, 0x96630004, 0x96640006, 0x2228821, +0x2238821, 0x2248821, 0x96620008, 0x9663000a, +0x9664000c, 0x2228821, 0x2238821, 0x10000007, +0x2248821, 0x94820000, 0x24840002, 0x2228821, +0x92102b, 0x1440fffb, 0x0, 0x111c02, +0x3222ffff, 0x628821, 0x111c02, 0x3222ffff, +0x628821, 0x32c20200, 0x10400003, 0x26440006, +0x1000003e, 0x8021, 0x3c05001f, 0x34a5ffff, +0xa4102b, 0x10400003, 0x0, 0x8f42013c, +0x822023, 0x94820000, 0x30421fff, 0x10400004, +0x2644000c, 0x96420002, 0x10000030, 0x508023, +0x96420002, 0x26430014, 0x508023, 0x3c020020, +0x43102b, 0x1440000a, 0xd08021, 0x9642000c, +0x2028021, 0x9642000e, 0x96430010, 0x96440012, +0x2028021, 0x2038021, 0x10000020, 0x2048021, +0xa4102b, 0x10400003, 0x0, 0x8f42013c, +0x822023, 0x94820000, 0x24840002, 0x2028021, +0xa4102b, 0x10400003, 0x0, 0x8f42013c, +0x822023, 0x94820000, 0x24840002, 0x2028021, +0xa4102b, 0x10400003, 0x0, 0x8f42013c, +0x822023, 0x94820000, 0x24840002, 0x2028021, +0xa4102b, 0x10400003, 0x0, 0x8f42013c, +0x822023, 0x94820000, 0x2028021, 0x3c020100, +0x2c21024, 0x1040000c, 0x33c20004, 0x1040000a, +0x0, 0x9504000e, 0x2642021, 0xc003c24, +0x2484fffc, 0x3042ffff, 0x2228821, 0x111c02, +0x3222ffff, 0x628821, 0x8faa002c, 0x1518823, +0x111402, 0x2228821, 0x2308821, 0x111402, +0x2228821, 0x3231ffff, 0x52200001, 0x3411ffff, +0x37de0001, 0x24091000, 0x33c20004, 0xa6b10012, +0x10400002, 0xa6be000e, 0x34098000, 0x8f480044, +0x8f440190, 0x8f450194, 0xafa90010, 0x8f490044, +0x84140, 0x1001821, 0xafa90014, 0x8f48000c, +0x2a03021, 0x24070020, 0xafa80018, 0x8f48010c, +0x1021, 0xa32821, 0xa3482b, 0x822021, +0x100f809, 0x892021, 0x1440000c, 0x0, +0x8f820128, 0x8faa0024, 0x3c040001, 0x24843988, +0xafaa0014, 0xafa20010, 0x8f860124, 0x8f870120, +0x3c050007, 0xc0029bb, 0x34a59920, 0x8f420358, +0x2442ffff, 0xaf420358, 0x8f420044, 0x8f430088, +0x24420001, 0x431024, 0xaf420044, 0x8faa0034, +0x8f440358, 0x24020001, 0x15420006, 0x24020002, +0x8f42034c, 0x2442ffff, 0xaf42034c, 0x10000049, +0x8f42034c, 0x15420006, 0x0, 0x8f420354, +0x2442ffff, 0xaf420354, 0x10000042, 0x8f420354, +0x8f420350, 0x2442ffff, 0xaf420350, 0x1000003d, +0x8f420350, 0x30621000, 0x10400005, 0x30628000, +0x8f420078, 0x24420001, 0x10000036, 0xaf420078, +0x10400034, 0x0, 0x8f420078, 0x24420001, +0xaf420078, 0x8c030240, 0x43102b, 0x1440002d, +0x24070008, 0x8f440158, 0x8f45015c, 0x8f430044, +0x8f48000c, 0x8f860120, 0x24020040, 0xafa20010, +0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, +0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, +0x370821, 0xa02240f2, 0x8f820124, 0xafa20010, +0x8f820128, 0x3c040001, 0x2484390c, 0xafa20014, +0x8f460044, 0x8f870120, 0x3c050009, 0xc0029bb, +0x34a51300, 0x1000000b, 0x0, 0x8f4202f4, +0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044, +0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2, +0xaf400078, 0x8f420308, 0x24420001, 0xaf420308, +0x8f420308, 0x8fbf0060, 0x8fbe005c, 0x8fb50058, +0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048, +0x3e00008, 0x27bd0068, 0x3e00008, 0x0, +0x0, 0x0, 0x0, 0x8f420130, 0xaf8200c0, 0x8f420130, 0xaf8200c4, 0x8f420130, 0xaf8200c8, 0x8f42012c, 0xaf8200d0, 0x8f42012c, 0xaf8200d4, 0x8f42012c, 0x3e00008, 0xaf8200d8, 0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018, -0xc002a87, 0x24060008, 0x8c020204, 0xc003e1e, +0xc002a3f, 0x24060008, 0x8c020204, 0xc003d4a, 0xaf820210, 0x2021, 0x8c060248, 0x24020004, -0x3c010001, 0xac223e28, 0xc0048a8, 0x24050004, -0x3c020001, 0x8c423e24, 0x30420001, 0x10400007, -0x24020001, 0x3c010001, 0xac223e28, 0x2021, -0x24050001, 0xc0048a8, 0x3c06601b, 0x3c040001, -0x24843af0, 0x8f420144, 0x8f430148, 0x3c050008, +0x3c010001, 0xac223d88, 0xc0047d4, 0x24050004, +0x3c020001, 0x8c423d84, 0x30420001, 0x10400007, +0x24020001, 0x3c010001, 0xac223d88, 0x2021, +0x24050001, 0xc0047d4, 0x3c06601b, 0x3c040001, +0x24843a50, 0x8f420144, 0x8f430148, 0x3c050008, 0x8f46014c, 0x21640, 0x31940, 0x34630403, 0x431025, 0x633c0, 0x461025, 0xaf82021c, 0xafa00010, 0xafa00014, 0x8f86021c, 0x34a50200, -0xc002a03, 0x3821, 0x3c010001, 0xac203e20, -0x3c010001, 0xac203e38, 0x8fbf0018, 0x3e00008, +0xc0029bb, 0x3821, 0x3c010001, 0xac203d80, +0x3c010001, 0xac203d98, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, 0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200, -0x3c040001, 0x24843afc, 0xc002a03, 0x3821, +0x3c040001, 0x24843a5c, 0xc0029bb, 0x3821, 0x8f420400, 0x24420001, 0xaf420400, 0x8f420400, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0xafb00018, 0x8f420394, 0x24420001, 0xaf420394, 0x8f420394, 0x8f900220, -0x8f4303a8, 0x3c020001, 0x8c423e38, 0x3c040001, -0x24843b08, 0x3c050008, 0xafa20014, 0xafa30010, -0x8f4703ac, 0x34a50400, 0xc002a03, 0x2003021, -0x3c024000, 0x2021024, 0x104000e1, 0x3c040100, -0x8f4203ac, 0x24420001, 0xaf4203ac, 0x8f4203ac, -0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, -0x34420004, 0xaf820220, 0x8f8200e0, 0x8f8300c4, -0x3c02001f, 0x3442ffff, 0x24690008, 0x49102b, -0x10400003, 0x0, 0x8f42013c, 0x1224823, -0x8f8700c8, 0x8f840120, 0x8f830124, 0x10000005, -0x5821, 0x8f42012c, 0x62102b, 0x50400001, -0x27634800, 0x1083000d, 0x316200ff, 0x8c620018, -0x2442ffff, 0x2c420002, 0x5040fff6, 0x24630020, -0x8f4203c0, 0x240b0001, 0x24420001, 0xaf4203c0, -0x8f4203c0, 0x8c670008, 0x316200ff, 0x14400078, -0x0, 0x934205b5, 0x14400075, 0x0, -0x8f8500e4, 0x8f8200e0, 0x2403fff8, 0x433024, -0xc51023, 0x218c3, 0x4620001, 0x24630100, -0x8f8a00c4, 0x10600005, 0x24020001, 0x10620009, -0x0, 0x10000021, 0x0, 0x8f4203b0, -0x1403821, 0x24420001, 0xaf4203b0, 0x10000060, +0x8f8200e0, 0xafa20010, 0x8f8200e4, 0xafa20014, +0x8f8600c4, 0x8f8700c8, 0x3c040001, 0x24843a68, +0xc0029bb, 0x2002821, 0x3c044000, 0x2041024, +0x504000ae, 0x3c040100, 0x8f4203ac, 0x24420001, +0xaf4203ac, 0x8f4203ac, 0x8f8700c4, 0x8f8300c8, +0x8f42013c, 0x671823, 0x43102b, 0x10400003, +0x0, 0x8f42013c, 0x621821, 0x10600005, +0x0, 0x8f420140, 0x43102b, 0x10400007, +0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, +0x431024, 0x100000cc, 0x441025, 0x8f820220, +0x3c0308ff, 0x3463ffff, 0x431024, 0x34420004, +0xaf820220, 0x8f8600c8, 0x8f840120, 0x8f830124, +0x10000005, 0x2821, 0x14620002, 0x24620020, +0x27624800, 0x401821, 0x1064000c, 0x30a200ff, +0x8c620018, 0x30420003, 0x1040fff7, 0x27624fe0, +0x8f4203c0, 0x24050001, 0x24420001, 0xaf4203c0, +0x8f4203c0, 0x8c660008, 0x30a200ff, 0x14400058, +0x0, 0x934205b5, 0x14400055, 0x0, +0x8f8700c4, 0x8f8800e0, 0x8f8400e4, 0x2402fff8, +0x1024024, 0x1041023, 0x218c3, 0x4620001, +0x24630200, 0x10600005, 0x24020001, 0x10620009, +0x0, 0x1000001f, 0x0, 0x8f4203b0, +0xe03021, 0x24420001, 0xaf4203b0, 0x10000040, 0x8f4203b0, 0x8f4203b4, 0x24420001, 0xaf4203b4, -0x8ca70000, 0x8f42013c, 0x8f4303b4, 0x1471823, +0x8c860000, 0x8f42013c, 0x8f4303b4, 0xe61823, 0x43102b, 0x10400004, 0x2c62233f, 0x8f42013c, -0x621821, 0x2c62233f, 0x14400051, 0x3c020100, -0xaca20004, 0x8f8200e8, 0x24420008, 0xaf8200e8, -0x8f8200e8, 0x8f8200e4, 0x1403821, 0x24420008, -0xaf8200e4, 0x10000046, 0x8f8200e4, 0x8f4203b8, -0x24420001, 0xaf4203b8, 0x8ca80000, 0x8f42013c, -0x8f4303b8, 0x1092023, 0x44102b, 0x10400003, -0x0, 0x8f42013c, 0x822021, 0x8f420140, -0x44102b, 0x10400003, 0x3c030100, 0x10000034, -0x1003821, 0x8ca20004, 0x431025, 0xaca20004, -0x8f8200e4, 0x24450008, 0xaf8500e4, 0x8f8500e4, -0x10a60025, 0x3c080100, 0x8f4201fc, 0x24420001, -0xaf4201fc, 0x8ca20004, 0x8f4301fc, 0x481024, -0x1440000e, 0x0, 0x8ca30000, 0x8f42013c, -0x692023, 0x44102b, 0x10400003, 0x0, -0x8f42013c, 0x822021, 0x8f420140, 0x44102b, -0x10400006, 0x0, 0x603821, 0x8f420140, -0x44102b, 0x1440000a, 0x0, 0x8ca20004, -0x481025, 0xaca20004, 0x8f8200e4, 0x24450008, -0xaf8500e4, 0x8f8500e4, 0x14a6ffdf, 0x0, -0x14a60005, 0x0, 0x1403821, 0xaf8600e4, -0x10000003, 0xaf8600e8, 0xaf8500e4, 0xaf8500e8, -0x8f8300c8, 0x8f42013c, 0x692023, 0x44102b, -0x10400003, 0x0, 0x8f42013c, 0x822021, -0x8f420140, 0x82102b, 0x50400008, 0x5821, -0x8f42013c, 0xe92023, 0x44102b, 0x10400003, -0x0, 0x8f42013c, 0x822021, 0x8f420140, -0x82102b, 0x10400006, 0x316200ff, 0x1440001b, -0x3c02fdff, 0x934205b5, 0x14400018, 0x3c02fdff, -0xaf8700c8, 0x8f8400c8, 0x8f8300c4, 0x8f42013c, -0x832023, 0x44102b, 0x10400003, 0x0, -0x8f42013c, 0x822021, 0x8f420140, 0x2c830001, -0x44102b, 0x431025, 0x50400008, 0x3c02fdff, -0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, -0x3c034000, 0x10000041, 0x431025, 0x3442ffff, -0x8f4303bc, 0x282a024, 0x24020001, 0xa34205b1, -0x24630001, 0xaf4303bc, 0x10000039, 0x8f4203bc, -0x2041024, 0x1040000e, 0x3c110200, 0x8f420398, -0x24420001, 0xaf420398, 0x8f420398, 0x8f820220, -0x3c0308ff, 0x3463ffff, 0x431024, 0x441025, -0xc003be0, 0xaf820220, 0x10000029, 0x0, -0x2111024, 0x50400008, 0x3c110400, 0x8f42039c, -0x24420001, 0xaf42039c, 0xc003be0, 0x8f42039c, -0x10000019, 0x0, 0x2111024, 0x1040001c, -0x0, 0x8f830224, 0x24021402, 0x14620009, -0x3c050008, 0x3c040001, 0x24843b14, 0xafa00010, -0xafa00014, 0x8f860224, 0x34a50500, 0xc002a03, -0x3821, 0x8f4203a0, 0x24420001, 0xaf4203a0, -0x8f4203a0, 0x8f820220, 0x2002021, 0x34420002, -0xc004640, 0xaf820220, 0x8f820220, 0x3c0308ff, -0x3463ffff, 0x431024, 0x511025, 0xaf820220, -0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008, -0x27bd0028, 0x3e00008, 0x0, 0x3c020001, -0x8c423e38, 0x27bdffb0, 0xafbf0048, 0xafbe0044, -0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, -0x1040000f, 0xafb00030, 0x3c040001, 0x24843b20, -0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, -0x34a50600, 0x24020001, 0x3c010001, 0xac203e38, -0x3c010001, 0xac223e2c, 0xc002a03, 0x3821, -0x3c037fff, 0x8c020268, 0x3463ffff, 0x3c04fdff, -0x431024, 0xac020268, 0x8f420004, 0x3484ffff, -0x30420002, 0x10400092, 0x284a024, 0x3c040600, -0x34842000, 0x8f420004, 0x2821, 0x2403fffd, -0x431024, 0xaf420004, 0xafa40020, 0x8f5e0018, -0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa002c, -0x27c50001, 0x8c020228, 0xa09021, 0x1642000e, -0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, -0x8f42032c, 0x8c020228, 0x3c040001, 0x24843ab8, -0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, -0x1000006d, 0x34a50500, 0xf71021, 0x8fa30020, -0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, -0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, -0x1040001b, 0x9821, 0xe08821, 0x263504c0, -0x8f440168, 0x8f45016c, 0x2201821, 0x240a0004, -0xafaa0010, 0xafb20014, 0x8f48000c, 0x1021, -0x2f53021, 0xafa80018, 0x8f48010c, 0x24070008, -0xa32821, 0xa3482b, 0x822021, 0x100f809, -0x892021, 0x54400006, 0x24130001, 0x8f820054, -0x2021023, 0x2c4203e9, 0x1440ffe9, 0x0, -0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, +0x621821, 0x2c62233f, 0x14400031, 0x0, +0x8f4201fc, 0x24420001, 0xaf4201fc, 0x8f4201fc, +0xe03021, 0x24820008, 0xaf8200e4, 0x10000028, +0xaf8200e8, 0x8f4203b8, 0x24420001, 0xaf4203b8, +0x8f4203b8, 0x8c850000, 0x8f42013c, 0xa71823, +0x43102b, 0x10400003, 0x0, 0x8f42013c, +0x621821, 0x8f420140, 0x43102b, 0x5440000a, +0xa03021, 0x8f4201fc, 0x24420001, 0xaf4201fc, +0x8f4201fc, 0x24820008, 0xaf8200e4, 0x8f8400e4, +0x1488ffec, 0xaf8400e8, 0x1488000d, 0x27623000, +0x14820002, 0x2482fff8, 0x27623ff8, 0x94430006, +0x3c02001f, 0x3442ffff, 0xc33021, 0x46102b, +0x10400003, 0x0, 0x8f42013c, 0xc23023, +0xaf8600c8, 0x8f8300c4, 0x8f42013c, 0xc31823, +0x43102b, 0x10400003, 0x0, 0x8f42013c, +0x621821, 0x10600005, 0x0, 0x8f420140, +0x43102b, 0x50400008, 0x3c02fdff, 0x8f820220, +0x3c0308ff, 0x3463fffb, 0x431024, 0x3c034000, +0x10000041, 0x431025, 0x3442ffff, 0x8f4303bc, +0x282a024, 0x24020001, 0xa34205b1, 0x24630001, +0xaf4303bc, 0x10000039, 0x8f4203bc, 0x2041024, +0x1040000e, 0x3c110200, 0x8f420398, 0x24420001, +0xaf420398, 0x8f420398, 0x8f820220, 0x3c0308ff, +0x3463ffff, 0x431024, 0x441025, 0xc003b0b, +0xaf820220, 0x10000029, 0x0, 0x2111024, +0x50400008, 0x3c110400, 0x8f42039c, 0x24420001, +0xaf42039c, 0xc003b0b, 0x8f42039c, 0x10000019, +0x0, 0x2111024, 0x1040001c, 0x0, +0x8f830224, 0x24021402, 0x14620009, 0x3c050008, +0x3c040001, 0x24843a74, 0xafa00010, 0xafa00014, +0x8f860224, 0x34a50500, 0xc0029bb, 0x3821, +0x8f4203a0, 0x24420001, 0xaf4203a0, 0x8f4203a0, +0x8f820220, 0x2002021, 0x34420002, 0xc00456c, +0xaf820220, 0x8f820220, 0x3c0308ff, 0x3463ffff, +0x431024, 0x511025, 0xaf820220, 0x8fbf0020, +0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, +0x3e00008, 0x0, 0x3c020001, 0x8c423d98, +0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040, +0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f, +0xafb00030, 0x3c040001, 0x24843a80, 0x3c050008, +0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600, +0x24020001, 0x3c010001, 0xac203d98, 0x3c010001, +0xac223d8c, 0xc0029bb, 0x3821, 0x3c037fff, +0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024, +0xac020268, 0x8f420004, 0x3484ffff, 0x30420002, +0x10400092, 0x284a024, 0x3c040600, 0x34842000, +0x8f420004, 0x2821, 0x2403fffd, 0x431024, +0xaf420004, 0xafa40020, 0x8f5e0018, 0x27aa0020, +0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001, +0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0, +0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, +0x8c020228, 0x3c040001, 0x24843a18, 0x3c050009, +0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d, +0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, +0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, +0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b, +0x9821, 0xe08821, 0x263504c0, 0x8f440168, +0x8f45016c, 0x2201821, 0x240a0004, 0xafaa0010, +0xafb20014, 0x8f48000c, 0x1021, 0x2f53021, +0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, +0xa3482b, 0x822021, 0x100f809, 0x892021, +0x54400006, 0x24130001, 0x8f820054, 0x2021023, +0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, +0x54400017, 0xaf520018, 0x8f420368, 0x24420001, +0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843a24, +0x3c050009, 0xafa20014, 0x8d460000, 0x10000035, +0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, +0xaf4202f8, 0x8f4202f8, 0x1000001e, 0x326200ff, +0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, +0x2c4203e9, 0x10400016, 0x9821, 0x3c150020, +0x24110010, 0x8f42000c, 0x8f440150, 0x8f450154, +0x8f860120, 0xafb10010, 0xafb20014, 0x551025, +0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, +0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054, +0x2021023, 0x2c4203e9, 0x1440ffee, 0x0, +0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, -0x24843ac4, 0x3c050009, 0xafa20014, 0x8d460000, -0x10000035, 0x34a50600, 0x8f4202f8, 0x24130001, -0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001e, -0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8, -0x2021023, 0x2c4203e9, 0x10400016, 0x9821, -0x3c150020, 0x24110010, 0x8f42000c, 0x8f440150, -0x8f450154, 0x8f860120, 0xafb10010, 0xafb20014, -0x551025, 0xafa20018, 0x8f42010c, 0x24070008, -0x40f809, 0x24c6001c, 0x1440ffe3, 0x0, -0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffee, -0x0, 0x326200ff, 0x14400011, 0x0, -0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, -0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843acc, 0x3c050009, 0xafa20014, -0x8d460000, 0x34a50700, 0xc002a03, 0x3c03821, -0x8f4202dc, 0x24420001, 0xaf4202dc, 0x8f4202dc, -0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, -0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, -0x27bd0050, 0x3c020001, 0x8c423e38, 0x27bdffe0, -0x1440000d, 0xafbf0018, 0x3c040001, 0x24843b2c, -0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, -0x34a50700, 0x24020001, 0x3c010001, 0xac223e38, -0xc002a03, 0x3821, 0x3c020004, 0x2c21024, -0x10400008, 0x2021, 0x8f820220, 0x3c0308ff, -0x3463ffff, 0x431024, 0x34420008, 0xaf820220, -0x2021, 0xc0049b1, 0x24050004, 0xac020268, -0x8fbf0018, 0x3e00008, 0x27bd0020, 0x86102b, +0x24843a2c, 0x3c050009, 0xafa20014, 0x8d460000, +0x34a50700, 0xc0029bb, 0x3c03821, 0x8f4202dc, +0x24420001, 0xaf4202dc, 0x8f4202dc, 0x8fbf0048, +0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038, +0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050, +0x3c020001, 0x8c423d98, 0x27bdffe0, 0x1440000d, +0xafbf0018, 0x3c040001, 0x24843a8c, 0x3c050008, +0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700, +0x24020001, 0x3c010001, 0xac223d98, 0xc0029bb, +0x3821, 0x3c020004, 0x2c21024, 0x10400008, +0x2021, 0x8f820220, 0x3c0308ff, 0x3463ffff, +0x431024, 0x34420008, 0xaf820220, 0x2021, +0xc0048dd, 0x24050004, 0xac020268, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x0, 0x86102b, 0x50400001, 0x872023, 0xc41023, 0x24843, 0x125102b, 0x1040001b, 0x91040, 0x824021, 0x88102b, 0x10400007, 0x1821, 0x94820000, @@ -7372,7 +7329,7 @@ 0x90a20000, 0x822021, 0x41c02, 0x3082ffff, 0x622021, 0x41c02, 0x3082ffff, 0x622021, 0x3e00008, 0x3082ffff, 0x0, 0x8f820220, -0x34420002, 0xaf820220, 0x3c020001, 0x8c426038, +0x34420002, 0xaf820220, 0x3c020001, 0x8c425f98, 0x30424000, 0x10400054, 0x24040001, 0x8f820200, 0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd, 0x621824, 0xaf830200, 0xaf840204, 0x8f830054, @@ -7419,501 +7376,501 @@ 0x43102b, 0x14400006, 0x3c026000, 0x3c024000, 0x10620008, 0x24020800, 0x10000008, 0x0, 0x10620004, 0x24020800, 0x10000004, 0x0, -0x24020700, 0x3c010001, 0xac223e3c, 0x3e00008, +0x24020700, 0x3c010001, 0xac223d9c, 0x3e00008, 0x0, 0x27bdffc8, 0xafbf0034, 0xafb20030, -0xafb1002c, 0xafb00028, 0x3c010001, 0xc00461d, -0xac203e24, 0x24040001, 0x2821, 0x27a60020, -0x34028000, 0xc00423a, 0xa7a20020, 0x8f830054, +0xafb1002c, 0xafb00028, 0x3c010001, 0xc004549, +0xac203d84, 0x24040001, 0x2821, 0x27a60020, +0x34028000, 0xc004166, 0xa7a20020, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050001, 0xc0041f8, 0x27a60020, 0x8f830054, +0x24050001, 0xc004124, 0x27a60020, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050001, 0xc0041f8, 0x27a60020, 0x8f830054, +0x24050001, 0xc004124, 0x27a60020, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050002, 0xc0041f8, 0x27a60018, 0x8f830054, +0x24050002, 0xc004124, 0x27a60018, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050003, 0xc0041f8, 0x27a6001a, 0x97a20020, -0x10400029, 0x24020001, 0x3c020001, 0x8c423e24, -0x97a30018, 0x34420001, 0x3c010001, 0xac223e24, -0x24020015, 0x14620009, 0x0, 0x97a2001a, -0x3843f423, 0x2c630001, 0x3842f430, 0x2c420001, -0x621825, 0x14600018, 0x24020003, 0x97a30018, -0x24027810, 0x14620014, 0x24020002, 0x97a3001a, -0x24020001, 0x14620010, 0x24020002, 0x1000000e, -0x24020004, 0x3c020001, 0x8c423e24, 0x34420008, -0x3c010001, 0xac223e24, 0x10000058, 0x24020004, -0x3c020001, 0x8c423e24, 0x34420004, 0x3c010001, -0x100000a9, 0xac223e24, 0x3c010001, 0xac223f80, -0x24020e00, 0xaf820238, 0x8f840054, 0x8f820054, -0x24030008, 0x3c010001, 0xac233e28, 0x10000002, -0x248401f4, 0x8f820054, 0x821023, 0x2c4201f5, -0x1440fffc, 0x3c0200c8, 0x344201fb, 0xaf820238, -0x8f830054, 0x8f820054, 0x10000002, 0x246301f4, -0x8f820054, 0x621023, 0x2c4201f5, 0x1440fffc, -0x8021, 0x24120001, 0x24110009, 0xc004118, -0x0, 0x3c010001, 0xac323e40, 0xc0041c4, -0x0, 0x3c020001, 0x8c423e40, 0x1451fffb, -0x3c0200c8, 0x344201f6, 0xaf820238, 0x8f830054, -0x8f820054, 0x10000002, 0x2463000a, 0x8f820054, -0x621023, 0x2c42000b, 0x1440fffc, 0x0, +0x24050003, 0xc004124, 0x27a6001a, 0x97a20020, +0x1040002a, 0x24020001, 0x3c020001, 0x8c423d84, +0x97a30018, 0x34420001, 0x3c010001, 0xac223d84, +0x24020015, 0x1462000a, 0x0, 0x97a2001a, +0x3042fff0, 0x3843f420, 0x2c630001, 0x3842f430, +0x2c420001, 0x621825, 0x14600018, 0x24020003, +0x97a30018, 0x24027810, 0x14620014, 0x24020002, +0x97a2001a, 0x3042fff0, 0x14400010, 0x24020002, +0x1000000e, 0x24020004, 0x3c020001, 0x8c423d84, +0x34420008, 0x3c010001, 0xac223d84, 0x10000058, +0x24020004, 0x3c020001, 0x8c423d84, 0x34420004, +0x3c010001, 0x100000a9, 0xac223d84, 0x3c010001, +0xac223ee0, 0x24020e00, 0xaf820238, 0x8f840054, +0x8f820054, 0x24030008, 0x3c010001, 0xac233d88, +0x10000002, 0x248401f4, 0x8f820054, 0x821023, +0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb, +0xaf820238, 0x8f830054, 0x8f820054, 0x10000002, +0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5, +0x1440fffc, 0x8021, 0x24120001, 0x24110009, +0xc004045, 0x0, 0x3c010001, 0xac323da0, +0xc0040f2, 0x0, 0x3c020001, 0x8c423da0, +0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238, +0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, +0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, +0x0, 0x8f820220, 0x24040001, 0x34420002, +0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd, +0x621824, 0xaf830200, 0xaf840204, 0x8f830054, +0x8f820054, 0x10000002, 0x24630001, 0x8f820054, +0x621023, 0x2c420002, 0x1440fffc, 0x0, +0x8f820224, 0x14440005, 0x34028000, 0x42040, +0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa6, +0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004, +0x3c010001, 0xac223d88, 0x8021, 0x24120009, +0x3c11ffff, 0x36313f7f, 0xc004045, 0x0, +0x24020001, 0x3c010001, 0xac223da0, 0xc0040f2, +0x0, 0x3c020001, 0x8c423da0, 0x1452fffb, +0x0, 0x8f820044, 0x511024, 0x34425080, +0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, +0x2463000a, 0x8f820054, 0x621023, 0x2c42000b, +0x1440fffc, 0x0, 0x8f820044, 0x511024, +0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054, +0x10000002, 0x2463000a, 0x8f820054, 0x621023, +0x2c42000b, 0x1440fffc, 0x0, 0x8f820220, +0x3c03f700, 0x431025, 0xaf820220, 0x8f830054, +0x8f820054, 0x10000002, 0x24630064, 0x8f820054, +0x621023, 0x2c420065, 0x1440fffc, 0x0, 0x8f820220, 0x24040001, 0x34420002, 0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd, 0x621824, 0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054, 0x10000002, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820224, 0x14440005, 0x34028000, 0x42040, 0xa4102b, -0x1040fff0, 0x34028000, 0x1082ffa6, 0x26100001, -0x2e020014, 0x1440ffcd, 0x24020004, 0x3c010001, -0xac223e28, 0x8021, 0x24120009, 0x3c11ffff, -0x36313f7f, 0xc004118, 0x0, 0x24020001, -0x3c010001, 0xac223e40, 0xc0041c4, 0x0, -0x3c020001, 0x8c423e40, 0x1452fffb, 0x0, -0x8f820044, 0x511024, 0x34425080, 0xaf820044, -0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, -0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, -0x0, 0x8f820044, 0x511024, 0x3442f080, -0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, -0x2463000a, 0x8f820054, 0x621023, 0x2c42000b, -0x1440fffc, 0x0, 0x8f820220, 0x3c03f700, -0x431025, 0xaf820220, 0x8f830054, 0x8f820054, -0x10000002, 0x24630064, 0x8f820054, 0x621023, -0x2c420065, 0x1440fffc, 0x0, 0x8f820220, -0x24040001, 0x34420002, 0xaf820220, 0x8f830200, -0x24057fff, 0x2402fffd, 0x621824, 0xaf830200, -0xaf840204, 0x8f830054, 0x8f820054, 0x10000002, -0x24630001, 0x8f820054, 0x621023, 0x2c420002, -0x1440fffc, 0x0, 0x8f820224, 0x14440005, -0x34028000, 0x42040, 0xa4102b, 0x1040fff0, -0x34028000, 0x1082ff56, 0x26100001, 0x2e020064, -0x1440ffb0, 0x0, 0x3c020001, 0x8c423e24, -0x30420004, 0x14400007, 0x3c08fff0, 0x8f820044, -0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044, -0x3c08fff0, 0x3508bdc0, 0x8f830054, 0x97a60018, -0x3c070001, 0x8ce73f80, 0x3c040001, 0x24843c00, -0x24020001, 0x3c010001, 0xac223e2c, 0xafa60010, -0x3c060001, 0x8cc63e24, 0x97a2001a, 0x3c05000d, -0x34a50100, 0x3c010001, 0xac203e28, 0x681821, -0x3c010001, 0xac233f78, 0xc002a03, 0xafa20014, -0x8fbf0034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, -0x3e00008, 0x27bd0038, 0x27bdffe8, 0x24070004, -0x3c040001, 0x8c843e28, 0x3021, 0x24020001, -0x1482000a, 0xafbf0010, 0x3c020001, 0x8c42603c, -0x3c050004, 0x30428000, 0x1040000c, 0x34a593e0, -0x3c05000f, 0x10000009, 0x34a54240, 0x3c020001, -0x8c42603c, 0x3c05000f, 0x30428000, 0x10400003, -0x34a54240, 0x3c05001e, 0x34a58480, 0x3c020001, -0x8c423f78, 0x8f830054, 0x451021, 0x431023, -0x45102b, 0x1440002e, 0x0, 0x3c020001, -0x8c423e30, 0x1440002a, 0x2cc20001, 0x7182b, -0x431024, 0x1040001d, 0x0, 0x3c090001, -0x8d293e24, 0x240b0001, 0x3c054000, 0x3c080001, -0x2508603c, 0x250afffc, 0x42042, 0x14800002, -0x24e7ffff, 0x24040008, 0x891024, 0x5040000b, -0x2cc20001, 0x148b0004, 0x0, 0x8d020000, -0x10000003, 0x451024, 0x8d420000, 0x451024, -0x54400001, 0x24060001, 0x2cc20001, 0x7182b, -0x431024, 0x5440ffed, 0x42042, 0x3c010001, -0x10c00020, 0xac243e28, 0x8f830054, 0x24020001, -0x3c010001, 0xac223e2c, 0x3c010001, 0xac233f78, -0x3c020001, 0x8c423e2c, 0x10400004, 0x24020001, -0x3c010001, 0xac203e2c, 0xaee204b8, 0x8ee304b8, -0x24020008, 0x10620005, 0x24020001, 0xc003fc1, -0x0, 0x1000000b, 0x0, 0x3c030001, -0x8c633e28, 0x10620007, 0x2402000e, 0x3c030001, -0x8c635fd0, 0x10620003, 0x0, 0xc004640, -0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, -0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c843e28, -0x3c020001, 0x8c423e48, 0x3463ffff, 0x283a024, -0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001, -0x8c423e4c, 0x10620006, 0x0, 0x8ee204b8, -0x3c010001, 0xac243e48, 0x3c010001, 0xac223e4c, -0x3c030001, 0x8c633e28, 0x24020002, 0x1062013c, -0x2c620003, 0x10400005, 0x24020001, 0x1062000a, -0x0, 0x10000134, 0x0, 0x24020004, -0x1062006d, 0x24020008, 0x1062009f, 0x24020001, -0x1000012d, 0x0, 0x8ee204b8, 0x2443ffff, -0x2c620008, 0x1040012a, 0x31080, 0x3c010001, -0x220821, 0x8c223c18, 0x400008, 0x0, -0xc004118, 0x0, 0x3c020001, 0x8c423e34, -0x3c010001, 0xac203dc0, 0x104000d7, 0x24020002, -0xaee204b8, 0x3c010001, 0x10000119, 0xac203e34, -0xc00427b, 0x0, 0x3c030001, 0x8c633e50, -0x1000009e, 0x24020011, 0x3c050001, 0x8ca53e28, -0x3c060001, 0x8cc6603c, 0xc0048a8, 0x2021, -0x24020005, 0x3c010001, 0xac203e34, 0x10000108, -0xaee204b8, 0x3c040001, 0x24843c0c, 0x3c05000f, -0x34a50100, 0x3021, 0x3821, 0xafa00010, -0xc002a03, 0xafa00014, 0x100000fd, 0x0, -0x8f820220, 0x3c03f700, 0x431025, 0x100000a4, -0xaf820220, 0x8f820220, 0x3c030004, 0x431024, -0x144000ae, 0x24020007, 0x8f830054, 0x3c020001, -0x8c423f70, 0x2463d8f0, 0x431023, 0x2c422710, -0x144000eb, 0x24020001, 0x100000e7, 0x0, -0x3c050001, 0x8ca53e28, 0xc0049b1, 0x2021, -0xc004a7c, 0x2021, 0x3c030001, 0x8c636034, -0x46100dd, 0x24020001, 0x3c020008, 0x621024, -0x10400006, 0x0, 0x8f820214, 0x3c03ffff, -0x431024, 0x10000005, 0x3442251f, 0x8f820214, -0x3c03ffff, 0x431024, 0x3442241f, 0xaf820214, -0x8f820220, 0x3c030200, 0x283a025, 0x34420002, -0xaf820220, 0x24020008, 0xc003c9e, 0xaee204b8, -0x100000c7, 0x0, 0x8ee204b8, 0x2443ffff, -0x2c620008, 0x104000c2, 0x31080, 0x3c010001, -0x220821, 0x8c223c38, 0x400008, 0x0, -0x3c020001, 0x8c426038, 0x30424000, 0x10400004, -0x0, 0x8f820044, 0x10000006, 0x3442f080, +0x1040fff0, 0x34028000, 0x1082ff56, 0x26100001, +0x2e020064, 0x1440ffb0, 0x0, 0x3c020001, +0x8c423d84, 0x30420004, 0x14400007, 0x3c08fff0, 0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, -0x3442a080, 0xaf820044, 0x8f830054, 0x1000005a, -0x24020004, 0xc003d5c, 0x0, 0x104000a6, -0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, -0x8c843f68, 0x431024, 0x3442251f, 0xaf820214, -0x24020008, 0x10800005, 0xaee204b8, 0x3c020001, -0x8c423eb4, 0x1040006d, 0x24020001, 0x8f820220, -0x3c030008, 0x431024, 0x10400073, 0x3c020200, -0x10000081, 0x0, 0x8ee204b8, 0x2443ffff, -0x2c620007, 0x1040008e, 0x31080, 0x3c010001, -0x220821, 0x8c223c58, 0x400008, 0x0, -0xc003be0, 0x0, 0x3c010001, 0xac203e2c, -0xaf800204, 0x3c010001, 0xc004118, 0xac206020, -0x24020001, 0x3c010001, 0xac223e40, 0x24020002, -0x1000007b, 0xaee204b8, 0xc0041c4, 0x0, -0x3c030001, 0x8c633e40, 0x24020009, 0x14620074, -0x24020003, 0x10000072, 0xaee204b8, 0x3c020001, -0x8c426038, 0x30424000, 0x10400003, 0x3c0200c8, -0x10000002, 0x344201f6, 0x344201fe, 0xaf820238, -0x8f830054, 0x10000014, 0x24020004, 0x8f830054, -0x3c020001, 0x8c423f70, 0x2463d8f0, 0x431023, -0x2c422710, 0x1440005e, 0x24020005, 0x1000005c, -0xaee204b8, 0x8f820220, 0x3c03f700, 0x431025, -0xaf820220, 0xaf800204, 0x3c010001, 0xac206020, -0x8f830054, 0x24020006, 0xaee204b8, 0x3c010001, -0x1000004f, 0xac233f70, 0x8f830054, 0x3c020001, -0x8c423f70, 0x2463fff6, 0x431023, 0x2c42000a, -0x14400047, 0x0, 0x24020007, 0x10000044, -0xaee204b8, 0xc003d5c, 0x0, 0x1040003e, -0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, -0x8c843f68, 0x431024, 0x3442251f, 0xaf820214, -0x24020008, 0x1080000f, 0xaee204b8, 0x3c020001, -0x8c423eb4, 0x1440000b, 0x0, 0x8f820220, -0x34420002, 0xaf820220, 0x24020001, 0x3c010001, -0xac225fd0, 0xc004640, 0x8f840220, 0x10000016, -0x0, 0x8f820220, 0x3c030008, 0x431024, -0x14400011, 0x3c020200, 0x282a025, 0x2402000e, -0x3c010001, 0xac225fd0, 0xc004a7c, 0x2021, -0x8f820220, 0x34420002, 0xc003c9e, 0xaf820220, -0x3c050001, 0x8ca53e28, 0xc0049b1, 0x2021, -0x10000013, 0x0, 0x3c020001, 0x8c423eb4, -0x1040000f, 0x0, 0x3c020001, 0x8c423eb0, -0x2442ffff, 0x3c010001, 0xac223eb0, 0x14400008, -0x24020002, 0x3c010001, 0xac203eb4, 0x3c010001, -0x10000003, 0xac223eb0, 0x3c010001, 0xac223e2c, -0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f820200, -0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, -0x8f820200, 0x3c040001, 0x8c843e28, 0x34420004, -0xaf820200, 0x24020002, 0x1082003a, 0x2c820003, -0x10400005, 0x24020001, 0x1082000a, 0x3c03f0ff, -0x10000098, 0x0, 0x24020004, 0x10820059, -0x24020008, 0x1082006c, 0x3c02f0ff, 0x10000091, -0x0, 0x8f820050, 0x3463ffff, 0x3c05ffff, -0x34a53f7f, 0x431024, 0x3c030700, 0x431025, -0xaf820050, 0x24020e00, 0xaf840200, 0xaf840220, -0xaf820238, 0x8f820044, 0x3c030001, 0x8c633e18, -0x3c040001, 0x8c843f80, 0x451024, 0x34630022, -0xaf820044, 0x24020004, 0x1082000c, 0xaf830200, -0x3c020001, 0x8c423e3c, 0x3c030001, 0x8c633e20, -0x3c040001, 0x8c843e1c, 0x34428000, 0x621825, -0x641825, 0x1000006e, 0x34620002, 0x3c020001, -0x8c423e20, 0x3c030001, 0x8c633e3c, 0x3c040001, -0x8c843e1c, 0x431025, 0x441025, 0x10000064, -0x34420002, 0x8f830050, 0x3c02f0ff, 0x3442ffff, -0x3c040001, 0x8c843f68, 0x621824, 0x3c020d00, -0x621825, 0x24020001, 0xaf830050, 0xaf820200, -0xaf820220, 0x24020e00, 0x10800009, 0xaf820238, -0x3c020001, 0x8c423eb4, 0x14400005, 0x3c033f00, -0x3c020001, 0x8c423e10, 0x10000005, 0x34630070, -0x3c020001, 0x8c423e10, 0x3c033f00, 0x34630072, -0x431025, 0xaf820200, 0x3c030001, 0x8c633e14, -0x3c04f700, 0x3c020001, 0x8c423e20, 0x3c050001, -0x8ca53e3c, 0x641825, 0x431025, 0x1000003c, -0x451025, 0x8f830050, 0x3c02f0ff, 0x3442ffff, -0x3c040001, 0x8c843f68, 0x621824, 0x3c020a00, -0x621825, 0x24020001, 0xaf830050, 0xaf820200, -0x1080001e, 0xaf820220, 0x3c020001, 0x8c423eb4, -0x1440001a, 0x3c033f00, 0x3c020001, 0x8c423e10, -0x1000001a, 0x346300e0, 0x8f830050, 0x3c040001, -0x8c843f68, 0x3442ffff, 0x621824, 0x1080000f, -0xaf830050, 0x3c020001, 0x8c423eb4, 0x1440000b, -0x3c043f00, 0x3c030001, 0x8c633e10, 0x348400e0, -0x24020001, 0xaf820200, 0xaf820220, 0x641825, -0xaf830200, 0x10000008, 0x3c05f700, 0x3c020001, -0x8c423e10, 0x3c033f00, 0x346300e2, 0x431025, -0xaf820200, 0x3c05f700, 0x34a58000, 0x3c030001, -0x8c633e14, 0x3c020001, 0x8c423e20, 0x3c040001, -0x8c843e3c, 0x651825, 0x431025, 0x441025, -0xaf820220, 0x3e00008, 0x0, 0x3c030001, -0x8c633e40, 0x3c020001, 0x8c423e44, 0x10620003, -0x24020002, 0x3c010001, 0xac233e44, 0x1062001d, -0x2c620003, 0x10400025, 0x24020001, 0x14620023, -0x24020004, 0x3c030001, 0x8c633e28, 0x10620006, -0x24020008, 0x1462000c, 0x3c0200c8, 0x344201fb, -0x10000009, 0xaf820238, 0x24020e01, 0xaf820238, -0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, -0x34420080, 0xaf820044, 0x8f830054, 0x24020002, -0x3c010001, 0xac223e40, 0x3c010001, 0x1000000b, -0xac233f74, 0x8f830054, 0x3c020001, 0x8c423f74, -0x2463d8f0, 0x431023, 0x2c422710, 0x14400003, -0x24020009, 0x3c010001, 0xac223e40, 0x3e00008, -0x0, 0x0, 0x0, 0x27bdffd8, +0xaf820044, 0x3c08fff0, 0x3508bdc0, 0x8f830054, +0x97a60018, 0x3c070001, 0x8ce73ee0, 0x3c040001, +0x24843b60, 0x24020001, 0x3c010001, 0xac223d8c, +0xafa60010, 0x3c060001, 0x8cc63d84, 0x97a2001a, +0x3c05000d, 0x34a50100, 0x3c010001, 0xac203d88, +0x681821, 0x3c010001, 0xac233ed8, 0xc0029bb, +0xafa20014, 0x8fbf0034, 0x8fb20030, 0x8fb1002c, +0x8fb00028, 0x3e00008, 0x27bd0038, 0x27bdffe8, +0x24070004, 0x3c040001, 0x8c843d88, 0x3021, +0x24020001, 0x1482000a, 0xafbf0010, 0x3c020001, +0x8c425f9c, 0x3c050004, 0x30428000, 0x1040000c, +0x34a593e0, 0x3c05000f, 0x10000009, 0x34a54240, +0x3c020001, 0x8c425f9c, 0x3c05000f, 0x30428000, +0x10400003, 0x34a54240, 0x3c05001e, 0x34a58480, +0x3c020001, 0x8c423ed8, 0x8f830054, 0x451021, +0x431023, 0x45102b, 0x1440002e, 0x0, +0x3c020001, 0x8c423d90, 0x1440002a, 0x2cc20001, +0x7182b, 0x431024, 0x1040001d, 0x0, +0x3c090001, 0x8d293d84, 0x240b0001, 0x3c054000, +0x3c080001, 0x25085f9c, 0x250afffc, 0x42042, +0x14800002, 0x24e7ffff, 0x24040008, 0x891024, +0x5040000b, 0x2cc20001, 0x148b0004, 0x0, +0x8d020000, 0x10000003, 0x451024, 0x8d420000, +0x451024, 0x54400001, 0x24060001, 0x2cc20001, +0x7182b, 0x431024, 0x5440ffed, 0x42042, +0x3c010001, 0x10c00020, 0xac243d88, 0x8f830054, +0x24020001, 0x3c010001, 0xac223d8c, 0x3c010001, +0xac233ed8, 0x3c020001, 0x8c423d8c, 0x10400004, +0x24020001, 0x3c010001, 0xac203d8c, 0xaee204b8, +0x8ee304b8, 0x24020008, 0x10620005, 0x24020001, +0xc003eee, 0x0, 0x1000000b, 0x0, +0x3c030001, 0x8c633d88, 0x10620007, 0x2402000e, +0x3c030001, 0x8c635f30, 0x10620003, 0x0, +0xc00456c, 0x8f840220, 0x8fbf0010, 0x3e00008, +0x27bd0018, 0x27bdffe0, 0x3c03fdff, 0x3c040001, +0x8c843d88, 0x3c020001, 0x8c423da8, 0x3463ffff, +0x283a024, 0x14820006, 0xafbf0018, 0x8ee304b8, +0x3c020001, 0x8c423dac, 0x10620006, 0x0, +0x8ee204b8, 0x3c010001, 0xac243da8, 0x3c010001, +0xac223dac, 0x3c030001, 0x8c633d88, 0x24020002, +0x1062013c, 0x2c620003, 0x10400005, 0x24020001, +0x1062000a, 0x0, 0x10000134, 0x0, +0x24020004, 0x1062006d, 0x24020008, 0x1062009f, +0x24020001, 0x1000012d, 0x0, 0x8ee204b8, +0x2443ffff, 0x2c620008, 0x1040012a, 0x31080, +0x3c010001, 0x220821, 0x8c223b78, 0x400008, +0x0, 0xc004045, 0x0, 0x3c020001, +0x8c423d94, 0x3c010001, 0xac203d20, 0x104000d7, +0x24020002, 0xaee204b8, 0x3c010001, 0x10000119, +0xac203d94, 0xc0041a7, 0x0, 0x3c030001, +0x8c633db0, 0x1000009e, 0x24020011, 0x3c050001, +0x8ca53d88, 0x3c060001, 0x8cc65f9c, 0xc0047d4, +0x2021, 0x24020005, 0x3c010001, 0xac203d94, +0x10000108, 0xaee204b8, 0x3c040001, 0x24843b6c, +0x3c05000f, 0x34a50100, 0x3021, 0x3821, +0xafa00010, 0xc0029bb, 0xafa00014, 0x100000fd, +0x0, 0x8f820220, 0x3c03f700, 0x431025, +0x100000a4, 0xaf820220, 0x8f820220, 0x3c030004, +0x431024, 0x144000ae, 0x24020007, 0x8f830054, +0x3c020001, 0x8c423ed0, 0x2463d8f0, 0x431023, +0x2c422710, 0x144000eb, 0x24020001, 0x100000e7, +0x0, 0x3c050001, 0x8ca53d88, 0xc0048dd, +0x2021, 0xc0049a8, 0x2021, 0x3c030001, +0x8c635f94, 0x46100dd, 0x24020001, 0x3c020008, +0x621024, 0x10400006, 0x0, 0x8f820214, +0x3c03ffff, 0x431024, 0x10000005, 0x3442251f, +0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f, +0xaf820214, 0x8f820220, 0x3c030200, 0x283a025, +0x34420002, 0xaf820220, 0x24020008, 0xc003bc9, +0xaee204b8, 0x100000c7, 0x0, 0x8ee204b8, +0x2443ffff, 0x2c620008, 0x104000c2, 0x31080, +0x3c010001, 0x220821, 0x8c223b98, 0x400008, +0x0, 0x3c020001, 0x8c425f98, 0x30424000, +0x10400004, 0x0, 0x8f820044, 0x10000006, +0x3442f080, 0x8f820044, 0x3c03ffff, 0x34633f7f, +0x431024, 0x3442a080, 0xaf820044, 0x8f830054, +0x1000005a, 0x24020004, 0xc003c88, 0x0, +0x104000a6, 0x24020001, 0x8f820214, 0x3c03ffff, +0x3c040001, 0x8c843ec8, 0x431024, 0x3442251f, +0xaf820214, 0x24020008, 0x10800005, 0xaee204b8, +0x3c020001, 0x8c423e14, 0x1040006d, 0x24020001, +0x8f820220, 0x3c030008, 0x431024, 0x10400073, +0x3c020200, 0x10000081, 0x0, 0x8ee204b8, +0x2443ffff, 0x2c620007, 0x1040008e, 0x31080, +0x3c010001, 0x220821, 0x8c223bb8, 0x400008, +0x0, 0xc003b0b, 0x0, 0x3c010001, +0xac203d8c, 0xaf800204, 0x3c010001, 0xc004045, +0xac205f80, 0x24020001, 0x3c010001, 0xac223da0, +0x24020002, 0x1000007b, 0xaee204b8, 0xc0040f2, +0x0, 0x3c030001, 0x8c633da0, 0x24020009, +0x14620074, 0x24020003, 0x10000072, 0xaee204b8, +0x3c020001, 0x8c425f98, 0x30424000, 0x10400003, +0x3c0200c8, 0x10000002, 0x344201f6, 0x344201fe, +0xaf820238, 0x8f830054, 0x10000014, 0x24020004, +0x8f830054, 0x3c020001, 0x8c423ed0, 0x2463d8f0, +0x431023, 0x2c422710, 0x1440005e, 0x24020005, +0x1000005c, 0xaee204b8, 0x8f820220, 0x3c03f700, +0x431025, 0xaf820220, 0xaf800204, 0x3c010001, +0xac205f80, 0x8f830054, 0x24020006, 0xaee204b8, +0x3c010001, 0x1000004f, 0xac233ed0, 0x8f830054, +0x3c020001, 0x8c423ed0, 0x2463fff6, 0x431023, +0x2c42000a, 0x14400047, 0x0, 0x24020007, +0x10000044, 0xaee204b8, 0xc003c88, 0x0, +0x1040003e, 0x24020001, 0x8f820214, 0x3c03ffff, +0x3c040001, 0x8c843ec8, 0x431024, 0x3442251f, +0xaf820214, 0x24020008, 0x1080000f, 0xaee204b8, +0x3c020001, 0x8c423e14, 0x1440000b, 0x0, +0x8f820220, 0x34420002, 0xaf820220, 0x24020001, +0x3c010001, 0xac225f30, 0xc00456c, 0x8f840220, +0x10000016, 0x0, 0x8f820220, 0x3c030008, +0x431024, 0x14400011, 0x3c020200, 0x282a025, +0x2402000e, 0x3c010001, 0xac225f30, 0xc0049a8, +0x2021, 0x8f820220, 0x34420002, 0xc003bc9, +0xaf820220, 0x3c050001, 0x8ca53d88, 0xc0048dd, +0x2021, 0x10000013, 0x0, 0x3c020001, +0x8c423e14, 0x1040000f, 0x0, 0x3c020001, +0x8c423e10, 0x2442ffff, 0x3c010001, 0xac223e10, +0x14400008, 0x24020002, 0x3c010001, 0xac203e14, +0x3c010001, 0x10000003, 0xac223e10, 0x3c010001, +0xac223d8c, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0x8f820200, 0x8f820220, 0x8f820220, 0x34420004, +0xaf820220, 0x8f820200, 0x3c060001, 0x8cc63d88, +0x34420004, 0xaf820200, 0x24020002, 0x10c2003b, +0x2cc20003, 0x10400005, 0x24020001, 0x10c2000a, +0x3c03f0ff, 0x10000099, 0x0, 0x24020004, +0x10c2005a, 0x24020008, 0x10c2006d, 0x3c02f0ff, +0x10000092, 0x0, 0x8f820050, 0x3463ffff, +0x3c05ffff, 0x3c040001, 0x8c843ee0, 0x431024, +0x3c030700, 0x431025, 0xaf820050, 0x24020e00, +0xaf860200, 0xaf860220, 0xaf820238, 0x8f820044, +0x3c030001, 0x8c633d78, 0x34a53f7f, 0x451024, +0x34630022, 0xaf820044, 0x24020004, 0xaf860238, +0x1082000c, 0xaf830200, 0x3c020001, 0x8c423d9c, +0x3c030001, 0x8c633d80, 0x3c040001, 0x8c843d7c, +0x34428000, 0x621825, 0x641825, 0x1000006e, +0x34620002, 0x3c020001, 0x8c423d80, 0x3c030001, +0x8c633d9c, 0x3c040001, 0x8c843d7c, 0x431025, +0x441025, 0x10000064, 0x34420002, 0x8f830050, +0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c843ec8, +0x621824, 0x3c020d00, 0x621825, 0x24020001, +0xaf830050, 0xaf820200, 0xaf820220, 0x24020e00, +0x10800009, 0xaf820238, 0x3c020001, 0x8c423e14, +0x14400005, 0x3c033f00, 0x3c020001, 0x8c423d70, +0x10000005, 0x34630070, 0x3c020001, 0x8c423d70, +0x3c033f00, 0x34630072, 0x431025, 0xaf820200, +0x3c030001, 0x8c633d74, 0x3c04f700, 0x3c020001, +0x8c423d80, 0x3c050001, 0x8ca53d9c, 0x641825, +0x431025, 0x1000003c, 0x451025, 0x8f830050, +0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c843ec8, +0x621824, 0x3c020a00, 0x621825, 0x24020001, +0xaf830050, 0xaf820200, 0x1080001e, 0xaf820220, +0x3c020001, 0x8c423e14, 0x1440001a, 0x3c033f00, +0x3c020001, 0x8c423d70, 0x1000001a, 0x346300e0, +0x8f830050, 0x3c040001, 0x8c843ec8, 0x3442ffff, +0x621824, 0x1080000f, 0xaf830050, 0x3c020001, +0x8c423e14, 0x1440000b, 0x3c043f00, 0x3c030001, +0x8c633d70, 0x348400e0, 0x24020001, 0xaf820200, +0xaf820220, 0x641825, 0xaf830200, 0x10000008, +0x3c05f700, 0x3c020001, 0x8c423d70, 0x3c033f00, +0x346300e2, 0x431025, 0xaf820200, 0x3c05f700, +0x34a58000, 0x3c030001, 0x8c633d74, 0x3c020001, +0x8c423d80, 0x3c040001, 0x8c843d9c, 0x651825, +0x431025, 0x441025, 0xaf820220, 0x3e00008, +0x0, 0x3c030001, 0x8c633da0, 0x3c020001, +0x8c423da4, 0x10620003, 0x24020002, 0x3c010001, +0xac233da4, 0x1062001d, 0x2c620003, 0x10400025, +0x24020001, 0x14620023, 0x24020004, 0x3c030001, +0x8c633d88, 0x10620006, 0x24020008, 0x1462000c, +0x3c0200c8, 0x344201fb, 0x10000009, 0xaf820238, +0x24020e01, 0xaf820238, 0x8f820044, 0x3c03ffff, +0x34633f7f, 0x431024, 0x34420080, 0xaf820044, +0x8f830054, 0x24020002, 0x3c010001, 0xac223da0, +0x3c010001, 0x1000000b, 0xac233ed4, 0x8f830054, +0x3c020001, 0x8c423ed4, 0x2463d8f0, 0x431023, +0x2c422710, 0x14400003, 0x24020009, 0x3c010001, +0xac223da0, 0x3e00008, 0x0, 0x27bdffd8, 0xafb20018, 0x809021, 0xafb3001c, 0xa09821, 0xafb10014, 0xc08821, 0xafb00010, 0x8021, -0xafbf0020, 0xa6200000, 0xc0045f7, 0x24040001, +0xafbf0020, 0xa6200000, 0xc004523, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc004523, 0x2021, 0xc004523, 0x24040001, +0xc004523, 0x24040001, 0xc004523, 0x2021, 0x24100010, 0x2501024, 0x10400002, 0x2021, -0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, +0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x2501024, 0x24100010, 0x2701024, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, -0x1600fffa, 0x2701024, 0xc00461d, 0x34108000, -0xc00461d, 0x0, 0xc0045d7, 0x0, +0x2021, 0x24040001, 0xc004523, 0x108042, +0x1600fffa, 0x2701024, 0xc004549, 0x34108000, +0xc004549, 0x0, 0xc004503, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc00461d, 0x0, 0x8fbf0020, 0x8fb3001c, +0xc004549, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, 0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, -0xafb00010, 0x8021, 0xafbf0020, 0xc0045f7, +0xafb00010, 0x8021, 0xafbf0020, 0xc004523, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045f7, 0x2021, 0xc0045f7, -0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, +0x0, 0xc004523, 0x2021, 0xc004523, +0x24040001, 0xc004523, 0x2021, 0xc004523, 0x24040001, 0x24100010, 0x2301024, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x2301024, 0x24100010, 0x2501024, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, -0x108042, 0x1600fffa, 0x2501024, 0xc0045f7, -0x24040001, 0xc0045f7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc004523, +0x108042, 0x1600fffa, 0x2501024, 0xc004523, +0x24040001, 0xc004523, 0x2021, 0x34108000, 0x96620000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, -0x0, 0xc00461d, 0x0, 0x8fbf0020, +0x24040001, 0xc004523, 0x108042, 0x1600fff8, +0x0, 0xc004549, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, -0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633e50, -0x3c020001, 0x8c423e94, 0x27bdffd8, 0xafbf0020, +0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633db0, +0x3c020001, 0x8c423df4, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001, -0xac233e94, 0x2463ffff, 0x2c620013, 0x10400349, -0x31080, 0x3c010001, 0x220821, 0x8c223c80, -0x400008, 0x0, 0xc00461d, 0x8021, -0x34028000, 0xa7a20010, 0x27b10010, 0xc0045f7, +0xac233df4, 0x2463ffff, 0x2c620013, 0x10400349, +0x31080, 0x3c010001, 0x220821, 0x8c223be0, +0x400008, 0x0, 0xc004549, 0x8021, +0x34028000, 0xa7a20010, 0x27b10010, 0xc004523, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045f7, 0x2021, 0xc0045f7, -0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, +0x0, 0xc004523, 0x2021, 0xc004523, +0x24040001, 0xc004523, 0x2021, 0xc004523, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0xc0045f7, +0x2021, 0x24040001, 0xc004523, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0xc004523, 0x2021, 0x108042, 0x1600fffc, 0x0, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, -0x1600fff8, 0x0, 0xc00461d, 0x0, +0x2021, 0x24040001, 0xc004523, 0x108042, +0x1600fff8, 0x0, 0xc004549, 0x0, 0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010, -0x8021, 0xc0045f7, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc0045f7, -0x2021, 0xc0045f7, 0x24040001, 0xc0045f7, -0x24040001, 0xc0045f7, 0x2021, 0x24100010, +0x8021, 0xc004523, 0x24040001, 0x26100001, +0x2e020020, 0x1440fffb, 0x0, 0xc004523, +0x2021, 0xc004523, 0x24040001, 0xc004523, +0x24040001, 0xc004523, 0x2021, 0x24100010, 0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0xc0045f7, 0x2021, 0x108042, -0x1600fffc, 0x0, 0xc00461d, 0x34108000, -0xc00461d, 0x0, 0xc0045d7, 0x0, +0xc004523, 0x108042, 0x1600fffa, 0x32020001, +0x24100010, 0xc004523, 0x2021, 0x108042, +0x1600fffc, 0x0, 0xc004549, 0x34108000, +0xc004549, 0x0, 0xc004503, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc00461d, 0x0, 0x97a20010, 0x30428000, +0xc004549, 0x0, 0x97a20010, 0x30428000, 0x144002dc, 0x24020003, 0x100002d8, 0x0, 0x24021200, 0xa7a20010, 0x27b10010, 0x8021, -0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0xc004523, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0xc0045f7, 0x2021, 0x108042, 0x1600fffc, -0x0, 0xc0045f7, 0x24040001, 0xc0045f7, +0xc004523, 0x2021, 0x108042, 0x1600fffc, +0x0, 0xc004523, 0x24040001, 0xc004523, 0x2021, 0x34108000, 0x96220000, 0x501024, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, -0x108042, 0x1600fff8, 0x0, 0xc00461d, +0x10400002, 0x2021, 0x24040001, 0xc004523, +0x108042, 0x1600fff8, 0x0, 0xc004549, 0x0, 0x8f830054, 0x10000296, 0x24020004, -0x8f830054, 0x3c020001, 0x8c423f7c, 0x2463ff9c, +0x8f830054, 0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440029e, 0x24020002, -0x3c030001, 0x8c633f80, 0x10620297, 0x2c620003, +0x3c030001, 0x8c633ee0, 0x10620297, 0x2c620003, 0x14400296, 0x24020011, 0x24020003, 0x10620005, 0x24020004, 0x10620291, 0x2402000f, 0x1000028f, 0x24020011, 0x1000028d, 0x24020005, 0x24020014, -0xa7a20010, 0x27b10010, 0x8021, 0xc0045f7, +0xa7a20010, 0x27b10010, 0x8021, 0xc004523, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045f7, 0x2021, 0xc0045f7, -0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, +0x0, 0xc004523, 0x2021, 0xc004523, +0x24040001, 0xc004523, 0x2021, 0xc004523, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020012, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, -0x108042, 0x1600fffa, 0x32020012, 0xc0045f7, -0x24040001, 0xc0045f7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc004523, +0x108042, 0x1600fffa, 0x32020012, 0xc004523, +0x24040001, 0xc004523, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, -0x0, 0xc00461d, 0x0, 0x8f830054, +0x24040001, 0xc004523, 0x108042, 0x1600fff8, +0x0, 0xc004549, 0x0, 0x8f830054, 0x10000248, 0x24020006, 0x8f830054, 0x3c020001, -0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, +0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400250, 0x24020007, 0x1000024c, 0x0, 0x24020006, 0xa7a20010, 0x27b10010, 0x8021, -0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0xc004523, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, 0x10400002, 0x2021, 0x24040001, -0xc0045f7, 0x108042, 0x1600fffa, 0x32020013, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc004523, 0x108042, 0x1600fffa, 0x32020013, +0xc004523, 0x24040001, 0xc004523, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, -0x1600fff8, 0x0, 0xc00461d, 0x0, +0x2021, 0x24040001, 0xc004523, 0x108042, +0x1600fff8, 0x0, 0xc004549, 0x0, 0x8f830054, 0x10000207, 0x24020008, 0x8f830054, -0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440020f, 0x24020009, 0x1000020b, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, -0xc0045f7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0xc004523, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x24040001, +0xc004523, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, -0xc00461d, 0x34108000, 0xc00461d, 0x0, -0xc0045d7, 0x0, 0x50400005, 0x108042, +0xc004523, 0x108042, 0x1600fffa, 0x32020018, +0xc004549, 0x34108000, 0xc004549, 0x0, +0xc004503, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc00461d, 0x8021, +0x1600fff7, 0x0, 0xc004549, 0x8021, 0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, -0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0xc004523, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc004523, 0x108042, 0x1600fffa, 0x32020018, +0xc004523, 0x24040001, 0xc004523, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, -0x1600fff8, 0x0, 0xc00461d, 0x0, +0x2021, 0x24040001, 0xc004523, 0x108042, +0x1600fff8, 0x0, 0xc004549, 0x0, 0x8f830054, 0x10000193, 0x2402000a, 0x8f830054, -0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440019b, 0x2402000b, 0x10000197, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, -0xc0045f7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0xc004523, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x24040001, +0xc004523, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc0045f7, 0x108042, 0x1600fffa, 0x32020017, -0xc00461d, 0x34108000, 0xc00461d, 0x0, -0xc0045d7, 0x0, 0x50400005, 0x108042, +0xc004523, 0x108042, 0x1600fffa, 0x32020017, +0xc004549, 0x34108000, 0xc004549, 0x0, +0xc004503, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc00461d, 0x8021, +0x1600fff7, 0x0, 0xc004549, 0x8021, 0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, -0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0xc004523, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc0045f7, 0x108042, 0x1600fffa, 0x32020017, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc004523, 0x108042, 0x1600fffa, 0x32020017, +0xc004523, 0x24040001, 0xc004523, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, -0x1600fff8, 0x0, 0xc00461d, 0x0, +0x2021, 0x24040001, 0xc004523, 0x108042, +0x1600fff8, 0x0, 0xc004549, 0x0, 0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054, -0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400127, 0x24020012, 0x10000123, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, -0xc0045f7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0xc004523, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x24040001, +0xc004523, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc0045f7, 0x108042, 0x1600fffa, 0x32020014, -0xc00461d, 0x34108000, 0xc00461d, 0x0, -0xc0045d7, 0x0, 0x50400005, 0x108042, +0xc004523, 0x108042, 0x1600fffa, 0x32020014, +0xc004549, 0x34108000, 0xc004549, 0x0, +0xc004503, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc00461d, 0x8021, +0x1600fff7, 0x0, 0xc004549, 0x8021, 0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, -0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0xc004523, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc0045f7, 0x108042, 0x1600fffa, 0x32020014, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc004523, 0x108042, 0x1600fffa, 0x32020014, +0xc004523, 0x24040001, 0xc004523, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, -0x1600fff8, 0x0, 0xc00461d, 0x0, +0x2021, 0x24040001, 0xc004523, 0x108042, +0x1600fff8, 0x0, 0xc004549, 0x0, 0x8f830054, 0x100000ab, 0x24020013, 0x8f830054, -0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064, 0x144000b3, 0x2402000d, 0x100000af, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, -0xc0045f7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0xc004523, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x24040001, +0xc004523, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, -0xc00461d, 0x34108000, 0xc00461d, 0x0, -0xc0045d7, 0x0, 0x50400005, 0x108042, +0xc004523, 0x108042, 0x1600fffa, 0x32020018, +0xc004549, 0x34108000, 0xc004549, 0x0, +0xc004503, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc00461d, 0x8021, +0x1600fff7, 0x0, 0xc004549, 0x8021, 0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, -0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, -0xc0045f7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0xc004523, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0xc004523, 0x2021, +0xc004523, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, -0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc004523, 0x108042, 0x1600fffa, 0x32020018, +0xc004523, 0x24040001, 0xc004523, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, -0x1600fff8, 0x0, 0xc00461d, 0x0, +0x2021, 0x24040001, 0xc004523, 0x108042, +0x1600fff8, 0x0, 0xc004549, 0x0, 0x8f830054, 0x10000037, 0x2402000e, 0x24020840, -0xa7a20010, 0x27b10010, 0x8021, 0xc0045f7, +0xa7a20010, 0x27b10010, 0x8021, 0xc004523, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045f7, 0x2021, 0xc0045f7, -0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, +0x0, 0xc004523, 0x2021, 0xc004523, +0x24040001, 0xc004523, 0x2021, 0xc004523, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x2021, 0x24040001, 0xc004523, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, -0x10400002, 0x2021, 0x24040001, 0xc0045f7, -0x108042, 0x1600fffa, 0x32020013, 0xc0045f7, -0x24040001, 0xc0045f7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc004523, +0x108042, 0x1600fffa, 0x32020013, 0xc004523, +0x24040001, 0xc004523, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, -0x0, 0xc00461d, 0x0, 0x8f830054, -0x24020010, 0x3c010001, 0xac223e50, 0x3c010001, -0x1000000c, 0xac233f7c, 0x8f830054, 0x3c020001, -0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, +0x24040001, 0xc004523, 0x108042, 0x1600fff8, +0x0, 0xc004549, 0x0, 0x8f830054, +0x24020010, 0x3c010001, 0xac223db0, 0x3c010001, +0x1000000c, 0xac233edc, 0x8f830054, 0x3c020001, +0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400004, 0x0, 0x24020011, 0x3c010001, -0xac223e50, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, +0xac223db0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044, 0x3c030001, 0x431025, 0x3c030008, 0xaf820044, 0x8f840054, 0x8f820054, 0xa32824, 0x10000002, @@ -7942,136 +7899,136 @@ 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, 0x0, 0x0, 0x27bdffe8, 0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0, -0x0, 0x3c020001, 0x8c423f68, 0x14400005, -0x0, 0xc003be0, 0x8f840224, 0x100001d8, +0x0, 0x3c020001, 0x8c423ec8, 0x14400005, +0x0, 0xc003b0b, 0x8f840224, 0x100001d8, 0x0, 0x8f820220, 0x3c030008, 0x431024, 0x10400026, 0x24020001, 0x8f840224, 0x8f820220, 0x3c030400, 0x431024, 0x10400006, 0x0, -0x3c010001, 0xac205fe0, 0x3c010001, 0x1000000b, -0xac206000, 0x3c030001, 0x24635fe0, 0x8c620000, +0x3c010001, 0xac205f40, 0x3c010001, 0x1000000b, +0xac205f60, 0x3c030001, 0x24635f40, 0x8c620000, 0x24420001, 0xac620000, 0x2c420002, 0x14400003, -0x24020001, 0x3c010001, 0xac226000, 0x3c020001, -0x8c426000, 0x10400006, 0x30820040, 0x10400004, -0x24020001, 0x3c010001, 0x10000003, 0xac226004, -0x3c010001, 0xac206004, 0x3c010001, 0xac245fdc, -0x3c010001, 0x1000000b, 0xac206010, 0x3c010001, -0xac226010, 0x3c010001, 0xac206000, 0x3c010001, -0xac205fe0, 0x3c010001, 0xac206004, 0x3c010001, -0xac205fdc, 0x3c030001, 0x8c635fd0, 0x3c020001, -0x8c425fd4, 0x50620004, 0x2463ffff, 0x3c010001, -0xac235fd4, 0x2463ffff, 0x2c62000e, 0x10400194, -0x31080, 0x3c010001, 0x220821, 0x8c223cd0, +0x24020001, 0x3c010001, 0xac225f60, 0x3c020001, +0x8c425f60, 0x10400006, 0x30820040, 0x10400004, +0x24020001, 0x3c010001, 0x10000003, 0xac225f64, +0x3c010001, 0xac205f64, 0x3c010001, 0xac245f3c, +0x3c010001, 0x1000000b, 0xac205f70, 0x3c010001, +0xac225f70, 0x3c010001, 0xac205f60, 0x3c010001, +0xac205f40, 0x3c010001, 0xac205f64, 0x3c010001, +0xac205f3c, 0x3c030001, 0x8c635f30, 0x3c020001, +0x8c425f34, 0x50620004, 0x2463ffff, 0x3c010001, +0xac235f34, 0x2463ffff, 0x2c62000e, 0x10400194, +0x31080, 0x3c010001, 0x220821, 0x8c223c30, 0x400008, 0x0, 0x24020002, 0x3c010001, -0xac206000, 0x3c010001, 0xac205fe0, 0x3c010001, -0xac205fdc, 0x3c010001, 0xac206004, 0x3c010001, -0xac205ff8, 0x3c010001, 0xac205ff0, 0xaf800224, -0x3c010001, 0xac225fd0, 0x3c020001, 0x8c426010, -0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003be0, +0xac205f60, 0x3c010001, 0xac205f40, 0x3c010001, +0xac205f3c, 0x3c010001, 0xac205f64, 0x3c010001, +0xac205f58, 0x3c010001, 0xac205f50, 0xaf800224, +0x3c010001, 0xac225f30, 0x3c020001, 0x8c425f70, +0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003b0b, 0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd, -0x431024, 0xaf820200, 0x3c010001, 0xac206020, -0x8f830054, 0x3c020001, 0x8c425ff8, 0x24040001, -0x3c010001, 0xac24600c, 0x24420001, 0x3c010001, -0xac225ff8, 0x2c420004, 0x3c010001, 0xac235ff4, -0x14400006, 0x24020003, 0x3c010001, 0xac243e2c, -0x3c010001, 0x1000015e, 0xac205ff8, 0x3c010001, -0x1000015b, 0xac225fd0, 0x8f830054, 0x3c020001, -0x8c425ff4, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400003, 0x24020004, 0x3c010001, 0xac225fd0, -0x3c020001, 0x8c426010, 0x14400021, 0x3c02fdff, +0x431024, 0xaf820200, 0x3c010001, 0xac205f80, +0x8f830054, 0x3c020001, 0x8c425f58, 0x24040001, +0x3c010001, 0xac245f6c, 0x24420001, 0x3c010001, +0xac225f58, 0x2c420004, 0x3c010001, 0xac235f54, +0x14400006, 0x24020003, 0x3c010001, 0xac243d8c, +0x3c010001, 0x1000015e, 0xac205f58, 0x3c010001, +0x1000015b, 0xac225f30, 0x8f830054, 0x3c020001, +0x8c425f54, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400003, 0x24020004, 0x3c010001, 0xac225f30, +0x3c020001, 0x8c425f70, 0x14400021, 0x3c02fdff, 0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001, -0x8c843f6c, 0x3c010001, 0xc004828, 0xac205fe8, -0x3c020001, 0x8c42601c, 0xaf820204, 0x3c020001, -0x8c426010, 0x14400012, 0x3c03fdff, 0x8f820204, +0x8c843ecc, 0x3c010001, 0xc004754, 0xac205f48, +0x3c020001, 0x8c425f7c, 0xaf820204, 0x3c020001, +0x8c425f70, 0x14400012, 0x3c03fdff, 0x8f820204, 0x3463ffff, 0x30420030, 0x1440012f, 0x283a024, -0x3c030001, 0x8c63601c, 0x24020005, 0x3c010001, -0xac225fd0, 0x3c010001, 0x10000131, 0xac236020, -0x3c020001, 0x8c426010, 0x10400010, 0x3c02fdff, -0x3c020001, 0x8c423eac, 0x24420001, 0x3c010001, -0xac223eac, 0x2c420002, 0x14400125, 0x24020001, -0x3c010001, 0xac223eb4, 0x3c010001, 0xac203eac, -0x3c010001, 0x1000011e, 0xac223e2c, 0x3c030001, -0x8c636000, 0x3442ffff, 0x10600119, 0x282a024, -0x3c020001, 0x8c425fdc, 0x10400115, 0x0, -0x3c010001, 0xac226008, 0x24020003, 0x3c010001, -0xac225fe0, 0x100000b8, 0x24020006, 0x3c010001, -0xac205fe8, 0x8f820204, 0x34420040, 0xaf820204, -0x3c020001, 0x8c426020, 0x24030007, 0x3c010001, -0xac235fd0, 0x34420040, 0x3c010001, 0xac226020, -0x3c020001, 0x8c426000, 0x10400005, 0x0, -0x3c020001, 0x8c425fdc, 0x104000f0, 0x24020002, -0x3c050001, 0x24a55fe0, 0x8ca20000, 0x2c424e21, -0x104000ea, 0x24020002, 0x3c020001, 0x8c426004, -0x104000ef, 0x2404ffbf, 0x3c020001, 0x8c425fdc, -0x3c030001, 0x8c636008, 0x441024, 0x641824, +0x3c030001, 0x8c635f7c, 0x24020005, 0x3c010001, +0xac225f30, 0x3c010001, 0x10000131, 0xac235f80, +0x3c020001, 0x8c425f70, 0x10400010, 0x3c02fdff, +0x3c020001, 0x8c423e0c, 0x24420001, 0x3c010001, +0xac223e0c, 0x2c420002, 0x14400125, 0x24020001, +0x3c010001, 0xac223e14, 0x3c010001, 0xac203e0c, +0x3c010001, 0x1000011e, 0xac223d8c, 0x3c030001, +0x8c635f60, 0x3442ffff, 0x10600119, 0x282a024, +0x3c020001, 0x8c425f3c, 0x10400115, 0x0, +0x3c010001, 0xac225f68, 0x24020003, 0x3c010001, +0xac225f40, 0x100000b8, 0x24020006, 0x3c010001, +0xac205f48, 0x8f820204, 0x34420040, 0xaf820204, +0x3c020001, 0x8c425f80, 0x24030007, 0x3c010001, +0xac235f30, 0x34420040, 0x3c010001, 0xac225f80, +0x3c020001, 0x8c425f60, 0x10400005, 0x0, +0x3c020001, 0x8c425f3c, 0x104000f0, 0x24020002, +0x3c050001, 0x24a55f40, 0x8ca20000, 0x2c424e21, +0x104000ea, 0x24020002, 0x3c020001, 0x8c425f64, +0x104000ef, 0x2404ffbf, 0x3c020001, 0x8c425f3c, +0x3c030001, 0x8c635f68, 0x441024, 0x641824, 0x10430004, 0x24020001, 0x3c010001, 0x100000e4, -0xac225fd0, 0x24020003, 0xaca20000, 0x24020008, -0x3c010001, 0xac225fd0, 0x3c020001, 0x8c42600c, -0x1040000c, 0x24020001, 0x3c040001, 0xc004835, -0x8c845fdc, 0x3c020001, 0x8c426028, 0x14400005, -0x24020001, 0x3c020001, 0x8c426024, 0x10400006, -0x24020001, 0x3c010001, 0xac223e2c, 0x3c010001, -0x100000cb, 0xac205ff8, 0x3c020001, 0x8c425ff0, -0x3c030001, 0x8c635fdc, 0x2c420001, 0x210c0, -0x30630008, 0x3c010001, 0xac225ff0, 0x3c010001, -0xac235fec, 0x8f830054, 0x24020009, 0x3c010001, -0xac225fd0, 0x3c010001, 0x100000b9, 0xac235ff4, -0x8f830054, 0x3c020001, 0x8c425ff4, 0x2463d8f0, +0xac225f30, 0x24020003, 0xaca20000, 0x24020008, +0x3c010001, 0xac225f30, 0x3c020001, 0x8c425f6c, +0x1040000c, 0x24020001, 0x3c040001, 0xc004761, +0x8c845f3c, 0x3c020001, 0x8c425f88, 0x14400005, +0x24020001, 0x3c020001, 0x8c425f84, 0x10400006, +0x24020001, 0x3c010001, 0xac223d8c, 0x3c010001, +0x100000cb, 0xac205f58, 0x3c020001, 0x8c425f50, +0x3c030001, 0x8c635f3c, 0x2c420001, 0x210c0, +0x30630008, 0x3c010001, 0xac225f50, 0x3c010001, +0xac235f4c, 0x8f830054, 0x24020009, 0x3c010001, +0xac225f30, 0x3c010001, 0x100000b9, 0xac235f54, +0x8f830054, 0x3c020001, 0x8c425f54, 0x2463d8f0, 0x431023, 0x2c422710, 0x1440009f, 0x0, -0x3c020001, 0x8c426000, 0x10400005, 0x0, -0x3c020001, 0x8c425fdc, 0x104000a0, 0x24020002, -0x3c030001, 0x24635fe0, 0x8c620000, 0x2c424e21, -0x1040009a, 0x24020002, 0x3c020001, 0x8c42600c, -0x1040000e, 0x0, 0x3c020001, 0x8c425fdc, -0x3c010001, 0xac20600c, 0x30420080, 0x1040002f, +0x3c020001, 0x8c425f60, 0x10400005, 0x0, +0x3c020001, 0x8c425f3c, 0x104000a0, 0x24020002, +0x3c030001, 0x24635f40, 0x8c620000, 0x2c424e21, +0x1040009a, 0x24020002, 0x3c020001, 0x8c425f6c, +0x1040000e, 0x0, 0x3c020001, 0x8c425f3c, +0x3c010001, 0xac205f6c, 0x30420080, 0x1040002f, 0x2402000c, 0x8f820204, 0x30420080, 0x1440000c, 0x24020003, 0x10000029, 0x2402000c, 0x3c020001, -0x8c425fdc, 0x30420080, 0x14400005, 0x24020003, +0x8c425f3c, 0x30420080, 0x14400005, 0x24020003, 0x8f820204, 0x30420080, 0x1040001f, 0x24020003, -0xac620000, 0x2402000a, 0x3c010001, 0xac225fd0, -0x3c040001, 0x24846018, 0x8c820000, 0x3c030001, -0x8c635ff0, 0x431025, 0xaf820204, 0x8c830000, -0x3c040001, 0x8c845ff0, 0x2402000b, 0x3c010001, -0xac225fd0, 0x641825, 0x3c010001, 0xac236020, -0x3c050001, 0x24a55fe0, 0x8ca20000, 0x2c424e21, -0x10400066, 0x24020002, 0x3c020001, 0x8c426010, +0xac620000, 0x2402000a, 0x3c010001, 0xac225f30, +0x3c040001, 0x24845f78, 0x8c820000, 0x3c030001, +0x8c635f50, 0x431025, 0xaf820204, 0x8c830000, +0x3c040001, 0x8c845f50, 0x2402000b, 0x3c010001, +0xac225f30, 0x641825, 0x3c010001, 0xac235f80, +0x3c050001, 0x24a55f40, 0x8ca20000, 0x2c424e21, +0x10400066, 0x24020002, 0x3c020001, 0x8c425f70, 0x10400005, 0x0, 0x2402000c, 0x3c010001, -0x10000067, 0xac225fd0, 0x3c020001, 0x8c426000, -0x10400063, 0x0, 0x3c040001, 0x8c845fdc, -0x10800055, 0x30820008, 0x3c030001, 0x8c635fec, -0x1062005b, 0x24020003, 0x3c010001, 0xac246008, +0x10000067, 0xac225f30, 0x3c020001, 0x8c425f60, +0x10400063, 0x0, 0x3c040001, 0x8c845f3c, +0x10800055, 0x30820008, 0x3c030001, 0x8c635f4c, +0x1062005b, 0x24020003, 0x3c010001, 0xac245f68, 0xaca20000, 0x24020006, 0x3c010001, 0x10000054, -0xac225fd0, 0x8f820200, 0x34420002, 0xaf820200, -0x8f830054, 0x2402000d, 0x3c010001, 0xac225fd0, -0x3c010001, 0xac235ff4, 0x8f830054, 0x3c020001, -0x8c425ff4, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400031, 0x0, 0x3c020001, 0x8c426010, -0x10400020, 0x2402000e, 0x3c030001, 0x8c636024, -0x3c010001, 0x14600015, 0xac225fd0, 0xc003c9e, -0x0, 0x3c050001, 0x8ca53e28, 0xc0049b1, -0x2021, 0x3c030001, 0x8c633e28, 0x24020004, -0x14620005, 0x2403fffb, 0x3c020001, 0x8c423e24, -0x10000003, 0x2403fff7, 0x3c020001, 0x8c423e24, -0x431024, 0x3c010001, 0xac223e24, 0x8f830224, -0x3c020200, 0x3c010001, 0xac23602c, 0x10000020, -0x282a025, 0x3c020001, 0x8c426000, 0x10400005, -0x0, 0x3c020001, 0x8c425fdc, 0x1040000f, -0x24020002, 0x3c020001, 0x8c425fe0, 0x2c424e21, -0x1040000a, 0x24020002, 0x3c020001, 0x8c426000, -0x1040000f, 0x0, 0x3c020001, 0x8c425fdc, +0xac225f30, 0x8f820200, 0x34420002, 0xaf820200, +0x8f830054, 0x2402000d, 0x3c010001, 0xac225f30, +0x3c010001, 0xac235f54, 0x8f830054, 0x3c020001, +0x8c425f54, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400031, 0x0, 0x3c020001, 0x8c425f70, +0x10400020, 0x2402000e, 0x3c030001, 0x8c635f84, +0x3c010001, 0x14600015, 0xac225f30, 0xc003bc9, +0x0, 0x3c050001, 0x8ca53d88, 0xc0048dd, +0x2021, 0x3c030001, 0x8c633d88, 0x24020004, +0x14620005, 0x2403fffb, 0x3c020001, 0x8c423d84, +0x10000003, 0x2403fff7, 0x3c020001, 0x8c423d84, +0x431024, 0x3c010001, 0xac223d84, 0x8f830224, +0x3c020200, 0x3c010001, 0xac235f8c, 0x10000020, +0x282a025, 0x3c020001, 0x8c425f60, 0x10400005, +0x0, 0x3c020001, 0x8c425f3c, 0x1040000f, +0x24020002, 0x3c020001, 0x8c425f40, 0x2c424e21, +0x1040000a, 0x24020002, 0x3c020001, 0x8c425f60, +0x1040000f, 0x0, 0x3c020001, 0x8c425f3c, 0x1440000b, 0x0, 0x24020002, 0x3c010001, -0x10000007, 0xac225fd0, 0x3c020001, 0x8c426000, -0x10400003, 0x0, 0xc003be0, 0x0, +0x10000007, 0xac225f30, 0x3c020001, 0x8c425f60, +0x10400003, 0x0, 0xc003b0b, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030001, -0x24636028, 0x8c620000, 0x10400005, 0x34422000, -0x3c010001, 0xac22601c, 0x10000003, 0xac600000, -0x3c010001, 0xac24601c, 0x3e00008, 0x0, +0x24635f88, 0x8c620000, 0x10400005, 0x34422000, +0x3c010001, 0xac225f7c, 0x10000003, 0xac600000, +0x3c010001, 0xac245f7c, 0x3e00008, 0x0, 0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010001, -0xac226024, 0x14400067, 0x3c02ffff, 0x34421f0e, +0xac225f84, 0x14400067, 0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061, 0x24020030, 0x30822000, 0x1040005d, 0x30838000, 0x31a02, 0x30820001, -0x21200, 0x3c040001, 0x8c843f6c, 0x621825, -0x331c2, 0x3c030001, 0x24633eb8, 0x30828000, +0x21200, 0x3c040001, 0x8c843ecc, 0x621825, +0x331c2, 0x3c030001, 0x24633e18, 0x30828000, 0x21202, 0x30840001, 0x42200, 0x441025, 0x239c2, 0x61080, 0x431021, 0x471021, 0x90430000, 0x24020001, 0x10620025, 0x0, @@ -8079,86 +8036,86 @@ 0x1062002c, 0x3c05000f, 0x10000037, 0x0, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, -0xaf820220, 0x3c010001, 0xac206044, 0x3c010001, -0x10000034, 0xac20604c, 0x8f820200, 0x34420100, +0xaf820220, 0x3c010001, 0xac205fa4, 0x3c010001, +0x10000034, 0xac205fac, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, 0x24020100, 0x3c010001, -0xac226044, 0x3c010001, 0x10000026, 0xac20604c, +0xac225fa4, 0x3c010001, 0x10000026, 0xac205fac, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, -0x3c010001, 0xac206044, 0x3c010001, 0x10000019, -0xac23604c, 0x8f820200, 0x34420100, 0xaf820200, +0x3c010001, 0xac205fa4, 0x3c010001, 0x10000019, +0xac235fac, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, -0x24020100, 0x3c010001, 0xac226044, 0x3c010001, -0x1000000c, 0xac23604c, 0x34a5ffff, 0x3c040001, -0x24843d08, 0xafa30010, 0xc002a03, 0xafa00014, +0x24020100, 0x3c010001, 0xac225fa4, 0x3c010001, +0x1000000c, 0xac235fac, 0x34a5ffff, 0x3c040001, +0x24843c68, 0xafa30010, 0xc0029bb, 0xafa00014, 0x10000004, 0x0, 0x24020030, 0x3c010001, -0xac226028, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0xac225f88, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, 0x0, 0x0, 0x27bdffc8, 0xafb10024, 0x808821, 0xafb3002c, 0xa09821, -0xafb00020, 0xc08021, 0x3c040001, 0x24843d20, -0x3c050009, 0x3c020001, 0x8c423e28, 0x34a59001, +0xafb00020, 0xc08021, 0x3c040001, 0x24843c80, +0x3c050009, 0x3c020001, 0x8c423d88, 0x34a59001, 0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, -0xa7a0001a, 0xafb00014, 0xc002a03, 0xafa20010, +0xa7a0001a, 0xafb00014, 0xc0029bb, 0xafa20010, 0x24020002, 0x126200eb, 0x2e620003, 0x10400005, 0x24020001, 0x1262000a, 0x3c02fffb, 0x100000e5, 0x0, 0x24020004, 0x1262006d, 0x24020008, 0x1262006c, 0x3c02ffec, 0x100000de, 0x0, 0x3442ffff, 0x2028024, 0x119140, 0x3c010001, -0x320821, 0xac30603c, 0x3c024000, 0x2021024, +0x320821, 0xac305f9c, 0x3c024000, 0x2021024, 0x10400046, 0x1023c2, 0x30840030, 0x101382, -0x3042000c, 0x3c030001, 0x24633e54, 0x431021, +0x3042000c, 0x3c030001, 0x24633db4, 0x431021, 0x823821, 0x3c020020, 0x2021024, 0x10400006, -0x24020100, 0x3c010001, 0x320821, 0xac226040, +0x24020100, 0x3c010001, 0x320821, 0xac225fa0, 0x10000005, 0x3c020080, 0x3c010001, 0x320821, -0xac206040, 0x3c020080, 0x2021024, 0x10400006, +0xac205fa0, 0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, 0x3c010001, 0x230821, -0x10000005, 0xac226048, 0x111140, 0x3c010001, -0x220821, 0xac206048, 0x94e30000, 0x32024000, +0x10000005, 0xac225fa8, 0x111140, 0x3c010001, +0x220821, 0xac205fa8, 0x94e30000, 0x32024000, 0x10400003, 0xa7a30018, 0x34624000, 0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, 0x24e60002, -0x34420001, 0xc00423a, 0xa4e20002, 0x24040001, -0x2821, 0xc00423a, 0x27a60018, 0x3c020001, -0x8c423e28, 0x24110001, 0x3c010001, 0xac313e34, -0x14530004, 0x32028000, 0xc003be0, 0x0, -0x32028000, 0x10400097, 0x0, 0xc003be0, -0x0, 0x24020002, 0x3c010001, 0xac313e2c, -0x3c010001, 0x1000008f, 0xac223e28, 0x24040001, -0x24050004, 0x27b0001a, 0xc00423a, 0x2003021, -0x24040001, 0x2821, 0xc00423a, 0x2003021, -0x3c020001, 0x521021, 0x8c426034, 0x3c040001, -0x8c843e28, 0x3c03bfff, 0x3463ffff, 0x3c010001, -0xac333e34, 0x431024, 0x3c010001, 0x320821, -0x10930076, 0xac226034, 0x10000076, 0x0, +0x34420001, 0xc004166, 0xa4e20002, 0x24040001, +0x2821, 0xc004166, 0x27a60018, 0x3c020001, +0x8c423d88, 0x24110001, 0x3c010001, 0xac313d94, +0x14530004, 0x32028000, 0xc003b0b, 0x0, +0x32028000, 0x10400097, 0x0, 0xc003b0b, +0x0, 0x24020002, 0x3c010001, 0xac313d8c, +0x3c010001, 0x1000008f, 0xac223d88, 0x24040001, +0x24050004, 0x27b0001a, 0xc004166, 0x2003021, +0x24040001, 0x2821, 0xc004166, 0x2003021, +0x3c020001, 0x521021, 0x8c425f94, 0x3c040001, +0x8c843d88, 0x3c03bfff, 0x3463ffff, 0x3c010001, +0xac333d94, 0x431024, 0x3c010001, 0x320821, +0x10930076, 0xac225f94, 0x10000076, 0x0, 0x3c02ffec, 0x3442ffff, 0x2028024, 0x3c020008, 0x2028025, 0x111140, 0x3c010001, 0x220821, -0xac306038, 0x3c022000, 0x2021024, 0x10400009, -0x0, 0x3c020001, 0x8c423eb4, 0x14400005, -0x24020001, 0x3c010001, 0xac223f68, 0x10000004, -0x3c024000, 0x3c010001, 0xac203f68, 0x3c024000, +0xac305f98, 0x3c022000, 0x2021024, 0x10400009, +0x0, 0x3c020001, 0x8c423e14, 0x14400005, +0x24020001, 0x3c010001, 0xac223ec8, 0x10000004, +0x3c024000, 0x3c010001, 0xac203ec8, 0x3c024000, 0x2021024, 0x1440001a, 0x0, 0x3c020001, -0x8c423f68, 0x10400005, 0x24022020, 0x3c010001, -0xac223f6c, 0x24020001, 0xaee204b8, 0x3c04bfff, -0x111940, 0x3c020001, 0x431021, 0x8c426030, -0x3c050001, 0x8ca53e28, 0x3484ffff, 0x441024, -0x3c010001, 0x230821, 0xac226030, 0x24020001, +0x8c423ec8, 0x10400005, 0x24022020, 0x3c010001, +0xac223ecc, 0x24020001, 0xaee204b8, 0x3c04bfff, +0x111940, 0x3c020001, 0x431021, 0x8c425f90, +0x3c050001, 0x8ca53d88, 0x3484ffff, 0x441024, +0x3c010001, 0x230821, 0xac225f90, 0x24020001, 0x10a20044, 0x0, 0x10000040, 0x0, -0x3c020001, 0x8c423f68, 0x1040001c, 0x24022000, -0x3c010001, 0xac223f6c, 0x3c0300a0, 0x2031024, +0x3c020001, 0x8c423ec8, 0x1040001c, 0x24022000, +0x3c010001, 0xac223ecc, 0x3c0300a0, 0x2031024, 0x14430005, 0x111140, 0x3402a000, 0x3c010001, -0x1000002d, 0xac223f6c, 0x3c030001, 0x621821, -0x8c636038, 0x3c020020, 0x621024, 0x10400004, -0x24022001, 0x3c010001, 0x10000023, 0xac223f6c, +0x1000002d, 0xac223ecc, 0x3c030001, 0x621821, +0x8c635f98, 0x3c020020, 0x621024, 0x10400004, +0x24022001, 0x3c010001, 0x10000023, 0xac223ecc, 0x3c020080, 0x621024, 0x1040001f, 0x3402a001, -0x3c010001, 0x1000001c, 0xac223f6c, 0x3c020020, +0x3c010001, 0x1000001c, 0xac223ecc, 0x3c020020, 0x2021024, 0x10400007, 0x111940, 0x24020100, -0x3c010001, 0x230821, 0xac226044, 0x10000006, +0x3c010001, 0x230821, 0xac225fa4, 0x10000006, 0x3c020080, 0x111140, 0x3c010001, 0x220821, -0xac206044, 0x3c020080, 0x2021024, 0x10400006, +0xac205fa4, 0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, 0x3c010001, 0x230821, -0x10000005, 0xac22604c, 0x111140, 0x3c010001, -0x220821, 0xac20604c, 0x3c030001, 0x8c633e28, -0x24020001, 0x10620003, 0x0, 0xc003be0, +0x10000005, 0xac225fac, 0x111140, 0x3c010001, +0x220821, 0xac205fac, 0x3c030001, 0x8c633d88, +0x24020001, 0x10620003, 0x0, 0xc003b0b, 0x0, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, 0x27bdffd0, 0xafb50028, 0x80a821, 0xafb20020, @@ -8168,95 +8125,95 @@ 0x10400005, 0x24020001, 0x10a2000a, 0x158140, 0x100000ae, 0x2201021, 0x24020004, 0x10a2005e, 0x24020008, 0x10a2005d, 0x152940, 0x100000a7, -0x2201021, 0x3c030001, 0x701821, 0x8c63603c, +0x2201021, 0x3c030001, 0x701821, 0x8c635f9c, 0x3c024000, 0x621024, 0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff, 0x628824, 0x3c010001, -0x300821, 0xac316034, 0x10000098, 0x2201021, -0x24050001, 0xc0041f8, 0x27a60010, 0x24040001, -0x24050001, 0xc0041f8, 0x27a60010, 0x97a20010, +0x300821, 0xac315f94, 0x10000098, 0x2201021, +0x24050001, 0xc004124, 0x27a60010, 0x24040001, +0x24050001, 0xc004124, 0x27a60010, 0x97a20010, 0x30420004, 0x10400034, 0x3c114000, 0x3c030001, -0x8c633f80, 0x24020003, 0x10620008, 0x2c620004, +0x8c633ee0, 0x24020003, 0x10620008, 0x2c620004, 0x14400029, 0x3c028000, 0x24020004, 0x10620014, 0x24040001, 0x10000024, 0x3c028000, 0x24040001, -0x24050011, 0x27b00012, 0xc0041f8, 0x2003021, -0x24040001, 0x24050011, 0xc0041f8, 0x2003021, +0x24050011, 0x27b00012, 0xc004124, 0x2003021, +0x24040001, 0x24050011, 0xc004124, 0x2003021, 0x97a30012, 0x30624000, 0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, 0x10000010, 0x30628000, -0x24050014, 0x27b00012, 0xc0041f8, 0x2003021, -0x24040001, 0x24050014, 0xc0041f8, 0x2003021, +0x24050014, 0x27b00012, 0xc004124, 0x2003021, +0x24040001, 0x24050014, 0xc004124, 0x2003021, 0x97a30012, 0x30621000, 0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, 0x30620800, 0x54400001, 0x3c120002, 0x3c028000, 0x2221025, 0x2531825, 0x10000007, 0x438825, 0x3c110001, 0x2308821, -0x8e31603c, 0x3c027fff, 0x3442ffff, 0x2228824, -0x151140, 0x3c010001, 0x220821, 0xac316034, +0x8e315f9c, 0x3c027fff, 0x3442ffff, 0x2228824, +0x151140, 0x3c010001, 0x220821, 0xac315f94, 0x1000004e, 0x2201021, 0x152940, 0x3c030001, -0x651821, 0x8c636038, 0x3c024000, 0x621024, +0x651821, 0x8c635f98, 0x3c024000, 0x621024, 0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, -0x3c010001, 0x250821, 0xac316030, 0x1000003f, -0x2201021, 0x3c020001, 0x8c423e38, 0x10400033, -0x3c11c00c, 0x3c020001, 0x8c423eb4, 0x3c04c00c, -0x34842000, 0x3c030001, 0x8c633f68, 0x2102b, +0x3c010001, 0x250821, 0xac315f90, 0x1000003f, +0x2201021, 0x3c020001, 0x8c423d98, 0x10400033, +0x3c11c00c, 0x3c020001, 0x8c423e14, 0x3c04c00c, +0x34842000, 0x3c030001, 0x8c633ec8, 0x2102b, 0x21023, 0x441024, 0x10600003, 0x518825, 0x3c022000, 0x2228825, 0x3c020001, 0x451021, -0x8c426044, 0x10400003, 0x3c020020, 0x10000004, +0x8c425fa4, 0x10400003, 0x3c020020, 0x10000004, 0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, -0x151140, 0x3c010001, 0x220821, 0x8c22604c, +0x151140, 0x3c010001, 0x220821, 0x8c225fac, 0x10400003, 0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001, -0x8c423ea0, 0x10400002, 0x3c020800, 0x2228825, -0x3c020001, 0x8c423ea4, 0x10400002, 0x3c020400, -0x2228825, 0x3c020001, 0x8c423ea8, 0x10400006, +0x8c423e00, 0x10400002, 0x3c020800, 0x2228825, +0x3c020001, 0x8c423e04, 0x10400002, 0x3c020400, +0x2228825, 0x3c020001, 0x8c423e08, 0x10400006, 0x3c020100, 0x10000004, 0x2228825, 0x3c027fff, 0x3442ffff, 0x628824, 0x151140, 0x3c010001, -0x220821, 0xac316030, 0x2201021, 0x8fbf002c, +0x220821, 0xac315f90, 0x2201021, 0x8fbf002c, 0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe0, 0xafb20018, 0x809021, 0xafbf001c, 0xafb10014, -0xafb00010, 0x8f840200, 0x3c030001, 0x8c633e28, +0xafb00010, 0x8f840200, 0x3c030001, 0x8c633d88, 0x8f860220, 0x24020002, 0x106200a6, 0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 0x121940, 0x100000a0, 0x0, 0x24020004, 0x10620053, 0x24020008, 0x10620052, 0x128940, 0x10000099, -0x0, 0x3c050001, 0xa32821, 0x8ca5603c, -0x3c100001, 0x2038021, 0x8e106034, 0x3c024000, +0x0, 0x3c050001, 0xa32821, 0x8ca55f9c, +0x3c100001, 0x2038021, 0x8e105f94, 0x3c024000, 0xa21024, 0x10400038, 0x3c020008, 0x2021024, 0x10400020, 0x34840002, 0x3c020001, 0x431021, -0x8c426040, 0x10400005, 0x34840020, 0x34840100, +0x8c425fa0, 0x10400005, 0x34840020, 0x34840100, 0x3c020020, 0x10000006, 0x2028025, 0x2402feff, 0x822024, 0x3c02ffdf, 0x3442ffff, 0x2028024, -0x121140, 0x3c010001, 0x220821, 0x8c226048, +0x121140, 0x3c010001, 0x220821, 0x8c225fa8, 0x10400005, 0x3c020001, 0xc23025, 0x3c020080, 0x10000016, 0x2028025, 0x3c02fffe, 0x3442ffff, 0xc23024, 0x3c02ff7f, 0x3442ffff, 0x1000000f, 0x2028024, 0x2402fedf, 0x822024, 0x3c02fffe, 0x3442ffff, 0xc23024, 0x3c02ff5f, 0x3442ffff, -0x2028024, 0x3c010001, 0x230821, 0xac206040, -0x3c010001, 0x230821, 0xac206048, 0xaf840200, +0x2028024, 0x3c010001, 0x230821, 0xac205fa0, +0x3c010001, 0x230821, 0xac205fa8, 0xaf840200, 0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, 0x1000000a, 0x121140, 0x3c02bfff, 0x3442ffff, 0x8f830200, 0x2028024, 0x2402fffd, 0x621824, -0xc003be0, 0xaf830200, 0x121140, 0x3c010001, -0x220821, 0x1000004b, 0xac306034, 0x128940, -0x3c050001, 0xb12821, 0x8ca56038, 0x3c100001, -0x2118021, 0x8e106030, 0x3c024000, 0xa21024, -0x14400010, 0x0, 0x3c020001, 0x8c423f68, +0xc003b0b, 0xaf830200, 0x121140, 0x3c010001, +0x220821, 0x1000004b, 0xac305f94, 0x128940, +0x3c050001, 0xb12821, 0x8ca55f98, 0x3c100001, +0x2118021, 0x8e105f90, 0x3c024000, 0xa21024, +0x14400010, 0x0, 0x3c020001, 0x8c423ec8, 0x14400005, 0x3c02bfff, 0x8f820200, 0x34420002, -0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003be0, +0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003b0b, 0x2028024, 0x3c010001, 0x310821, 0x10000031, -0xac306030, 0x3c020001, 0x8c423f68, 0x10400005, -0x3c020020, 0x3c020001, 0x8c423eb4, 0x10400025, +0xac305f90, 0x3c020001, 0x8c423ec8, 0x10400005, +0x3c020020, 0x3c020001, 0x8c423e14, 0x10400025, 0x3c020020, 0xa21024, 0x10400007, 0x34840020, -0x24020100, 0x3c010001, 0x310821, 0xac226044, +0x24020100, 0x3c010001, 0x310821, 0xac225fa4, 0x10000006, 0x34840100, 0x3c010001, 0x310821, -0xac206044, 0x2402feff, 0x822024, 0x3c020080, +0xac205fa4, 0x2402feff, 0x822024, 0x3c020080, 0xa21024, 0x10400007, 0x121940, 0x3c020001, -0x3c010001, 0x230821, 0xac22604c, 0x10000008, +0x3c010001, 0x230821, 0xac225fac, 0x10000008, 0xc23025, 0x121140, 0x3c010001, 0x220821, -0xac20604c, 0x3c02fffe, 0x3442ffff, 0xc23024, +0xac205fac, 0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200, 0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, 0x121140, 0x3c010001, 0x220821, -0xac306030, 0x8fbf001c, 0x8fb20018, 0x8fb10014, +0xac305f90, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0020, 0x1821, 0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007, 0x30420001, 0x10400004, 0x0, 0x8f820044, @@ -8264,6 +8221,49 @@ 0xaf820044, 0x8f820044, 0x34420020, 0xaf820044, 0x8f820044, 0x451024, 0xaf820044, 0x24630001, 0x28620008, 0x5440ffee, 0x641007, 0x3e00008, +0x0, 0x0, 0x0, 0x8f8400c4, +0x8f8600e0, 0x8f8700e4, 0x2402fff8, 0xc22824, +0x10e5001a, 0x27623ff8, 0x14e20002, 0x24e80008, +0x27683000, 0x55050004, 0x8d0a0000, 0x30c20004, +0x14400012, 0x805021, 0x8ce90000, 0x8f42013c, +0x1494823, 0x49182b, 0x94eb0006, 0x10600002, +0x25630050, 0x494821, 0x123182b, 0x50400003, +0x8f4201fc, 0x3e00008, 0xe01021, 0xaf8800e8, +0x24420001, 0xaf4201fc, 0xaf8800e4, 0x3e00008, +0x1021, 0x3e00008, 0x0, 0x8f8300e4, +0x27623ff8, 0x10620004, 0x24620008, 0xaf8200e4, +0x3e00008, 0xaf8200e8, 0x27623000, 0xaf8200e4, +0x3e00008, 0xaf8200e8, 0x3e00008, 0x0, +0x27bdffd0, 0xafbf0028, 0x8f4c004c, 0x8f4d0048, +0xafb00024, 0x118d0026, 0x1ac4023, 0x8f490054, +0x5020001, 0x25080200, 0x189102b, 0x14400003, +0x24020200, 0x8004abe, 0x4c5023, 0x12c5023, +0x254affff, 0x10a102a, 0x54400001, 0x1005021, +0x14c8021, 0x321001ff, 0x8f45017c, 0x8f440178, +0xc1140, 0xa22821, 0x3406ecc0, 0xc23021, +0x2e63021, 0xa3940, 0x24031000, 0xafa30010, +0x8f430108, 0xafb00014, 0x8f420014, 0x60f809, +0xafa20018, 0x10400002, 0x8fbf0028, 0xaf50004c, +0x120d0003, 0x8fb00024, 0x3e00008, 0x27bd0030, +0xaf800048, 0x8f820048, 0x0, 0x1040fffc, +0x8f820060, 0x2403fdff, 0x431024, 0xaf820060, +0xaf800048, 0x3e00008, 0x27bd0030, 0x3e00008, +0x0, 0x0, 0x0, 0x8f880120, +0x27624fe0, 0x8f830128, 0x15020002, 0x25090020, +0x27694800, 0x11230012, 0x8fa20010, 0xad040000, +0xad050004, 0xad060008, 0xa507000e, 0x8fa30014, +0xad020018, 0x8fa20018, 0xad03001c, 0x25030016, +0xad020010, 0xad030014, 0xaf890120, 0x8f4300fc, +0x24020001, 0x2463ffff, 0x3e00008, 0xaf4300fc, +0x8f430324, 0x1021, 0x24630001, 0x3e00008, +0xaf430324, 0x3e00008, 0x0, 0x8f880100, +0x276247e0, 0x8f830108, 0x15020002, 0x25090020, +0x27694000, 0x1123000f, 0x8fa20010, 0xad040000, +0xad050004, 0xad060008, 0xa507000e, 0x8fa30014, +0xad020018, 0x8fa20018, 0xad03001c, 0x25030016, +0xad020010, 0xad030014, 0xaf890100, 0x3e00008, +0x24020001, 0x8f430328, 0x1021, 0x24630001, +0x3e00008, 0xaf430328, 0x3e00008, 0x0, 0x0, 0x0, 0x0, 0x0 }; u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, @@ -8368,12 +8368,12 @@ 0x0, 0x3f636d64, 0x48737453, 0x0, 0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64, 0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b, -0x0, 0x3f636d64, 0x45727200, 0x811c, -0x8898, 0x8898, 0x8820, 0x85c4, -0x886c, 0x8898, 0x81f4, 0x8258, -0x83dc, 0x84b4, 0x8480, 0x8898, -0x82bc, 0x8570, 0x8898, 0x8580, -0x8218, 0x827c, 0x0, 0x0, +0x0, 0x3f636d64, 0x45727200, 0x80fc, +0x8878, 0x8878, 0x8800, 0x85a4, +0x884c, 0x8878, 0x81d4, 0x8238, +0x83bc, 0x8494, 0x8460, 0x8878, +0x829c, 0x8550, 0x8878, 0x8560, +0x81f8, 0x825c, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, @@ -8424,10 +8424,10 @@ 0x2e313220, 0x31393939, 0x2f30312f, 0x32302031, 0x393a3439, 0x3a353120, 0x73687561, 0x6e672045, 0x78702024, 0x0, 0x46575f56, 0x45525349, -0x4f4e3a20, 0x23312054, 0x75652041, 0x70722032, -0x30203137, 0x3a32333a, 0x30322050, 0x44542031, +0x4f4e3a20, 0x23312054, 0x68752041, 0x75672031, +0x32203135, 0x3a35323a, 0x32392050, 0x44542031, 0x39393900, 0x46575f43, 0x4f4d5049, 0x4c455f54, -0x494d453a, 0x2031373a, 0x32333a30, 0x32000000, +0x494d453a, 0x2031353a, 0x35323a32, 0x39000000, 0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, @@ -8503,22 +8503,22 @@ 0x6e495f46, 0x0, 0x5173436f, 0x6e734600, 0x51725072, 0x6f644600, 0x0, 0x0, 0x0, 0x50726f62, 0x65506879, 0x0, -0x6c6e6b41, 0x53535254, 0x0, 0xffc4, -0xfff4, 0x1000c, 0x10038, 0x10064, -0x10078, 0x100b4, 0x10454, 0x10234, -0x1026c, 0x10164, 0x102c0, 0x102e8, -0x1031c, 0x101a8, 0x10454, 0x10234, -0x1026c, 0x10290, 0x102c0, 0x102e8, -0x1031c, 0x10348, 0x0, 0x0, -0x0, 0x10a3c, 0x10b0c, 0x10be4, -0x10cb4, 0x10d10, 0x10dec, 0x10e14, -0x10ef0, 0x10f18, 0x110c0, 0x110e8, -0x11290, 0x11488, 0x1171c, 0x11630, -0x1171c, 0x11748, 0x112b8, 0x11460, -0x0, 0x11a4c, 0x11a8c, 0x11b1c, -0x11b60, 0x11bc4, 0x11c50, 0x11c84, -0x11d0c, 0x11da4, 0x11e74, 0x11eb4, -0x11f38, 0x11f5c, 0x1206c, 0x646f4261, +0x6c6e6b41, 0x53535254, 0x0, 0xfc78, +0xfca8, 0xfcc0, 0xfcec, 0xfd18, +0xfd2c, 0xfd68, 0x10108, 0xfee8, +0xff20, 0xfe18, 0xff74, 0xff9c, +0xffd0, 0xfe5c, 0x10108, 0xfee8, +0xff20, 0xff44, 0xff74, 0xff9c, +0xffd0, 0xfffc, 0x0, 0x0, +0x0, 0x106ec, 0x107bc, 0x10894, +0x10964, 0x109c0, 0x10a9c, 0x10ac4, +0x10ba0, 0x10bc8, 0x10d70, 0x10d98, +0x10f40, 0x11138, 0x113cc, 0x112e0, +0x113cc, 0x113f8, 0x10f68, 0x11110, +0x0, 0x116fc, 0x1173c, 0x117cc, +0x11810, 0x11874, 0x11900, 0x11934, +0x119bc, 0x11a54, 0x11b24, 0x11b64, +0x11be8, 0x11c0c, 0x11d1c, 0x646f4261, 0x73655067, 0x0, 0x0, 0x0, 0x0, 0x73746d61, 0x634c4e4b, 0x0, 0x0, 0x0 }; diff -u --recursive --new-file v2.3.16/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v2.3.16/linux/drivers/net/ariadne.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/ariadne.c Sat Sep 4 13:08:32 1999 @@ -399,8 +399,8 @@ board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ - if (!(board->Lance.RDP & INTR)) /* Check if any interrupt has been - return; generated by the board. */ + if (!(board->Lance.RDP & INTR)) /* Check if any interrupt has been */ + return; /* generated by the board. */ if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); diff -u --recursive --new-file v2.3.16/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.3.16/linux/drivers/net/defxx.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/defxx.c Thu Sep 2 10:02:32 1999 @@ -549,7 +549,7 @@ /* Get I/O base address from PCI Configuration Space */ - port = pdev->resource[1].start + port = pdev->resource[1].start; /* Verify port address range is not already being used */ diff -u --recursive --new-file v2.3.16/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.3.16/linux/drivers/net/eepro.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/eepro.c Tue Sep 7 10:14:36 1999 @@ -23,6 +23,7 @@ This is a compatibility hardware problem. Versions: + 0.11e some tweaks about multiple cards support (PdP, jul/aug 1999) 0.11d added __initdata, __init stuff; call spin_lock_init in eepro_probe1. Replaced "eepro" by dev->name. Augmented the code protected by spin_lock in interrupt routine @@ -1661,17 +1662,10 @@ #else 0x200, /* Why? */ #endif - -1, -1, -1, -1, -1, -1, -1}; -static int irq[MAX_EEPRO] = {0, 0, 0, 0, 0, 0, 0, 0}; + [1 ... MAX_EEPRO - 1] = -1 }; +static int irq[MAX_EEPRO] = { [0 ... MAX_EEPRO-1] = 0 }; static int mem[MAX_EEPRO] = { /* Size of the rx buffer in KB */ - (RCV_RAM/1024), - (RCV_RAM/1024), - (RCV_RAM/1024), - (RCV_RAM/1024), - (RCV_RAM/1024), - (RCV_RAM/1024), - (RCV_RAM/1024), - (RCV_RAM/1024) + [0 ... MAX_EEPRO-1] = RCV_RAM/1024 }; static int n_eepro = 0; @@ -1679,9 +1673,9 @@ #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 MODULE_AUTHOR("Pascal Dupuis for the 2.1 stuff (locking,...)"); MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(mem, "i"); +MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EEPRO) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EEPRO) "i"); +MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_EEPRO) "i"); #endif int diff -u --recursive --new-file v2.3.16/linux/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c --- v2.3.16/linux/drivers/net/hamradio/yam.c Wed Aug 18 11:38:51 1999 +++ linux/drivers/net/hamradio/yam.c Thu Sep 2 10:02:32 1999 @@ -131,7 +131,6 @@ #else #define __init #define __initdata -#define __initfunc(x) x #endif /* --------------------------------------------------------------------- */ @@ -1201,7 +1200,7 @@ /* --------------------------------------------------------------------- */ -__initfunc(int yam_init(struct net_device *dev)) +int __init yam_init(struct net_device *dev) { int i; @@ -1267,7 +1266,7 @@ #endif -__initfunc(int init_module(void)) +int init_module(void) { int ret = yam_init(NULL); diff -u --recursive --new-file v2.3.16/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.3.16/linux/drivers/net/irda/toshoboe.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/irda/toshoboe.c Tue Sep 7 10:14:36 1999 @@ -28,10 +28,22 @@ /* an olivetti notebook which doesn't have FIR, a toshiba libretto, and */ /* an hp printer, this works fine at 4MBPS with my HP printer */ -static char *rcsid = "$Id: toshoboe.c,v 1.5 1999/05/12 12:24:39 root Exp root $"; +static char *rcsid = "$Id: toshoboe.c,v 1.9 1999/06/29 14:21:06 root Exp $"; /* * $Log: toshoboe.c,v $ + * Revision 1.9 1999/06/29 14:21:06 root + * *** empty log message *** + * + * Revision 1.8 1999/06/29 14:15:08 root + * *** empty log message *** + * + * Revision 1.7 1999/06/29 13:46:42 root + * *** empty log message *** + * + * Revision 1.6 1999/06/29 12:31:03 root + * *** empty log message *** + * * Revision 1.5 1999/05/12 12:24:39 root * *** empty log message *** * @@ -93,6 +105,10 @@ #include #include +#ifdef CONFIG_APM +#include +#endif + #include static char *driver_name = "toshoboe"; @@ -100,8 +116,10 @@ static struct toshoboe_cb *dev_self[NSELFS + 1] = {NULL, NULL, NULL, NULL, NULL}; +static int max_baud = 4000000; + /* Shutdown the chip and point the taskfile reg somewhere else */ -static void +static void toshoboe_stopchip (struct toshoboe_cb *self) { DEBUG (4, __FUNCTION__ "()\n"); @@ -117,16 +135,19 @@ outb_p (0x00, OBOE_ISR); /*FIXME: should i do this to disbale ints */ outb_p (0x80, OBOE_RST); outb_p (0xe, OBOE_LOCK); + } /*Set the baud rate */ -static void +static void toshoboe_setbaud (struct toshoboe_cb *self, int baud) { + unsigned long flags; DEBUG (4, __FUNCTION__ "()\n"); printk (KERN_WARNING "ToshOboe: seting baud to %d\n", baud); + save_flags (flags); cli (); switch (baud) { @@ -177,7 +198,7 @@ break; } - sti (); + restore_flags (flags); outb_p (0x00, OBOE_RST); outb_p (0x80, OBOE_RST); @@ -186,7 +207,7 @@ } /* Wake the chip up and get it looking at the taskfile */ -static void +static void toshoboe_startchip (struct toshoboe_cb *self) { __u32 physaddr; @@ -217,7 +238,7 @@ } /*Let the chip look at memory */ -static void +static void toshoboe_enablebm (struct toshoboe_cb *self) { DEBUG (4, __FUNCTION__ "()\n"); @@ -225,7 +246,7 @@ } /*Don't let the chip look at memory */ -static void +static void toshoboe_disablebm (struct toshoboe_cb *self) { __u8 command; @@ -238,13 +259,15 @@ } /*setup the taskfile */ -static void +static void toshoboe_initbuffs (struct toshoboe_cb *self) { int i; + unsigned long flags; DEBUG (4, __FUNCTION__ "()\n"); + save_flags (flags); cli (); for (i = 0; i < TX_SLOTS; ++i) @@ -261,12 +284,14 @@ self->taskfile->recv[i].buffer = virt_to_bus (self->recv_bufs[i]); } - sti (); + restore_flags (flags); } + + /*Transmit something */ -static int +static int toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) { struct irda_device *idev; @@ -274,12 +299,17 @@ int mtt, len; idev = (struct irda_device *) dev->priv; - ASSERT (idev != NULL, return 0;); - ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;); + ASSERT (idev != NULL, return 0; + ); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0; + ); self = idev->priv; - ASSERT (self != NULL, return 0;); + ASSERT (self != NULL, return 0; + ); + if (self->stopped) + return 0; #ifdef ONETASK if (self->txpending) @@ -343,7 +373,7 @@ } /*interrupt handler */ -static void +static void toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs) { struct irda_device *idev = (struct irda_device *) dev_id; @@ -399,8 +429,9 @@ #endif { int len = self->taskfile->recv[self->rxs].len; - - if (len>2) len-=2; + + if (len > 2) + len -= 2; skb = dev_alloc_skb (len + 1); if (skb) @@ -459,27 +490,34 @@ /* Change the baud rate */ -static void +static void toshoboe_change_speed (struct irda_device *idev, __u32 speed) { struct toshoboe_cb *self; DEBUG (4, __FUNCTION__ "()\n"); - ASSERT (idev != NULL, return;); - ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT (idev != NULL, return; + ); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return; + ); self = idev->priv; - ASSERT (self != NULL, return;); + ASSERT (self != NULL, return; + ); + idev->io.baudrate = speed; + if (self->stopped) + return; + toshoboe_setbaud (self, speed); } /* Check all xmit_tasks finished */ -static void +static void toshoboe_wait_until_sent (struct irda_device *idev) { struct toshoboe_cb *self; @@ -487,11 +525,17 @@ DEBUG (4, __FUNCTION__ "()\n"); - ASSERT (idev != NULL, return;); - ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT (idev != NULL, return; + ); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return; + ); self = idev->priv; - ASSERT (self != NULL, return;); + ASSERT (self != NULL, return; + ); + + if (self->stopped) + return; for (i = 0; i < TX_SLOTS; ++i) { @@ -504,7 +548,7 @@ } -static int +static int toshoboe_is_receiving (struct irda_device *idev) { DEBUG (4, __FUNCTION__ "()\n"); @@ -514,7 +558,7 @@ } -static int +static int toshoboe_net_init (struct net_device *dev) { DEBUG (4, __FUNCTION__ "()\n"); @@ -527,37 +571,12 @@ } - - -static int -toshoboe_net_open (struct net_device *dev) +static void +toshoboe_initptrs (struct toshoboe_cb *self) { - struct irda_device *idev; - struct toshoboe_cb *self; - - DEBUG (4, __FUNCTION__ "()\n"); - - ASSERT (dev != NULL, return -1;); - idev = (struct irda_device *) dev->priv; - - ASSERT (idev != NULL, return 0;); - ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;); - - self = idev->priv; - ASSERT (self != NULL, return 0;); - - if (request_irq (idev->io.irq, toshoboe_interrupt, - SA_SHIRQ | SA_INTERRUPT, idev->name, (void *) idev)) - { - - return -EAGAIN; - } - - toshoboe_initbuffs (self); - toshoboe_enablebm (self); - toshoboe_startchip (self); - + unsigned long flags; + save_flags (flags); cli (); /*FIXME: need to test this carefully to check which one */ @@ -580,17 +599,59 @@ self->txpending = 0; - sti (); + restore_flags (flags); - irda_device_net_open(dev); +} + + +static int +toshoboe_net_open (struct net_device *dev) +{ + struct irda_device *idev; + struct toshoboe_cb *self; + + DEBUG (4, __FUNCTION__ "()\n"); + + ASSERT (dev != NULL, return -1; + ); + idev = (struct irda_device *) dev->priv; + + ASSERT (idev != NULL, return 0; + ); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0; + ); + + self = idev->priv; + ASSERT (self != NULL, return 0; + ); + if (self->stopped) + return 0; + + + if (request_irq (idev->io.irq, toshoboe_interrupt, + SA_SHIRQ | SA_INTERRUPT, idev->name, (void *) idev)) + { + + return -EAGAIN; + } + + toshoboe_initbuffs (self); + toshoboe_enablebm (self); + toshoboe_startchip (self); + toshoboe_initptrs (self); + + irda_device_net_open(dev); + + self->open = 1; + MOD_INC_USE_COUNT; return 0; } -static int +static int toshoboe_net_close (struct net_device *dev) { struct irda_device *idev; @@ -598,22 +659,31 @@ DEBUG (4, __FUNCTION__ "()\n"); - ASSERT (dev != NULL, return -1;); + ASSERT (dev != NULL, return -1; + ); idev = (struct irda_device *) dev->priv; - ASSERT (idev != NULL, return 0;); - ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;); + ASSERT (idev != NULL, return 0; + ); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0; + ); irda_device_net_close(dev); self = idev->priv; - ASSERT (self != NULL, return 0;); + ASSERT (self != NULL, return 0; + ); + + self->open = 0; free_irq (idev->io.irq, (void *) idev); - toshoboe_stopchip (self); - toshoboe_disablebm (self); + if (!self->stopped) + { + toshoboe_stopchip (self); + toshoboe_disablebm (self); + } MOD_DEC_USE_COUNT; @@ -625,7 +695,9 @@ #ifdef MODULE -static int +MODULE_PARM (max_baud, "i"); + +static int toshoboe_close (struct irda_device *idev) { struct toshoboe_cb *self; @@ -633,14 +705,21 @@ DEBUG (4, __FUNCTION__ "()\n"); - ASSERT (idev != NULL, return -1;); - ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return -1;); + ASSERT (idev != NULL, return -1; + ); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return -1; + ); self = idev->priv; - ASSERT (self != NULL, return -1;); + ASSERT (self != NULL, return -1; + ); - toshoboe_stopchip (self); + if (!self->stopped) + { + toshoboe_stopchip (self); + toshoboe_disablebm (self); + } release_region (idev->io.iobase, idev->io.io_ext); @@ -673,13 +752,13 @@ -static int +static int toshoboe_open (struct pci_dev *pci_dev) { struct toshoboe_cb *self; struct irda_device *idev; int i = 0; - int ok=0; + int ok = 0; DEBUG (4, __FUNCTION__ "()\n"); @@ -704,9 +783,10 @@ memset (self, 0, sizeof (struct toshoboe_cb)); + dev_self[i] = self; /*This needs moving if we ever get more than one chip */ - dev_self[i] = self; - + self->open = 0; + self->stopped = 0; self->pdev = pci_dev; self->base = pci_dev->resource[0].start; @@ -717,6 +797,7 @@ idev->io.iobase = self->base; idev->io.irq = pci_dev->irq; idev->io.io_ext = CHIP_IO_EXTENT; + idev->io.baudrate = 9600; /* Lock the port that we need */ i = check_region (idev->io.iobase, idev->io.io_ext); @@ -731,16 +812,29 @@ return -ENODEV; } - request_region (idev->io.iobase, idev->io.io_ext, driver_name); irda_init_max_qos_capabilies (&idev->qos); + idev->qos.baud_rate.bits = 0; - idev->qos.baud_rate.bits = IR_2400 | /*IR_4800 | */ IR_9600 | IR_19200 | - IR_115200; + if (max_baud >= 2400) + idev->qos.baud_rate.bits |= IR_2400; + /*if (max_baud>=4800) idev->qos.baud_rate.bits|=IR_4800; */ + if (max_baud >= 9600) + idev->qos.baud_rate.bits |= IR_9600; + if (max_baud >= 19200) + idev->qos.baud_rate.bits |= IR_19200; + if (max_baud >= 115200) + idev->qos.baud_rate.bits |= IR_115200; #ifdef ENABLE_FAST - idev->qos.baud_rate.bits|= IR_576000 | IR_1152000 | (IR_4000000 << 8); + if (max_baud >= 576000) + idev->qos.baud_rate.bits |= IR_576000; + if (max_baud >= 1152000) + idev->qos.baud_rate.bits |= IR_1152000; + if (max_baud >= 4000000) + idev->qos.baud_rate.bits |= (IR_4000000 << 8); #endif + idev->qos.min_turn_time.bits = 0xff; /*FIXME: what does this do? */ irda_qos_bits_to_value (&idev->qos); @@ -748,7 +842,8 @@ idev->flags = IFF_SIR | IFF_DMA | IFF_PIO; #ifdef ENABLE_FAST - idev->flags |= IFF_FIR; + if (max_baud >= 576000) + idev->flags |= IFF_FIR; #endif /* These aren't much use as we need to have a whole panoply of @@ -774,12 +869,13 @@ self->txs = 0; self->rxs = 0; - self->taskfilebuf = kmalloc (OBOE_TASK_BUF_LEN, GFP_KERNEL | GFP_DMA); - if (!self->taskfilebuf) { - printk(KERN_ERR "toshoboe: kmalloc for DMA failed()\n"); - kfree(self); - return -ENOMEM; - } + self->taskfilebuf = kmalloc (OBOE_TASK_BUF_LEN, GFP_KERNEL); + if (!self->taskfilebuf) + { + printk (KERN_ERR "toshoboe: kmalloc for DMA failed()\n"); + kfree (self); + return -ENOMEM; + } memset (self->taskfilebuf, 0, OBOE_TASK_BUF_LEN); @@ -798,27 +894,35 @@ for (i = 0; i < TX_SLOTS; ++i) { self->xmit_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL | GFP_DMA); - if (self->xmit_bufs[i]) ok++; + if (self->xmit_bufs[i]) + ok++; } for (i = 0; i < RX_SLOTS; ++i) { self->recv_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL | GFP_DMA); - if (self->recv_bufs[i]) ok++; + if (self->recv_bufs[i]) + ok++; } - if (ok!=RX_SLOTS+TX_SLOTS) { - printk(KERN_ERR "toshoboe: kmalloc for buffers failed()\n"); + if (ok != RX_SLOTS + TX_SLOTS) + { + printk (KERN_ERR "toshoboe: kmalloc for buffers failed()\n"); - for (i = 0; i < TX_SLOTS; ++i) if (self->xmit_bufs[i]) kfree(self->xmit_bufs[i]); - for (i = 0; i < RX_SLOTS; ++i) if (self->recv_bufs[i]) kfree(self->recv_bufs[i]); + for (i = 0; i < TX_SLOTS; ++i) + if (self->xmit_bufs[i]) + kfree (self->xmit_bufs[i]); + for (i = 0; i < RX_SLOTS; ++i) + if (self->recv_bufs[i]) + kfree (self->recv_bufs[i]); - kfree(self); - return -ENOMEM; + kfree (self); + return -ENOMEM; - } + } + request_region (idev->io.iobase, idev->io.io_ext, driver_name); irda_device_open (idev, driver_name, self); @@ -833,6 +937,121 @@ return (0); } +#ifdef CONFIG_APM +static void +toshoboe_gotosleep (struct toshoboe_cb *self) +{ + int i = 10; + + printk (KERN_WARNING "ToshOboe: suspending\n"); + + if (self->stopped) + return; + + self->stopped = 1; + + if (!self->open) + return; + +/*FIXME: can't sleep here wait one second */ + + while ((i--) && (self->txpending)) + udelay (100000); + + toshoboe_stopchip (self); + toshoboe_disablebm (self); + + self->txpending = 0; + +} + + +static void +toshoboe_wakeup (struct toshoboe_cb *self) +{ + struct irda_device *idev = &self->idev; + struct net_device *dev = &idev->netdev; + unsigned long flags; + + if (!self->stopped) + return; + + if (!self->open) + { + self->stopped = 0; + return; + } + + save_flags (flags); + cli (); + + toshoboe_initbuffs (self); + toshoboe_enablebm (self); + toshoboe_startchip (self); + + toshoboe_setbaud (self, idev->io.baudrate); + + toshoboe_initptrs (self); + + + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + self->stopped = 0; + + restore_flags (flags); + printk (KERN_WARNING "ToshOboe: waking up\n"); + +} + +static int +toshoboe_apmproc (apm_event_t event) +{ + static int down = 0; /*Filter out double events */ + int i; + + switch (event) + { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (!down) + { + + for (i = 0; i < 4; i++) + { + if (dev_self[i]) + toshoboe_gotosleep (dev_self[i]); + } + + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (down) + { + + + + for (i = 0; i < 4; i++) + { + if (dev_self[i]) + toshoboe_wakeup (dev_self[i]); + } + + + + } + down = 0; + break; + } + return 0; +} + + +#endif + int __init toshoboe_init (void) { struct pci_dev *pci_dev = NULL; @@ -844,8 +1063,8 @@ PCI_DEVICE_ID_FIR701, pci_dev); if (pci_dev) { - printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %ld\n", - pci_dev->resource[0], + printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n", + pci_dev->resource[0].start, pci_dev->irq); if (!toshoboe_open (pci_dev)) @@ -855,15 +1074,21 @@ } while (pci_dev); + if (found) - return 0; + { +#ifdef CONFIG_APM + apm_register_callback (toshoboe_apmproc); +#endif + return 0; + } return -ENODEV; } #ifdef MODULE -static void +static void toshoboe_cleanup (void) { int i; @@ -875,18 +1100,23 @@ if (dev_self[i]) toshoboe_close (&(dev_self[i]->idev)); } + +#ifdef CONFIG_APM + apm_unregister_callback (toshoboe_apmproc); +#endif + } -int +int init_module (void) { return toshoboe_init (); } -void +void cleanup_module (void) { toshoboe_cleanup (); diff -u --recursive --new-file v2.3.16/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.3.16/linux/drivers/net/plip.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/plip.c Tue Sep 7 10:14:37 1999 @@ -2,17 +2,22 @@ /* PLIP: A parallel port "network" driver for Linux. */ /* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */ /* - * Authors: Donald Becker, - * Tommy Thorn, - * Tanabe Hiroyasu, - * Alan Cox, - * Peter Bauer, <100136.3530@compuserve.com> - * Niibe Yutaka, + * Authors: Donald Becker + * Tommy Thorn + * Tanabe Hiroyasu + * Alan Cox + * Peter Bauer <100136.3530@compuserve.com> + * Niibe Yutaka + * Nimrod Zimerman * + * Enhancements: * Modularization and ifreq/ifmap support by Alan Cox. * Rewritten by Niibe Yutaka. - * parport-sharing awareness code by Philip Blundell. + * parport-sharing awareness code by Philip Blundell. * SMP locking by Niibe Yutaka. + * Support for parallel ports with no IRQ (poll mode), + * Modifications to use the parallel port API + * by Nimrod Zimerman. * * Fixes: * Niibe Yutaka @@ -49,7 +54,7 @@ * To use with DOS box, please do (Turn on ARP switch): * # ifconfig plip[0-2] arp */ -static const char *version = "NET3 PLIP version 2.3-parport gniibe@mri.co.jp\n"; +static const char *version = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n"; /* Sources: @@ -57,7 +62,7 @@ "parallel.asm" parallel port packet driver. The "Crynwr" parallel port standard specifies the following protocol: - Trigger by sending '0x08' (this cause interrupt on other end) + Trigger by sending nibble '0x8' (this causes interrupt on other end) count-low octet count-high octet ... data octets @@ -93,7 +98,6 @@ #include #include #include -#include #include #include #include @@ -105,6 +109,7 @@ #include #include #include +#include #include #include @@ -112,6 +117,7 @@ #include #include #include +#include #include @@ -124,8 +130,8 @@ #endif static unsigned int net_debug = NET_DEBUG; -#define ENABLE(irq) enable_irq(irq) -#define DISABLE(irq) disable_irq(irq) +#define ENABLE(irq) if (irq != -1) enable_irq(irq) +#define DISABLE(irq) if (irq != -1) disable_irq(irq) /* In micro second */ #define PLIP_DELAY_UNIT 1 @@ -136,22 +142,21 @@ /* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */ #define PLIP_NIBBLE_WAIT 3000 -#define PAR_INTR_ON (LP_PINITP|LP_PSELECP|LP_PINTEN) -#define PAR_INTR_OFF (LP_PINITP|LP_PSELECP) -#define PAR_DATA(dev) ((dev)->base_addr+0) -#define PAR_STATUS(dev) ((dev)->base_addr+1) -#define PAR_CONTROL(dev) ((dev)->base_addr+2) - -/* Bottom halfs */ +/* Bottom halves */ static void plip_kick_bh(struct net_device *dev); static void plip_bh(struct net_device *dev); +static void plip_timer_bh(struct net_device *dev); /* Interrupt handler */ static void plip_interrupt(int irq, void *dev_id, struct pt_regs *regs); /* Functions for DEV methods */ -static int plip_rebuild_header(struct sk_buff *skb); static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev); +static int plip_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, + void *saddr, unsigned len); +static int plip_hard_header_cache(struct neighbour *neigh, + struct hh_cache *hh); static int plip_open(struct net_device *dev); static int plip_close(struct net_device *dev); static struct net_device_stats *plip_get_stats(struct net_device *dev); @@ -210,6 +215,7 @@ struct net_device_stats enet_stats; struct tq_struct immediate; struct tq_struct deferred; + struct tq_struct timer; struct plip_local snd_data; struct plip_local rcv_data; struct pardevice *pardev; @@ -220,10 +226,52 @@ int is_deferred; int port_owner; int should_relinquish; - int (*orig_rebuild_header)(struct sk_buff *skb); + int (*orig_hard_header)(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, + void *saddr, unsigned len); + int (*orig_hard_header_cache)(struct neighbour *neigh, + struct hh_cache *hh); spinlock_t lock; + atomic_t kill_timer; + struct semaphore killed_timer_sem; }; +inline static void enable_parport_interrupts (struct net_device *dev) +{ + if (dev->irq != -1) + { + struct parport *port = + ((struct net_local *)dev->priv)->pardev->port; + port->ops->enable_irq (port); + } +} + +inline static void disable_parport_interrupts (struct net_device *dev) +{ + if (dev->irq != -1) + { + struct parport *port = + ((struct net_local *)dev->priv)->pardev->port; + port->ops->disable_irq (port); + } +} + +inline static void write_data (struct net_device *dev, unsigned char data) +{ + struct parport *port = + ((struct net_local *)dev->priv)->pardev->port; + + port->ops->write_data (port, data); +} + +inline static unsigned char read_status (struct net_device *dev) +{ + struct parport *port = + ((struct net_local *)dev->priv)->pardev->port; + + return port->ops->read_status (port); +} + /* Entry point of PLIP driver. Probe the hardware, and register/initialize the driver. @@ -243,8 +291,8 @@ dev->base_addr = pb->base; if (pb->irq == -1) { - printk(KERN_INFO "plip: %s has no IRQ.\n", pb->name); - return -ENODEV; + printk(KERN_INFO "plip: %s has no IRQ. Using IRQ-less mode," + "which is fairly inefficient!\n", pb->name); } pardev = parport_register_device(pb, dev->name, plip_preempt, @@ -255,21 +303,26 @@ return -ENODEV; printk(KERN_INFO "%s", version); - printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d\n", dev->name, - dev->base_addr, dev->irq); + if (dev->irq != -1) + printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d.\n", + dev->name, dev->base_addr, dev->irq); + else + printk(KERN_INFO "%s: Parallel port at %#3lx, not using IRQ.\n", + dev->name, dev->base_addr); /* Fill in the generic fields of the device structure. */ ether_setup(dev); /* Then, override parts of it */ - dev->hard_start_xmit = plip_tx_packet; - dev->open = plip_open; - dev->stop = plip_close; - dev->get_stats = plip_get_stats; - dev->set_config = plip_config; - dev->do_ioctl = plip_ioctl; - dev->tx_queue_len = 10; - dev->flags = IFF_POINTOPOINT|IFF_NOARP; + dev->hard_start_xmit = plip_tx_packet; + dev->open = plip_open; + dev->stop = plip_close; + dev->get_stats = plip_get_stats; + dev->set_config = plip_config; + dev->do_ioctl = plip_ioctl; + dev->header_cache_update = NULL; + dev->tx_queue_len = 10; + dev->flags = IFF_POINTOPOINT|IFF_NOARP; memset(dev->dev_addr, 0xfc, ETH_ALEN); /* Set the private structure */ @@ -282,8 +335,12 @@ memset(dev->priv, 0, sizeof(struct net_local)); nl = (struct net_local *) dev->priv; - nl->orig_rebuild_header = dev->rebuild_header; - dev->rebuild_header = plip_rebuild_header; + nl->orig_hard_header = dev->hard_header; + dev->hard_header = plip_hard_header; + + nl->orig_hard_header_cache = dev->hard_header_cache; + dev->hard_header_cache = plip_hard_header_cache; + nl->pardev = pardev; nl->port_owner = 0; @@ -295,13 +352,21 @@ /* Initialize task queue structures */ nl->immediate.next = NULL; nl->immediate.sync = 0; - nl->immediate.routine = (void *)(void *)plip_bh; + nl->immediate.routine = (void (*)(void *))plip_bh; nl->immediate.data = dev; nl->deferred.next = NULL; nl->deferred.sync = 0; - nl->deferred.routine = (void *)(void *)plip_kick_bh; + nl->deferred.routine = (void (*)(void *))plip_kick_bh; nl->deferred.data = dev; + + if (dev->irq == -1) { + nl->timer.next = NULL; + nl->timer.sync = 0; + nl->timer.routine = (void (*)(void *))plip_timer_bh; + nl->timer.data = dev; + } + spin_lock_init(&nl->lock); return 0; @@ -373,6 +438,22 @@ } } +static void +plip_timer_bh(struct net_device *dev) +{ + struct net_local *nl = (struct net_local *)dev->priv; + + if (!(atomic_read (&nl->kill_timer))) { + if (!dev->interrupt) + plip_interrupt (-1, dev, NULL); + + queue_task (&nl->timer, &tq_timer); + } + else { + up (&nl->killed_timer_sem); + } +} + static int plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv, @@ -401,7 +482,7 @@ /* Try again later */ return TIMEOUT; } - c0 = inb(PAR_STATUS(dev)); + c0 = read_status(dev); printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n", dev->name, snd->state, c0); } else @@ -420,7 +501,7 @@ /* Try again later */ return TIMEOUT; } - c0 = inb(PAR_STATUS(dev)); + c0 = read_status(dev); printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n", dev->name, rcv->state, c0); } @@ -441,10 +522,10 @@ DISABLE(dev->irq); synchronize_irq(); } - outb(PAR_INTR_OFF, PAR_CONTROL(dev)); + disable_parport_interrupts (dev); dev->tbusy = 1; nl->connection = PLIP_CN_ERROR; - outb(0x00, PAR_DATA(dev)); + write_data (dev, 0x00); return TIMEOUT; } @@ -459,7 +540,7 @@ /* PLIP_RECEIVE --- receive a byte(two nibbles) Returns OK on success, TIMEOUT on timeout */ inline static int -plip_receive(unsigned short nibble_timeout, unsigned short status_addr, +plip_receive(unsigned short nibble_timeout, struct net_device *dev, enum plip_nibble_state *ns_p, unsigned char *data_p) { unsigned char c0, c1; @@ -469,10 +550,10 @@ case PLIP_NB_BEGIN: cx = nibble_timeout; while (1) { - c0 = inb(status_addr); + c0 = read_status(dev); udelay(PLIP_DELAY_UNIT); if ((c0 & 0x80) == 0) { - c1 = inb(status_addr); + c1 = read_status(dev); if (c0 == c1) break; } @@ -480,17 +561,16 @@ return TIMEOUT; } *data_p = (c0 >> 3) & 0x0f; - outb(0x10, --status_addr); /* send ACK */ - status_addr++; + write_data (dev, 0x10); /* send ACK */ *ns_p = PLIP_NB_1; case PLIP_NB_1: cx = nibble_timeout; while (1) { - c0 = inb(status_addr); + c0 = read_status(dev); udelay(PLIP_DELAY_UNIT); if (c0 & 0x80) { - c1 = inb(status_addr); + c1 = read_status(dev); if (c0 == c1) break; } @@ -498,8 +578,7 @@ return TIMEOUT; } *data_p |= (c0 << 1) & 0xf0; - outb(0x00, --status_addr); /* send ACK */ - status_addr++; + write_data (dev, 0x00); /* send ACK */ *ns_p = PLIP_NB_BEGIN; case PLIP_NB_2: break; @@ -512,7 +591,6 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv) { - unsigned short status_addr = PAR_STATUS(dev); unsigned short nibble_timeout = nl->nibble; unsigned char *lbuf; @@ -520,9 +598,9 @@ case PLIP_PK_TRIGGER: DISABLE(dev->irq); /* Don't need to synchronize irq, as we can safely ignore it */ - outb(PAR_INTR_OFF, PAR_CONTROL(dev)); + disable_parport_interrupts (dev); dev->interrupt = 0; - outb(0x01, PAR_DATA(dev)); /* send ACK */ + write_data (dev, 0x01); /* send ACK */ if (net_debug > 2) printk(KERN_DEBUG "%s: receive start\n", dev->name); rcv->state = PLIP_PK_LENGTH_LSB; @@ -530,26 +608,26 @@ case PLIP_PK_LENGTH_LSB: if (snd->state != PLIP_PK_DONE) { - if (plip_receive(nl->trigger, status_addr, + if (plip_receive(nl->trigger, dev, &rcv->nibble, &rcv->length.b.lsb)) { /* collision, here dev->tbusy == 1 */ rcv->state = PLIP_PK_DONE; nl->is_deferred = 1; nl->connection = PLIP_CN_SEND; queue_task(&nl->deferred, &tq_timer); - outb(PAR_INTR_ON, PAR_CONTROL(dev)); + enable_parport_interrupts (dev); ENABLE(dev->irq); return OK; } } else { - if (plip_receive(nibble_timeout, status_addr, + if (plip_receive(nibble_timeout, dev, &rcv->nibble, &rcv->length.b.lsb)) return TIMEOUT; } rcv->state = PLIP_PK_LENGTH_MSB; case PLIP_PK_LENGTH_MSB: - if (plip_receive(nibble_timeout, status_addr, + if (plip_receive(nibble_timeout, dev, &rcv->nibble, &rcv->length.b.msb)) return TIMEOUT; if (rcv->length.h > dev->mtu + dev->hard_header_len @@ -572,7 +650,7 @@ case PLIP_PK_DATA: lbuf = rcv->skb->data; do - if (plip_receive(nibble_timeout, status_addr, + if (plip_receive(nibble_timeout, dev, &rcv->nibble, &lbuf[rcv->byte])) return TIMEOUT; while (++rcv->byte < rcv->length.h); @@ -582,7 +660,7 @@ rcv->state = PLIP_PK_CHECKSUM; case PLIP_PK_CHECKSUM: - if (plip_receive(nibble_timeout, status_addr, + if (plip_receive(nibble_timeout, dev, &rcv->nibble, &rcv->data)) return TIMEOUT; if (rcv->data != rcv->checksum) { @@ -604,20 +682,20 @@ printk(KERN_DEBUG "%s: receive end\n", dev->name); /* Close the connection. */ - outb (0x00, PAR_DATA(dev)); + write_data (dev, 0x00); spin_lock_irq(&nl->lock); if (snd->state != PLIP_PK_DONE) { nl->connection = PLIP_CN_SEND; spin_unlock_irq(&nl->lock); queue_task(&nl->immediate, &tq_immediate); mark_bh(IMMEDIATE_BH); - outb(PAR_INTR_ON, PAR_CONTROL(dev)); + enable_parport_interrupts (dev); ENABLE(dev->irq); return OK; } else { nl->connection = PLIP_CN_NONE; spin_unlock_irq(&nl->lock); - outb(PAR_INTR_ON, PAR_CONTROL(dev)); + enable_parport_interrupts (dev); ENABLE(dev->irq); return OK; } @@ -628,7 +706,7 @@ /* PLIP_SEND --- send a byte (two nibbles) Returns OK on success, TIMEOUT when timeout */ inline static int -plip_send(unsigned short nibble_timeout, unsigned short data_addr, +plip_send(unsigned short nibble_timeout, struct net_device *dev, enum plip_nibble_state *ns_p, unsigned char data) { unsigned char c0; @@ -636,37 +714,34 @@ switch (*ns_p) { case PLIP_NB_BEGIN: - outb((data & 0x0f), data_addr); + write_data (dev, data & 0x0f); *ns_p = PLIP_NB_1; case PLIP_NB_1: - outb(0x10 | (data & 0x0f), data_addr); + write_data (dev, 0x10 | (data & 0x0f)); cx = nibble_timeout; - data_addr++; while (1) { - c0 = inb(data_addr); + c0 = read_status(dev); if ((c0 & 0x80) == 0) break; if (--cx == 0) return TIMEOUT; udelay(PLIP_DELAY_UNIT); } - outb(0x10 | (data >> 4), --data_addr); + write_data (dev, 0x10 | (data >> 4)); *ns_p = PLIP_NB_2; case PLIP_NB_2: - outb((data >> 4), data_addr); - data_addr++; + write_data (dev, (data >> 4)); cx = nibble_timeout; while (1) { - c0 = inb(data_addr); + c0 = read_status(dev); if (c0 & 0x80) break; if (--cx == 0) return TIMEOUT; udelay(PLIP_DELAY_UNIT); } - data_addr--; *ns_p = PLIP_NB_BEGIN; return OK; } @@ -678,7 +753,6 @@ plip_send_packet(struct net_device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv) { - unsigned short data_addr = PAR_DATA(dev); unsigned short nibble_timeout = nl->nibble; unsigned char *lbuf; unsigned char c0; @@ -693,11 +767,11 @@ switch (snd->state) { case PLIP_PK_TRIGGER: - if ((inb(PAR_STATUS(dev)) & 0xf8) != 0x80) + if ((read_status(dev) & 0xf8) != 0x80) return HS_TIMEOUT; /* Trigger remote rx interrupt. */ - outb(0x08, data_addr); + write_data (dev, 0x08); cx = nl->trigger; while (1) { udelay(PLIP_DELAY_UNIT); @@ -708,7 +782,7 @@ nl->enet_stats.collisions++; return OK; } - c0 = inb(PAR_STATUS(dev)); + c0 = read_status(dev); if (c0 & 0x08) { spin_unlock_irq(&nl->lock); DISABLE(dev->irq); @@ -724,7 +798,7 @@ nl->enet_stats.collisions++; return OK; } - outb(PAR_INTR_OFF, PAR_CONTROL(dev)); + disable_parport_interrupts (dev); if (net_debug > 2) printk(KERN_DEBUG "%s: send start\n", dev->name); snd->state = PLIP_PK_LENGTH_LSB; @@ -734,19 +808,19 @@ } spin_unlock_irq(&nl->lock); if (--cx == 0) { - outb(0x00, data_addr); + write_data (dev, 0x00); return HS_TIMEOUT; } } case PLIP_PK_LENGTH_LSB: - if (plip_send(nibble_timeout, data_addr, + if (plip_send(nibble_timeout, dev, &snd->nibble, snd->length.b.lsb)) return TIMEOUT; snd->state = PLIP_PK_LENGTH_MSB; case PLIP_PK_LENGTH_MSB: - if (plip_send(nibble_timeout, data_addr, + if (plip_send(nibble_timeout, dev, &snd->nibble, snd->length.b.msb)) return TIMEOUT; snd->state = PLIP_PK_DATA; @@ -755,7 +829,7 @@ case PLIP_PK_DATA: do - if (plip_send(nibble_timeout, data_addr, + if (plip_send(nibble_timeout, dev, &snd->nibble, lbuf[snd->byte])) return TIMEOUT; while (++snd->byte < snd->length.h); @@ -765,7 +839,7 @@ snd->state = PLIP_PK_CHECKSUM; case PLIP_PK_CHECKSUM: - if (plip_send(nibble_timeout, data_addr, + if (plip_send(nibble_timeout, dev, &snd->nibble, snd->checksum)) return TIMEOUT; @@ -776,14 +850,14 @@ case PLIP_PK_DONE: /* Close the connection */ - outb (0x00, data_addr); + write_data (dev, 0x00); snd->skb = NULL; if (net_debug > 2) printk(KERN_DEBUG "%s: send end\n", dev->name); nl->connection = PLIP_CN_CLOSING; nl->is_deferred = 1; queue_task(&nl->deferred, &tq_timer); - outb(PAR_INTR_ON, PAR_CONTROL(dev)); + enable_parport_interrupts (dev); ENABLE(dev->irq); return OK; } @@ -815,7 +889,7 @@ { unsigned char status; - status = inb(PAR_STATUS(dev)); + status = read_status(dev); if ((status & 0xf8) == 0x80) { if (net_debug > 2) printk(KERN_DEBUG "%s: reset interface.\n", dev->name); @@ -823,7 +897,7 @@ nl->should_relinquish = 0; dev->tbusy = 0; dev->interrupt = 0; - outb(PAR_INTR_ON, PAR_CONTROL(dev)); + enable_parport_interrupts (dev); ENABLE(dev->irq); mark_bh(NET_BH); } else { @@ -854,9 +928,9 @@ if (dev->interrupt) return; - c0 = inb(PAR_STATUS(dev)); + c0 = read_status(dev); if ((c0 & 0xf8) != 0xc0) { - if (net_debug > 1) + if ((dev->irq != -1) && (net_debug > 1)) printk(KERN_DEBUG "%s: spurious interrupt\n", dev->name); return; } @@ -893,22 +967,6 @@ } } -/* We don't need to send arp, for plip is point-to-point. */ -static int -plip_rebuild_header(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct net_local *nl = (struct net_local *)dev->priv; - struct ethhdr *eth = (struct ethhdr *)skb->data; - - if ((dev->flags & IFF_NOARP)==0) - return nl->orig_rebuild_header(skb); - - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - memcpy(eth->h_dest, dev->broadcast, dev->addr_len); - return 0; -} - static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev) { @@ -955,6 +1013,51 @@ return 0; } +static void +plip_rewrite_address(struct net_device *dev, struct ethhdr *eth) +{ + struct in_device *in_dev; + + if ((in_dev=dev->ip_ptr) != NULL) { + /* Any address will do - we take the first */ + struct in_ifaddr *ifa=in_dev->ifa_list; + if (ifa != NULL) { + memcpy(eth->h_source, dev->dev_addr, 6); + memset(eth->h_dest, 0xfc, 2); + memcpy(eth->h_dest+2, &ifa->ifa_address, 4); + } + } +} + +static int +plip_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, + void *saddr, unsigned len) +{ + struct net_local *nl = (struct net_local *)dev->priv; + int ret; + + if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0) + plip_rewrite_address (dev, (struct ethhdr *)skb->data); + + return ret; +} + +int plip_hard_header_cache(struct neighbour *neigh, + struct hh_cache *hh) +{ + struct net_local *nl = (struct net_local *)neigh->dev->priv; + int ret; + + if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0) + { + struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2); + plip_rewrite_address (neigh->dev, eth); + } + + return ret; +} + /* Open/initialize the board. This is called (in the current kernel) sometime after booting when the 'ifconfig' program is run. @@ -976,10 +1079,15 @@ nl->should_relinquish = 0; /* Clear the data port. */ - outb (0x00, PAR_DATA(dev)); + write_data (dev, 0x00); /* Enable rx interrupt. */ - outb(PAR_INTR_ON, PAR_CONTROL(dev)); + enable_parport_interrupts (dev); + if (dev->irq == -1) + { + atomic_set (&nl->kill_timer, 0); + queue_task (&nl->timer, &tq_timer); + } /* Initialize the state machine. */ nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE; @@ -988,21 +1096,24 @@ nl->is_deferred = 0; /* Fill in the MAC-level header. - (ab)Use "dev->broadcast" to store point-to-point MAC address. - - PLIP doesn't have a real mac address, but we need to create one - to be DOS compatible. */ - memset(dev->dev_addr, 0xfc, ETH_ALEN); - memset(dev->broadcast, 0xfc, ETH_ALEN); + We used to abuse dev->broadcast to store the point-to-point + MAC address, but we no longer do it. Instead, we fetch the + interface address whenever it is needed, which is cheap enough + because we use the hh_cache. Actually, abusing dev->broadcast + didn't work, because when using plip_open the point-to-point + address isn't yet known. + PLIP doesn't have a real MAC address, but we need it to be + DOS compatible, and to properly support taps (otherwise, + when the device address isn't identical to the address of a + received frame, the kernel incorrectly drops it). */ if ((in_dev=dev->ip_ptr) != NULL) { - /* - * Any address will do - we take the first - */ + /* Any address will do - we take the first. We already + have the first two bytes filled with 0xfc, from + plip_init_dev(). */ struct in_ifaddr *ifa=in_dev->ifa_list; if (ifa != NULL) { memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); - memcpy(dev->broadcast+2, &ifa->ifa_address, 4); } } @@ -1027,6 +1138,13 @@ DISABLE(dev->irq); synchronize_irq(); + if (dev->irq == -1) + { + init_MUTEX_LOCKED (&nl->killed_timer_sem); + atomic_set (&nl->kill_timer, 1); + down (&nl->killed_timer_sem); + } + #ifdef NOTDEF outb(0x00, PAR_DATA(dev)); #endif @@ -1095,7 +1213,7 @@ if (!parport_claim(nl->pardev)) { nl->port_owner = 1; /* Clear the data port. */ - outb (0x00, PAR_DATA(dev)); + write_data (dev, 0x00); } return; diff -u --recursive --new-file v2.3.16/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c --- v2.3.16/linux/drivers/net/ppp_async.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/ppp_async.c Thu Sep 2 09:25:13 1999 @@ -20,7 +20,7 @@ * ==FILEVERSION 990806== */ -/* $Id$ */ +/* $Id: ppp_async.c,v 1.3 1999/09/02 05:30:10 paulus Exp $ */ #include #include @@ -895,8 +895,7 @@ /* stuff the chars in the skb */ skb = ap->rpkt; if (skb == 0) { - skb = alloc_skb(ap->mru + PPP_HDRLEN + 2, - GFP_ATOMIC); + skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2); if (skb == 0) goto nomem; /* Try to get the payload 4-byte aligned */ diff -u --recursive --new-file v2.3.16/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c --- v2.3.16/linux/drivers/net/ppp_generic.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/ppp_generic.c Thu Sep 2 09:25:17 1999 @@ -22,7 +22,7 @@ * ==FILEVERSION 990806== */ -/* $Id$ */ +/* $Id: ppp_generic.c,v 1.3 1999/09/02 05:30:12 paulus Exp $ */ #include #include @@ -94,7 +94,7 @@ void *rc_state; /* its internal state */ unsigned long last_xmit; /* jiffies when last pkt sent */ unsigned long last_recv; /* jiffies when last pkt rcvd */ - struct net_device dev; /* network interface device */ + struct net_device *dev; /* network interface device */ struct net_device_stats stats; /* statistics */ }; @@ -144,6 +144,7 @@ static struct compressor *find_compressor(int type); static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); static struct ppp *ppp_create_unit(int unit, int *retp); +static void ppp_release_unit(struct ppp *ppp); static struct ppp *ppp_find_unit(int unit); /* Translates a PPP protocol number to a NP index (NP == network protocol) */ @@ -267,49 +268,11 @@ static int ppp_release(struct inode *inode, struct file *file) { struct ppp *ppp = (struct ppp *) file->private_data; - struct list_head *list, *next; - int ref; - - if (ppp == 0) - goto out; - file->private_data = 0; - spin_lock(&all_ppp_lock); - ref = --ppp->refcnt; - if (ref == 0) - list_del(&ppp->list); - spin_unlock(&all_ppp_lock); - if (ref != 0) - goto out; - /* Last fd open to this ppp unit is being closed - - mark the interface down, free the ppp unit */ - rtnl_lock(); - dev_close(&ppp->dev); - rtnl_unlock(); - for (list = ppp->channels.next; list != &ppp->channels; list = next) { - /* forcibly detach this channel */ - struct channel *chan; - chan = list_entry(list, struct channel, list); - chan->chan->ppp = 0; - next = list->next; - kfree(chan); + if (ppp != 0) { + file->private_data = 0; + ppp_release_unit(ppp); } - - /* Free up resources. */ - ppp_ccp_closed(ppp); - lock_xmit_path(ppp); - lock_recv_path(ppp); - if (ppp->vj) { - slhc_free(ppp->vj); - ppp->vj = 0; - } - free_skbs(&ppp->xq); - free_skbs(&ppp->rq); - free_skbs(&ppp->recv_pending); - unregister_netdev(&ppp->dev); - kfree(ppp); - - out: MOD_DEC_USE_COUNT; return 0; } @@ -453,6 +416,12 @@ return -ENXIO; err = -EFAULT; switch (cmd) { + case PPPIOCDETACH: + file->private_data = 0; + ppp_release_unit(ppp); + err = 0; + break; + case PPPIOCSMRU: if (get_user(val, (int *) arg)) break; @@ -832,7 +801,7 @@ /* try to do packet compression */ if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0 && proto != PPP_LCP && proto != PPP_CCP) { - new_skb = alloc_skb(ppp->dev.mtu + PPP_HDRLEN, GFP_ATOMIC); + new_skb = alloc_skb(ppp->dev->mtu + PPP_HDRLEN, GFP_ATOMIC); if (new_skb == 0) { printk(KERN_ERR "PPP: no memory (comp pkt)\n"); goto drop; @@ -841,7 +810,7 @@ /* compressor still expects A/C bytes in hdr */ len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2, new_skb->data, skb->len + 2, - ppp->dev.mtu + PPP_HDRLEN); + ppp->dev->mtu + PPP_HDRLEN); if (len > 0 && (ppp->flags & SC_CCP_UP)) { kfree_skb(skb); skb = new_skb; @@ -853,6 +822,10 @@ } } + /* for data packets, record the time */ + if (proto < 0x8000) + ppp->last_xmit = jiffies; + /* * If we are waiting for traffic (demand dialling), * queue it up for pppd to receive. @@ -994,7 +967,7 @@ goto err; if (skb_tailroom(skb) < 124) { /* copy to a new sk_buff with more tailroom */ - ns = alloc_skb(skb->len + 128, GFP_ATOMIC); + ns = dev_alloc_skb(skb->len + 128); if (ns == 0) { printk(KERN_ERR"PPP: no memory (VJ decomp)\n"); goto err; @@ -1051,12 +1024,12 @@ } else { /* network protocol frame - give it to the kernel */ ppp->last_recv = jiffies; - if ((ppp->dev.flags & IFF_UP) == 0 + if ((ppp->dev->flags & IFF_UP) == 0 || ppp->npmode[npi] != NPMODE_PASS) { kfree_skb(skb); } else { skb_pull(skb, 2); /* chop off protocol */ - skb->dev = &ppp->dev; + skb->dev = ppp->dev; skb->protocol = htons(npindex_to_ethertype[npi]); skb->mac.raw = skb->data; netif_rx(skb); @@ -1079,7 +1052,7 @@ int len; if (proto == PPP_COMP) { - ns = alloc_skb(ppp->mru + PPP_HDRLEN, GFP_ATOMIC); + ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN); if (ns == 0) { printk(KERN_ERR "ppp_receive: no memory\n"); goto err; @@ -1189,7 +1162,7 @@ if (trylock_xmit_path(ppp)) ppp_xmit_unlock(ppp); if (ppp->xmit_pending == 0) { - ppp->dev.tbusy = 0; + ppp->dev->tbusy = 0; mark_bh(NET_BH); } } @@ -1476,6 +1449,7 @@ ppp_create_unit(int unit, int *retp) { struct ppp *ppp; + struct net_device *dev; struct list_head *list; int last_unit = -1; int ret = -EEXIST; @@ -1501,6 +1475,12 @@ if (ppp == 0) goto out; memset(ppp, 0, sizeof(struct ppp)); + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (dev == 0) { + kfree(ppp); + goto out; + } + memset(dev, 0, sizeof(struct net_device)); ppp->index = unit; sprintf(ppp->name, "ppp%d", unit); @@ -1514,13 +1494,18 @@ INIT_LIST_HEAD(&ppp->channels); skb_queue_head_init(&ppp->recv_pending); - ppp->dev.init = ppp_net_init; - ppp->dev.name = ppp->name; - ppp->dev.priv = ppp; + ppp->dev = dev; + dev->init = ppp_net_init; + dev->name = ppp->name; + dev->priv = ppp; + dev->new_style = 1; - ret = register_netdev(&ppp->dev); + rtnl_lock(); + ret = register_netdevice(dev); + rtnl_unlock(); if (ret != 0) { printk(KERN_ERR "PPP: couldn't register device (%d)\n", ret); + kfree(dev); kfree(ppp); goto out; } @@ -1535,6 +1520,59 @@ } /* + * Remove a reference to a ppp unit, and destroy it if + * the reference count goes to 0. + */ +static void ppp_release_unit(struct ppp *ppp) +{ + struct list_head *list, *next; + int ref; + + spin_lock(&all_ppp_lock); + ref = --ppp->refcnt; + if (ref == 0) + list_del(&ppp->list); + spin_unlock(&all_ppp_lock); + if (ref != 0) + return; + + /* Last fd open to this ppp unit is being closed or detached: + mark the interface down, free the ppp unit */ + if (ppp->dev) { + rtnl_lock(); + dev_close(ppp->dev); + rtnl_unlock(); + } + for (list = ppp->channels.next; list != &ppp->channels; list = next) { + /* forcibly detach this channel */ + struct channel *chan; + chan = list_entry(list, struct channel, list); + chan->chan->ppp = 0; + next = list->next; + kfree(chan); + } + + /* Free up resources. */ + ppp_ccp_closed(ppp); + lock_xmit_path(ppp); + lock_recv_path(ppp); + if (ppp->vj) { + slhc_free(ppp->vj); + ppp->vj = 0; + } + free_skbs(&ppp->xq); + free_skbs(&ppp->rq); + free_skbs(&ppp->recv_pending); + if (ppp->dev) { + rtnl_lock(); + unregister_netdevice(ppp->dev); + ppp->dev = 0; + rtnl_unlock(); + } + kfree(ppp); +} + +/* * Locate an existing ppp unit. * The caller should have locked the all_ppp_lock. */ @@ -1568,7 +1606,7 @@ cleanup_module(void) { /* should never happen */ - if (all_ppp_units.next != &all_ppp_units) + if (!list_empty(&all_ppp_units)) printk(KERN_ERR "PPP: removing module but units remain!\n"); if (unregister_chrdev(PPP_MAJOR, "ppp") != 0) printk(KERN_ERR "PPP: failed to unregister PPP device\n"); diff -u --recursive --new-file v2.3.16/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c --- v2.3.16/linux/drivers/net/sun3lance.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sun3lance.c Sat Sep 4 13:08:32 1999 @@ -0,0 +1,885 @@ +/* sun3lance.c: Ethernet driver for SUN3 Lance chip */ +/* + + Sun3 Lance ethernet driver, by Sam Creasey (sammy@users.qual.net). + This driver is a part of the linux kernel, and is thus distributed + under the GNU Public License. + + The values used in LANCE_OBIO and LANCE_IRQ seem to be empirically + true for the correct IRQ and address of the lance registers. They + have not been widely tested, however. What we probably need is a + "proper" way to search for a device in the sun3's prom, but, alas, + linux has no such thing. + + This driver is largely based on atarilance.c, by Roman Hodek. Other + sources of inspiration were the NetBSD sun3 am7990 driver, and the + linux sparc lance driver (sunlance.c). + + There are more assumptions made throughout this driver, it almost + certainly still needs work, but it does work at least for RARP/BOOTP and + mounting the root NFS filesystem. + +*/ + +static char *version = "sun3lance.c: v1.0 12/12/96 Sam Creasey (sammy@users.qual.net)\n"; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* sun3/60 addr/irq for the lance chip. If your sun is different, + change this. */ +#define LANCE_OBIO 0x120000 +#define LANCE_IRQ IRQ3 + +/* Debug level: + * 0 = silent, print only serious errors + * 1 = normal, print error messages + * 2 = debug, print debug infos + * 3 = debug, print even more debug infos (packet data) + */ + +#define LANCE_DEBUG 1 + +#ifdef LANCE_DEBUG +static int lance_debug = LANCE_DEBUG; +#else +static int lance_debug = 1; +#endif +MODULE_PARM(lance_debug, "i"); + +#define DPRINTK(n,a) \ + do { \ + if (lance_debug >= n) \ + printk a; \ + } while( 0 ) + + +/* we're only using 32k of memory, so we use 4 TX + buffers and 16 RX buffers. These values are expressed as log2. */ + +#define TX_LOG_RING_SIZE 3 +#define RX_LOG_RING_SIZE 5 + +/* These are the derived values */ + +#define TX_RING_SIZE (1 << TX_LOG_RING_SIZE) +#define TX_RING_LEN_BITS (TX_LOG_RING_SIZE << 5) +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) + +#define RX_RING_SIZE (1 << RX_LOG_RING_SIZE) +#define RX_RING_LEN_BITS (RX_LOG_RING_SIZE << 5) +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) + +/* Definitions for packet buffer access: */ +#define PKT_BUF_SZ 1544 + +/* Get the address of a packet buffer corresponding to a given buffer head */ +#define PKTBUF_ADDR(head) (void *)((unsigned long)(MEM) | (head)->base) + + +/* The LANCE Rx and Tx ring descriptors. */ +struct lance_rx_head { + unsigned short base; /* Low word of base addr */ + volatile unsigned char flag; + unsigned char base_hi; /* High word of base addr (unused) */ + short buf_length; /* This length is 2s complement! */ + volatile short msg_length; /* This length is "normal". */ +}; + +struct lance_tx_head { + unsigned short base; /* Low word of base addr */ + volatile unsigned char flag; + unsigned char base_hi; /* High word of base addr (unused) */ + short length; /* Length is 2s complement! */ + volatile short misc; +}; + +/* The LANCE initialization block, described in databook. */ +struct lance_init_block { + unsigned short mode; /* Pre-set mode */ + unsigned char hwaddr[6]; /* Physical ethernet address */ + unsigned int filter[2]; /* Multicast filter (unused). */ + /* Receive and transmit ring base, along with length bits. */ + unsigned short rdra; + unsigned short rlen; + unsigned short tdra; + unsigned short tlen; + unsigned short pad[4]; /* is thie needed? */ +}; + +/* The whole layout of the Lance shared memory */ +struct lance_memory { + struct lance_init_block init; + struct lance_tx_head tx_head[TX_RING_SIZE]; + struct lance_rx_head rx_head[RX_RING_SIZE]; + char rx_data[RX_RING_SIZE][PKT_BUF_SZ]; + char tx_data[RX_RING_SIZE][PKT_BUF_SZ]; +}; + +/* The driver's private device structure */ + +struct lance_private { + volatile unsigned short *iobase; + struct lance_memory *mem; + int new_rx, new_tx; /* The next free ring entry */ + int old_tx, old_rx; /* ring entry to be processed */ + struct net_device_stats stats; +/* These two must be ints for set_bit() */ + int tx_full; + int lock; +}; + +/* I/O register access macros */ + +#define MEM lp->mem +#define DREG lp->iobase[0] +#define AREG lp->iobase[1] +#define REGA(a) ( AREG = (a), DREG ) + +/* Definitions for the Lance */ + +/* tx_head flags */ +#define TMD1_ENP 0x01 /* end of packet */ +#define TMD1_STP 0x02 /* start of packet */ +#define TMD1_DEF 0x04 /* deferred */ +#define TMD1_ONE 0x08 /* one retry needed */ +#define TMD1_MORE 0x10 /* more than one retry needed */ +#define TMD1_ERR 0x40 /* error summary */ +#define TMD1_OWN 0x80 /* ownership (set: chip owns) */ + +#define TMD1_OWN_CHIP TMD1_OWN +#define TMD1_OWN_HOST 0 + +/* tx_head misc field */ +#define TMD3_TDR 0x03FF /* Time Domain Reflectometry counter */ +#define TMD3_RTRY 0x0400 /* failed after 16 retries */ +#define TMD3_LCAR 0x0800 /* carrier lost */ +#define TMD3_LCOL 0x1000 /* late collision */ +#define TMD3_UFLO 0x4000 /* underflow (late memory) */ +#define TMD3_BUFF 0x8000 /* buffering error (no ENP) */ + +/* rx_head flags */ +#define RMD1_ENP 0x01 /* end of packet */ +#define RMD1_STP 0x02 /* start of packet */ +#define RMD1_BUFF 0x04 /* buffer error */ +#define RMD1_CRC 0x08 /* CRC error */ +#define RMD1_OFLO 0x10 /* overflow */ +#define RMD1_FRAM 0x20 /* framing error */ +#define RMD1_ERR 0x40 /* error summary */ +#define RMD1_OWN 0x80 /* ownership (set: ship owns) */ + +#define RMD1_OWN_CHIP RMD1_OWN +#define RMD1_OWN_HOST 0 + +/* register names */ +#define CSR0 0 /* mode/status */ +#define CSR1 1 /* init block addr (low) */ +#define CSR2 2 /* init block addr (high) */ +#define CSR3 3 /* misc */ +#define CSR8 8 /* address filter */ +#define CSR15 15 /* promiscuous mode */ + +/* CSR0 */ +/* (R=readable, W=writeable, S=set on write, C=clear on write) */ +#define CSR0_INIT 0x0001 /* initialize (RS) */ +#define CSR0_STRT 0x0002 /* start (RS) */ +#define CSR0_STOP 0x0004 /* stop (RS) */ +#define CSR0_TDMD 0x0008 /* transmit demand (RS) */ +#define CSR0_TXON 0x0010 /* transmitter on (R) */ +#define CSR0_RXON 0x0020 /* receiver on (R) */ +#define CSR0_INEA 0x0040 /* interrupt enable (RW) */ +#define CSR0_INTR 0x0080 /* interrupt active (R) */ +#define CSR0_IDON 0x0100 /* initialization done (RC) */ +#define CSR0_TINT 0x0200 /* transmitter interrupt (RC) */ +#define CSR0_RINT 0x0400 /* receiver interrupt (RC) */ +#define CSR0_MERR 0x0800 /* memory error (RC) */ +#define CSR0_MISS 0x1000 /* missed frame (RC) */ +#define CSR0_CERR 0x2000 /* carrier error (no heartbeat :-) (RC) */ +#define CSR0_BABL 0x4000 /* babble: tx-ed too many bits (RC) */ +#define CSR0_ERR 0x8000 /* error (RC) */ + +/* CSR3 */ +#define CSR3_BCON 0x0001 /* byte control */ +#define CSR3_ACON 0x0002 /* ALE control */ +#define CSR3_BSWP 0x0004 /* byte swap (1=big endian) */ + +/***************************** Prototypes *****************************/ + +static int lance_probe( struct net_device *dev); +static int lance_open( struct net_device *dev ); +static void lance_init_ring( struct net_device *dev ); +static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); +static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp ); +static int lance_rx( struct net_device *dev ); +static int lance_close( struct net_device *dev ); +static struct net_device_stats *lance_get_stats( struct net_device *dev ); +static void set_multicast_list( struct net_device *dev ); + +/************************* End of Prototypes **************************/ + +__initfunc(int sun3lance_probe( struct net_device *dev )) +{ + static int found = 0; + + if(found) + return(ENODEV); + + if (lance_probe(dev)) { + found = 1; + return( 0 ); + } + + return( ENODEV ); +} + +__initfunc(static int lance_probe( struct net_device *dev)) +{ + unsigned long ioaddr, iopte; + + struct lance_private *lp; + int i; + static int did_version = 0; + int found = 0; + + /* LANCE_OBIO can be found within the IO pmeg with some effort */ + for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 + + SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) { + + iopte = sun3_get_pte(ioaddr); + if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */ + continue; + + if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) == + LANCE_OBIO) { + found = 1; + break; + } + } + + if(!found) + return 0; + + init_etherdev( dev, sizeof(struct lance_private) ); + if (!dev->priv) + dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); + lp = (struct lance_private *)dev->priv; + MEM = (struct lance_memory *)sun3_dvma_malloc(sizeof(struct + lance_memory)); + lp->iobase = (volatile unsigned short *)ioaddr; + dev->base_addr = (unsigned long)ioaddr; /* informational only */ + + REGA(CSR0) = CSR0_STOP; + + request_irq(LANCE_IRQ, lance_interrupt, 0, "SUN3 Lance", dev); + dev->irq = (unsigned short)LANCE_IRQ; + + + printk("%s: SUN3 Lance at io %#lx, mem %#lx, irq %d, hwaddr ", + dev->name, + (unsigned long)ioaddr, + (unsigned long)MEM, + dev->irq); + + /* copy in the ethernet address from the prom */ + for(i = 0; i < 6 ; i++) + dev->dev_addr[i] = idprom->id_ethaddr[i]; + + /* tell the card it's ether address, bytes swapped */ + MEM->init.hwaddr[0] = dev->dev_addr[1]; + MEM->init.hwaddr[1] = dev->dev_addr[0]; + MEM->init.hwaddr[2] = dev->dev_addr[3]; + MEM->init.hwaddr[3] = dev->dev_addr[2]; + MEM->init.hwaddr[4] = dev->dev_addr[5]; + MEM->init.hwaddr[5] = dev->dev_addr[4]; + + for( i = 0; i < 6; ++i ) + printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" ); + + MEM->init.mode = 0x0000; + MEM->init.filter[0] = 0x00000000; + MEM->init.filter[1] = 0x00000000; + MEM->init.rdra = sun3_dvma_vtop(MEM->rx_head); + MEM->init.rlen = (RX_LOG_RING_SIZE << 13) | + (sun3_dvma_vtop(MEM->rx_head) >> 16); + MEM->init.tdra = sun3_dvma_vtop(MEM->tx_head); + MEM->init.tlen = (TX_LOG_RING_SIZE << 13) | + (sun3_dvma_vtop(MEM->tx_head) >> 16); + + DPRINTK(2, ("initaddr: %08lx rx_ring: %08lx tx_ring: %08lx\n", + sun3_dvma_vtop(&(MEM->init)), sun3_dvma_vtop(MEM->rx_head), + (sun3_dvma_vtop(MEM->tx_head)))); + + + if (did_version++ == 0) + DPRINTK( 1, ( version )); + + /* The LANCE-specific entries in the device structure. */ + dev->open = &lance_open; + dev->hard_start_xmit = &lance_start_xmit; + dev->stop = &lance_close; + dev->get_stats = &lance_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->set_mac_address = 0; + dev->start = 0; + + memset( &lp->stats, 0, sizeof(lp->stats) ); + + return 1; +} + +static int lance_open( struct net_device *dev ) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + int i; + + DPRINTK( 2, ( "%s: lance_open()\n", dev->name )); + + REGA(CSR0) = CSR0_STOP; + + /* tell the lance the address of its init block */ + REGA(CSR1) = sun3_dvma_vtop(&(MEM->init)); + REGA(CSR2) = sun3_dvma_vtop(&(MEM->init)) >> 16; + + lance_init_ring(dev); + + /* Re-initialize the LANCE, and start it when done. */ + + REGA(CSR3) = CSR3_BSWP; + + /* From now on, AREG is kept to point to CSR0 */ + REGA(CSR0) = CSR0_INIT; + + i = 1000000; + while (--i > 0) + if (DREG & CSR0_IDON) + break; + if (i < 0 || (DREG & CSR0_ERR)) { + DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n", + dev->name, i, DREG )); + DREG = CSR0_STOP; + return( -EIO ); + } + + DREG = CSR0_IDON | CSR0_STRT | CSR0_INEA; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG )); + MOD_INC_USE_COUNT; + + return( 0 ); +} + + +/* Initialize the LANCE Rx and Tx rings. */ + +static void lance_init_ring( struct net_device *dev ) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + int i; + + lp->lock = 0; + lp->tx_full = 0; + lp->new_rx = lp->new_tx = 0; + lp->old_rx = lp->old_tx = 0; + + for( i = 0; i < TX_RING_SIZE; i++ ) { + MEM->tx_head[i].base = sun3_dvma_vtop(MEM->tx_data[i]); + MEM->tx_head[i].flag = 0; + MEM->tx_head[i].base_hi = + (sun3_dvma_vtop(MEM->tx_data[i])) >>16; + MEM->tx_head[i].length = 0; + MEM->tx_head[i].misc = 0; + } + + for( i = 0; i < RX_RING_SIZE; i++ ) { + MEM->rx_head[i].base = sun3_dvma_vtop(MEM->rx_data[i]); + MEM->rx_head[i].flag = TMD1_OWN_CHIP; + MEM->rx_head[i].base_hi = + (sun3_dvma_vtop(MEM->rx_data[i])) >> 16; + MEM->rx_head[i].buf_length = -PKT_BUF_SZ | 0xf000; + MEM->rx_head[i].msg_length = 0; + } + +} + + +static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + int entry, len; + struct lance_tx_head *head; + unsigned long flags; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 20) + return( 1 ); + + DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n", + dev->name, DREG )); + DREG = CSR0_STOP; + /* + * Always set BSWP after a STOP as STOP puts it back into + * little endian mode. + */ + REGA(CSR3) = CSR3_BSWP; + lp->stats.tx_errors++; + + if(lance_debug >= 2) { + int i; + printk("Ring data: old_tx %d new_tx %d%s new_rx %d\n", + lp->old_tx, lp->new_tx, + lp->tx_full ? " (full)" : "", + lp->new_rx ); + for( i = 0 ; i < RX_RING_SIZE; i++ ) + printk( "rx #%d: base=%04x blen=%04x mlen=%04x\n", + i, MEM->rx_head[i].base, + -MEM->rx_head[i].buf_length, + MEM->rx_head[i].msg_length); + for( i = 0 ; i < TX_RING_SIZE; i++ ) + printk("tx #%d: base=%04x len=%04x misc=%04x\n", + i, MEM->tx_head[i].base, + -MEM->tx_head[i].length, + MEM->tx_head[i].misc ); + } + + lance_init_ring(dev); + REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT; + + dev->tbusy = 0; + dev->trans_start = jiffies; + + return 0; + } + + AREG = CSR0; +// DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", +// dev->name, DREG )); + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); + return 1; + } + + if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) { + printk( "%s: tx queue lock!.\n", dev->name); + /* don't clear dev->tbusy flag. */ + return 1; + } + + /* Fill in a Tx ring entry */ +#if 0 + if (lance_debug >= 3) { + u_char *p; + int i; + printk( "%s: TX pkt %d type 0x%04x from ", dev->name, + lp->new_tx, ((u_short *)skb->data)[6]); + for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" to "); + for( p = (u_char *)skb->data, i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" data at 0x%08x len %d\n", (int)skb->data, + (int)skb->len ); + } +#endif + /* We're not prepared for the int until the last flags are set/reset. + * And the int may happen already after setting the OWN_CHIP... */ + save_and_cli(flags); + + /* Mask to ring buffer boundary. */ + entry = lp->new_tx; + head = &(MEM->tx_head[entry]); + + /* Caution: the write order is important here, set the "ownership" bits + * last. + */ + + /* the sun3's lance needs it's buffer padded to the minimum + size */ + len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + +// head->length = -len; + head->length = (-len) | 0xf000; + head->misc = 0; + + memcpy( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); + head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; + lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK; + lp->stats.tx_bytes += skb->len; + + /* Trigger an immediate send poll. */ + REGA(CSR0) = CSR0_INEA | CSR0_TDMD; + dev->trans_start = jiffies; + dev_kfree_skb( skb ); + + lp->lock = 0; + if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) == + TMD1_OWN_HOST) + dev->tbusy = 0; + + restore_flags(flags); + + return 0; +} + +/* The LANCE interrupt handler. */ + +static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp) +{ + struct net_device *dev = dev_id; + struct lance_private *lp = dev->priv; + int csr0; + + if (dev == NULL) { + DPRINTK( 1, ( "lance_interrupt(): invalid dev_id\n" )); + return; + } + + if (dev->interrupt) + DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name )); + dev->interrupt = 1; + + still_more: + + AREG = CSR0; + csr0 = DREG; + + /* ack interrupts */ + DREG = csr0 & (CSR0_TINT | CSR0_RINT); + + /* clear errors */ + if(csr0 & CSR0_ERR) + DREG = CSR0_BABL | CSR0_MERR | CSR0_CERR | CSR0_MISS; + + + DPRINTK( 2, ( "%s: interrupt csr0=%04x new csr=%04x.\n", + dev->name, csr0, DREG )); + + if (csr0 & CSR0_TINT) { /* Tx-done interrupt */ + int old_tx = lp->old_tx; + +// if(lance_debug >= 3) { +// int i; +// +// printk("%s: tx int\n", dev->name); +// +// for(i = 0; i < TX_RING_SIZE; i++) +// printk("ring %d flag=%04x\n", i, +// MEM->tx_head[i].flag); +// } + + while( old_tx != lp->new_tx) { + struct lance_tx_head *head = &(MEM->tx_head[old_tx]); + + DPRINTK(3, ("on tx_ring %d\n", old_tx)); + + if (head->flag & TMD1_OWN_CHIP) + break; /* It still hasn't been Txed */ + + if (head->flag & TMD1_ERR) { + int status = head->misc; + lp->stats.tx_errors++; + if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++; + if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++; + if (status & TMD3_LCOL) lp->stats.tx_window_errors++; + if (status & (TMD3_UFLO | TMD3_BUFF)) { + lp->stats.tx_fifo_errors++; + printk("%s: Tx FIFO error\n", + dev->name); + REGA(CSR0) = CSR0_STOP; + REGA(CSR3) = CSR3_BSWP; + lance_init_ring(dev); + REGA(CSR0) = CSR0_STRT | CSR0_INEA; + return; + } + } else if(head->flag & (TMD1_ENP | TMD1_STP)) { + + head->flag &= ~(TMD1_ENP | TMD1_STP); + if(head->flag & (TMD1_ONE | TMD1_MORE)) + lp->stats.collisions++; + + lp->stats.tx_packets++; + DPRINTK(3, ("cleared tx ring %d\n", old_tx)); + } + old_tx = (old_tx +1) & TX_RING_MOD_MASK; + } + + lp->old_tx = old_tx; + } + + + if (dev->tbusy) { + /* The ring is no longer full, clear tbusy. */ + dev->tbusy = 0; + mark_bh( NET_BH ); + } + + if (csr0 & CSR0_RINT) /* Rx interrupt */ + lance_rx( dev ); + + /* Log misc errors. */ + if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */ + if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */ + if (csr0 & CSR0_MERR) { + DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), " + "status %04x.\n", dev->name, csr0 )); + /* Restart the chip. */ + REGA(CSR0) = CSR0_STOP; + REGA(CSR3) = CSR3_BSWP; + lance_init_ring(dev); + REGA(CSR0) = CSR0_STRT | CSR0_INEA; + } + + + /* Clear any other interrupt, and set interrupt enable. */ +// DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR | +// CSR0_IDON | CSR0_INEA; + + REGA(CSR0) = CSR0_INEA; + + if(DREG & (CSR0_RINT | CSR0_TINT)) { + DPRINTK(2, ("restarting interrupt, csr0=%#04x\n", DREG)); + goto still_more; + } + + DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n", + dev->name, DREG )); + dev->interrupt = 0; + return; +} + +/* get packet, toss into skbuff */ +static int lance_rx( struct net_device *dev ) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + int entry = lp->new_rx; + + /* If we own the next entry, it's a new packet. Send it up. */ + while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) { + struct lance_rx_head *head = &(MEM->rx_head[entry]); + int status = head->flag; + + if (status != (RMD1_ENP|RMD1_STP)) { /* There was an error. */ + /* There is a tricky error noted by John Murphy, + to Russ Nelson: Even with + full-sized buffers it's possible for a jabber packet to use two + buffers, with only the last correctly noting the error. */ + if (status & RMD1_ENP) /* Only count a general error at the */ + lp->stats.rx_errors++; /* end of a packet.*/ + if (status & RMD1_FRAM) lp->stats.rx_frame_errors++; + if (status & RMD1_OFLO) lp->stats.rx_over_errors++; + if (status & RMD1_CRC) lp->stats.rx_crc_errors++; + if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++; + head->flag &= (RMD1_ENP|RMD1_STP); + } else { + /* Malloc up new buffer, compatible with net-3. */ +// short pkt_len = head->msg_length;// & 0xfff; + short pkt_len = (head->msg_length & 0xfff) - 4; + struct sk_buff *skb; + + if (pkt_len < 60) { + printk( "%s: Runt packet!\n", dev->name ); + lp->stats.rx_errors++; + } + else { + skb = dev_alloc_skb( pkt_len+2 ); + if (skb == NULL) { + DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n", + dev->name )); + + lp->stats.rx_dropped++; + head->msg_length = 0; + head->flag |= RMD1_OWN_CHIP; + lp->new_rx = (lp->new_rx+1) & + RX_RING_MOD_MASK; + } + +#if 0 + if (lance_debug >= 3) { + u_char *data = PKTBUF_ADDR(head), *p; + printk( "%s: RX pkt %d type 0x%04x from ", dev->name, entry, ((u_short *)data)[6]); + for( p = &data[6], i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" to "); + for( p = data, i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" data %02x %02x %02x %02x %02x %02x %02x %02x " + "len %d at %08x\n", + data[15], data[16], data[17], data[18], + data[19], data[20], data[21], data[22], + pkt_len, data); + } +#endif + if (lance_debug >= 3) { + u_char *data = PKTBUF_ADDR(head); + printk( "%s: RX pkt %d type 0x%04x len %d\n ", dev->name, entry, ((u_short *)data)[6], pkt_len); + } + + + skb->dev = dev; + skb_reserve( skb, 2 ); /* 16 byte align */ + skb_put( skb, pkt_len ); /* Make room */ +// memcpy( skb->data, PKTBUF_ADDR(head), pkt_len ); + eth_copy_and_sum(skb, + PKTBUF_ADDR(head), + pkt_len, 0); + + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; + } + } + +// head->buf_length = -PKT_BUF_SZ | 0xf000; + head->msg_length = 0; + head->flag = RMD1_OWN_CHIP; + + entry = lp->new_rx = (lp->new_rx +1) & RX_RING_MOD_MASK; + } + + /* From lance.c (Donald Becker): */ + /* We should check that at least two ring entries are free. + If not, we should free one and mark stats->rx_dropped++. */ + + return 0; +} + + +static int lance_close( struct net_device *dev ) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + + dev->start = 0; + dev->tbusy = 1; + + AREG = CSR0; + + DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, DREG )); + + /* We stop the LANCE here -- it occasionally polls + memory if we don't. */ + DREG = CSR0_STOP; + + MOD_DEC_USE_COUNT; + return 0; +} + + +static struct net_device_stats *lance_get_stats( struct net_device *dev ) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + + return &lp->stats; +} + + +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + */ + +/* completely untested on a sun3 */ +static void set_multicast_list( struct net_device *dev ) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + + if (!dev->start) + /* Only possible if board is already started */ + return; + + /* We take the simple way out and always enable promiscuous mode. */ + DREG = CSR0_STOP; /* Temporarily stop the lance. */ + + if (dev->flags & IFF_PROMISC) { + /* Log any net taps. */ + DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name )); + REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */ + } else { + short multicast_table[4]; + int num_addrs = dev->mc_count; + int i; + /* We don't use the multicast table, but rely on upper-layer + * filtering. */ + memset( multicast_table, (num_addrs == 0) ? 0 : -1, + sizeof(multicast_table) ); + for( i = 0; i < 4; i++ ) + REGA( CSR8+i ) = multicast_table[i]; + REGA( CSR15 ) = 0; /* Unset promiscuous mode */ + } + + /* + * Always set BSWP after a STOP as STOP puts it back into + * little endian mode. + */ + REGA( CSR3 ) = CSR3_BSWP; + + /* Resume normal operation and reset AREG to CSR0 */ + REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT; +} + + +#ifdef MODULE +static char devicename[9] = { 0, }; + +static struct net_device sun3lance_dev = +{ + devicename, /* filled in by register_netdev() */ + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, sun3lance_probe, +}; + +int init_module(void) +{ + int err; + + if ((err = register_netdev( &sun3lance_dev ))) { + if (err == -EIO) { + printk( "SUN3 Lance not detected. Module not loaded.\n"); + } + return( err ); + } + return( 0 ); +} + +void cleanup_module(void) +{ + unregister_netdev( &sun3lance_dev ); +} + +#endif /* MODULE */ + diff -u --recursive --new-file v2.3.16/linux/drivers/nubus/Makefile linux/drivers/nubus/Makefile --- v2.3.16/linux/drivers/nubus/Makefile Sat Mar 21 11:06:51 1998 +++ linux/drivers/nubus/Makefile Sat Sep 4 13:08:32 1999 @@ -9,7 +9,19 @@ # parent makefile. # -L_OBJS := nubus.o L_TARGET := nubus.a + +ifeq ($(CONFIG_MODULES),y) +O_TARGET := nubus_n_syms.o +OX_OBJS := nubus_syms.o +O_OBJS := nubus.o +L_OBJS := nubus_n_syms.o +else +L_OBJS := nubus.o +endif + +ifdef CONFIG_PROC_FS +L_OBJS += proc.o +endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.16/linux/drivers/nubus/nubus.c linux/drivers/nubus/nubus.c --- v2.3.16/linux/drivers/nubus/nubus.c Tue Jul 20 16:40:30 1999 +++ linux/drivers/nubus/nubus.c Sat Sep 4 13:08:32 1999 @@ -1,77 +1,120 @@ /* * Macintosh Nubus Interface Code + * + * Originally by Alan Cox + * + * Mostly rewritten by David Huggins-Daines, C. Scott Ananian, + * and others. */ #include #include #include #include -#include #include #include #include +#include +#include #include #include #include #include -/* for LCIII stuff; better find a general way like MACH_HAS_NUBUS */ -#include #include +#include +#include +extern void via_nubus_init(void); +extern void oss_nubus_init(void); -#undef LCIII_WEIRDNESS - -static struct nubus_slot nubus_slots[16]; - -/* - * Please skip to the bottom of this file if you ate lunch recently - * -- Alan - */ - +extern int console_loglevel; -/* - * Yes this sucks. The ROM can appear on arbitary bytes of the long - * word. We are not amused. - */ +/* Constants */ + +/* This is, of course, the size in bytelanes, rather than the size in + actual bytes */ +#define FORMAT_BLOCK_SIZE 20 +#define ROM_DIR_OFFSET 0x24 + +#define NUBUS_TEST_PATTERN 0x5A932BC7 + +/* Define this if you like to live dangerously - it is known not to + work on pretty much every machine except the Quadra 630 and the LC + III. */ +#undef I_WANT_TO_PROBE_SLOT_ZERO + +/* This sometimes helps combat failure to boot */ +#undef TRY_TO_DODGE_WSOD + +/* Globals */ + +struct nubus_dev* nubus_devices; +struct nubus_board* nubus_boards; + +/* Meaning of "bytelanes": + + The card ROM may appear on any or all bytes of each long word in + NuBus memory. The low 4 bits of the "map" value found in the + format block (at the top of the slot address space, as well as at + the top of the MacOS ROM) tells us which bytelanes, i.e. which byte + offsets within each longword, are valid. Thus: + + A map of 0x0f, as found in the MacOS ROM, means that all bytelanes + are valid. + + A map of 0xf0 means that no bytelanes are valid (We pray that we + will never encounter this, but stranger things have happened) + + A map of 0xe1 means that only the MSB of each long word is actually + part of the card ROM. (We hope to never encounter NuBus on a + little-endian machine. Again, stranger things have happened) + + A map of 0x78 means that only the LSB of each long word is valid. + + Etcetera, etcetera. Hopefully this clears up some confusion over + what the following code actually does. */ -extern __inline__ int not_useful(void *p, int map) +extern inline int not_useful(void *p, int map) { unsigned long pv=(unsigned long)p; - pv&=3; - if(map&(1<65536) - printk("rewind of %d!\n", len); + + /* Sanity check */ + if(len > 65536) + printk(KERN_ERR "rewind of 0x%08x!\n", len); while(len) { do { p--; } - while(not_useful(p,map)); + while(not_useful(p, map)); len--; } *ptr=p; @@ -79,9 +122,9 @@ static void nubus_advance(unsigned char **ptr, int len, int map) { - unsigned char *p=*ptr; + unsigned char *p = *ptr; if(len>65536) - printk("advance of %d!\n", len); + printk(KERN_ERR "advance of 0x%08x!\n", len); while(len) { while(not_useful(p,map)) @@ -89,29 +132,32 @@ p++; len--; } - *ptr=p; + *ptr = p; } -/* - * 24bit signed offset to 32bit - */ - -static unsigned long nubus_expand32(unsigned long foo) +static void nubus_move(unsigned char **ptr, int len, int map) { - if(foo&0x00800000) /* 24bit negative */ - foo|=0xFF000000; - return foo; + if(len > 0) + nubus_advance(ptr, len, map); + else if(len < 0) + nubus_rewind(ptr, -len, map); } -static void nubus_move(unsigned char **ptr, int len, int map) +/* Now, functions to read the sResource tree */ + +/* Each sResource entry consists of a 1-byte ID and a 3-byte data + field. If that data field contains an offset, then obviously we + have to expand it from a 24-bit signed number to a 32-bit signed + number. */ + +extern inline long nubus_expand32(long foo) { - if(len>0) - nubus_advance(ptr,len,map); - else if(len<0) - nubus_rewind(ptr,-len,map); + if(foo & 0x00800000) /* 24bit negative */ + foo |= 0xFF000000; + return foo; } -static void *nubus_rom_addr(int slot) +extern inline void *nubus_rom_addr(int slot) { /* * Returns the first byte after the card. We then walk @@ -120,472 +166,820 @@ return (void *)(0xF1000000+(slot<<24)); } -void nubus_memcpy(int slot, void *to, unsigned char *p, int len) +static unsigned char *nubus_dirptr(const struct nubus_dirent *nd) { - unsigned char *t=(unsigned char *)to; + unsigned char *p = nd->base; + /* Essentially, just step over the bytelanes using whatever + offset we might have found */ + nubus_move(&p, nubus_expand32(nd->data), nd->mask); + /* And return the value */ + return p; +} + +/* These two are for pulling resource data blocks (i.e. stuff that's + pointed to with offsets) out of the card ROM. */ + +void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent* dirent, + int len) +{ + unsigned char *t = (unsigned char *)dest; + unsigned char *p = nubus_dirptr(dirent); while(len) { - *t++=nubus_get_rom(&p,1, nubus_slots[slot].slot_lanes); + *t++ = nubus_get_rom(&p, 1, dirent->mask); len--; } } -void nubus_strncpy(int slot, void *to, unsigned char *p, int len) +void nubus_get_rsrc_str(void *dest, const struct nubus_dirent* dirent, + int len) { - unsigned char *t=(unsigned char *)to; + unsigned char *t=(unsigned char *)dest; + unsigned char *p = nubus_dirptr(dirent); while(len) { - *t=nubus_get_rom(&p,1, nubus_slots[slot].slot_lanes); + *t = nubus_get_rom(&p, 1, dirent->mask); if(!*t++) break; len--; } } - - - -unsigned char *nubus_dirptr(struct nubus_dirent *nd) +int nubus_get_root_dir(const struct nubus_board* board, + struct nubus_dir* dir) { - unsigned char *p=(unsigned char *)(nd->base); - - nubus_move(&p, nubus_expand32(nd->value), nd->mask); - return p; + dir->ptr = dir->base = board->directory; + dir->done = 0; + dir->mask = board->lanes; + return 0; } - -struct nubus_dir *nubus_openrootdir(int slot) -{ - static struct nubus_dir nbdir; - unsigned char *rp=nubus_rom_addr(slot); - - nubus_rewind(&rp,20, nubus_slots[slot].slot_lanes); - - nubus_move(&rp, nubus_expand32(nubus_slots[slot].slot_directory), - nubus_slots[slot].slot_lanes); - - nbdir.base=rp; - nbdir.length=nubus_slots[slot].slot_dlength; - nbdir.count=0; - nbdir.mask=nubus_slots[slot].slot_lanes; - return &nbdir; +/* This is a slyly renamed version of the above */ +int nubus_get_func_dir(const struct nubus_dev* dev, + struct nubus_dir* dir) +{ + dir->ptr = dir->base = dev->directory; + dir->done = 0; + dir->mask = dev->board->lanes; + return 0; } -struct nubus_dir *nubus_opensubdir(struct nubus_dirent *d) +int nubus_get_board_dir(const struct nubus_board* board, + struct nubus_dir* dir) { - static struct nubus_dir nbdir; - unsigned char *rp=nubus_dirptr(d); - nbdir.base=rp; - nbdir.length=99999;/*slots[i].slot_dlength;*/ - nbdir.count=0; - nbdir.mask=d->mask; - return &nbdir; + struct nubus_dirent ent; + + dir->ptr = dir->base = board->directory; + dir->done = 0; + dir->mask = board->lanes; + + /* Now dereference it (the first directory is always the board + directory) */ + if (nubus_readdir(dir, &ent) == -1) + return -1; + if (nubus_get_subdir(&ent, dir) == -1) + return -1; + return 0; } -void nubus_closedir(struct nubus_dir *nd) +int nubus_get_subdir(const struct nubus_dirent *ent, + struct nubus_dir *dir) { - ; + dir->ptr = dir->base = nubus_dirptr(ent); + dir->done = 0; + dir->mask = ent->mask; + return 0; } -struct nubus_dirent *nubus_readdir(struct nubus_dir *nd) +int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent) { u32 resid; - u8 rescode; - static struct nubus_dirent d; - - if(nd->count==nd->length) - return NULL; + if (nd->done) + return -1; - d.base=(unsigned long)nd->base; - - resid=nubus_get_rom(&nd->base, 4, nd->mask); - nd->count++; - rescode=resid>>24; - if(rescode==0xFF) - { - nd->count=nd->length; - return NULL; - } - d.type=rescode; - d.value=resid&0xFFFFFF; - d.mask=nd->mask; - return &d; -} + /* Do this first, otherwise nubus_rewind & co are off by 4 */ + ent->base = nd->ptr; -/* - * MAC video handling irritations - */ + /* This moves nd->ptr forward */ + resid = nubus_get_rom(&nd->ptr, 4, nd->mask); -static unsigned char nubus_vid_byte[16]; -static unsigned long nubus_vid_offset[16]; + /* EOL marker, as per the Apple docs */ + if((resid&0xff000000) == 0xff000000) + { + /* Mark it as done */ + nd->done = 1; + return -1; + } -static void nubus_irqsplat(int slot, void *dev_id, struct pt_regs *regs) -{ - unsigned char *p=((unsigned char *)nubus_slot_addr(slot))+ - nubus_vid_offset[slot]; - *p=nubus_vid_byte[slot]; + /* First byte is the resource ID */ + ent->type = resid >> 24; + /* Low 3 bytes might contain data (or might not) */ + ent->data = resid & 0xffffff; + ent->mask = nd->mask; + return 0; } -static int nubus_add_irqsplatter(int slot, unsigned long ptr, unsigned char v) +int nubus_rewinddir(struct nubus_dir* dir) { - nubus_vid_byte[slot]=v; - nubus_vid_offset[slot]=ptr; - nubus_request_irq(slot, NULL, nubus_irqsplat); + dir->ptr = dir->base; return 0; } - -void nubus_video_shutup(int slot, struct nubus_type *nt) -{ - if(nt->category!=3 /* Display */ || nt->type!=1 /* Video */ - || nt->DrSW!=1 /* Quickdraw device */) - return; - switch(nt->DrHW) - { - /* - * Toby and MacII Hires cards. These behave in a MacII - * anyway but not on an RBV box - */ - case 0x0001: - case 0x0013: - nubus_add_irqsplatter(slot, 0xA0000, 0); - break; - /* - * Apple workstation video card. - */ - case 0x0006: - nubus_add_irqsplatter(slot, 0xA00000, 0); - break; - /* - * Futura cards - */ - case 0x0417: - case 0x042F: - nubus_add_irqsplatter(slot, 0xF05000, 0x80); - break; - - /* - * Fingers crossed 8) - * - * If you have another card and an RBV based mac you'll - * almost certainly have to add it here to make it work. - */ - - default: - break; + +/* Driver interface functions, more or less like in pci.c */ + +struct nubus_dev* +nubus_find_device(unsigned short category, + unsigned short type, + unsigned short dr_hw, + unsigned short dr_sw, + const struct nubus_dev* from) +{ + struct nubus_dev* itor = + from ? from->next : nubus_devices; + + while (itor) { + if (itor->category == category + && itor->type == type + && itor->dr_hw == dr_hw + && itor->dr_sw == dr_sw) + return itor; + itor = itor->next; } + return NULL; } -/* - * Device list - */ +struct nubus_dev* +nubus_find_type(unsigned short category, + unsigned short type, + const struct nubus_dev* from) +{ + struct nubus_dev* itor = + from ? from->next : nubus_devices; + + while (itor) { + if (itor->category == category + && itor->type == type) + return itor; + itor = itor->next; + } + return NULL; +} -static struct nubus_device_specifier *nubus_device_list=NULL; - -void register_nubus_device(struct nubus_device_specifier *d) +struct nubus_dev* +nubus_find_slot(unsigned int slot, + const struct nubus_dev* from) { - d->next=nubus_device_list; - nubus_device_list=d; + struct nubus_dev* itor = + from ? from->next : nubus_devices; + + while (itor) { + if (itor->board->slot == slot) + return itor; + itor = itor->next; + } + return NULL; } -void unregister_nubus_device(struct nubus_device_specifier *nb) -{ - struct nubus_device_specifier **t=&nubus_device_list; - while(*t!=nb && *t) - t=&((*t)->next); - *t=nb->next; +int +nubus_find_rsrc(struct nubus_dir* dir, unsigned char rsrc_type, + struct nubus_dirent* ent) +{ + while (nubus_readdir(dir, ent) != -1) { + if (ent->type == rsrc_type) + return 0; + } + return -1; +} + +/* Initialization functions - decide which slots contain stuff worth + looking at, and print out lots and lots of information from the + resource blocks. */ + +/* FIXME: A lot of this stuff will eventually be useful after + initializaton, for intelligently probing Ethernet and video chips, + among other things. The rest of it should go in the /proc code. + For now, we just use it to give verbose boot logs. */ + +static int __init nubus_show_display_resource(struct nubus_dev* dev, + const struct nubus_dirent* ent) +{ + switch (ent->type) { + case NUBUS_RESID_GAMMADIR: + printk(KERN_INFO " gamma directory offset: 0x%06x\n", ent->data); + break; + case 0x0080 ... 0x0085: + printk(KERN_INFO " mode %02X info offset: 0x%06x\n", + ent->type, ent->data); + break; + default: + printk(KERN_INFO " unknown resource %02X, data 0x%06x\n", + ent->type, ent->data); + } + return 0; } -static struct nubus_device_specifier *find_nubus_device(int slot, struct nubus_type *nt) +static int __init nubus_show_network_resource(struct nubus_dev* dev, + const struct nubus_dirent* ent) { - struct nubus_device_specifier *t=nubus_device_list; - while(t!=NULL) + switch (ent->type) { + case NUBUS_RESID_MAC_ADDRESS: { - if(t->setup(t,slot, nt)==0) - return t; - t=t->next; + char addr[6]; + int i; + + nubus_get_rsrc_mem(addr, ent, 6); + printk(KERN_INFO " MAC address: "); + for (i = 0; i < 6; i++) + printk("%02x%s", addr[i] & 0xff, + i == 5 ? "" : ":"); + printk("\n"); + break; } - printk("No driver for device [%d %d %d %d]\n", - nt->category, nt->type, nt->DrHW, nt->DrSW); - return NULL; + default: + printk(KERN_INFO " unknown resource %02X, data 0x%06x\n", + ent->type, ent->data); + } + return 0; } -/* - * Probe a nubus slot - */ +static int __init nubus_show_cpu_resource(struct nubus_dev* dev, + const struct nubus_dirent* ent) +{ + switch (ent->type) { + case NUBUS_RESID_MEMINFO: + { + unsigned long meminfo[2]; + nubus_get_rsrc_mem(&meminfo, ent, 8); + printk(KERN_INFO " memory: [ 0x%08lx 0x%08lx ]\n", + meminfo[0], meminfo[1]); + break; + } + case NUBUS_RESID_ROMINFO: + { + unsigned long rominfo[2]; + nubus_get_rsrc_mem(&rominfo, ent, 8); + printk(KERN_INFO " ROM: [ 0x%08lx 0x%08lx ]\n", + rominfo[0], rominfo[1]); + break; + } + default: + printk(KERN_INFO " unknown resource %02X, data 0x%06x\n", + ent->type, ent->data); + } + return 0; +} -void nubus_probe_slot(int slot, int mode) +static int __init nubus_show_private_resource(struct nubus_dev* dev, + const struct nubus_dirent* ent) { - unsigned char *rp; - unsigned char dp; - int lanes; - int i; - unsigned long dpat; - struct nubus_dir *dir; - struct nubus_dirent *nd; - struct nubus_type type_info; + switch (dev->category) { + case NUBUS_CAT_DISPLAY: + nubus_show_display_resource(dev, ent); + break; + case NUBUS_CAT_NETWORK: + nubus_show_network_resource(dev, ent); + break; + case NUBUS_CAT_CPU: + nubus_show_cpu_resource(dev, ent); + break; + default: + printk(KERN_INFO " unknown resource %02X, data 0x%06x\n", + ent->type, ent->data); + } + return 0; +} - /* - * Ok see whats cooking in the bytelanes - */ +static struct nubus_dev* __init + nubus_get_functional_resource(struct nubus_board* board, + int slot, + const struct nubus_dirent* parent) +{ + struct nubus_dir dir; + struct nubus_dirent ent; + struct nubus_dev* dev; - rp=nubus_rom_addr(slot); + printk(KERN_INFO " Function 0x%02x:\n", parent->type); + nubus_get_subdir(parent, &dir); + + /* Apple seems to have botched the ROM on the IIx */ + if (slot == 0 && (unsigned long)dir.base % 2) + dir.base += 1; - for(i=4;i;i--) - { - rp--; - - if(!hwreg_present(rp)) - continue; - - dp=*rp; + if (console_loglevel >= 10) + printk(KERN_DEBUG "nubus_get_functional_resource: parent is 0x%p, dir is 0x%p\n", + parent->base, dir.base); + + /* Actually we should probably panic if this fails */ + if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == NULL) + return NULL; + memset(dev, 0, sizeof(*dev)); + dev->resid = parent->type; + dev->directory = dir.base; + dev->board = board; - if(dp==0) - continue; - - /* - * Valid ? - */ - - if((((dp>>4)^dp)&0x0F)!=0x0F) - continue; - - if((dp&0x0F) >= 1<type==0x80/*RES_ID_BOARD_DIR*/) - break; + case NUBUS_RESID_TYPE: + { + unsigned short nbtdata[4]; + nubus_get_rsrc_mem(nbtdata, &ent, 8); + dev->category = nbtdata[0]; + dev->type = nbtdata[1]; + dev->dr_sw = nbtdata[2]; + dev->dr_hw = nbtdata[3]; + printk(KERN_INFO " type: [cat 0x%x type 0x%x hw 0x%x sw 0x%x]\n", + nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]); + break; } - - nubus_closedir(dir); - - if(nd==NULL) + case NUBUS_RESID_NAME: { - printk("board resource not found!\n"); - return; + nubus_get_rsrc_str(dev->name, &ent, 64); + printk(KERN_INFO " name: %s\n", dev->name); + break; } - - dir=nubus_opensubdir(nd); - - /* - * Walk the board resource - */ - - while((nd=nubus_readdir(dir))!=NULL) + case NUBUS_RESID_DRVRDIR: { - switch(nd->type) - { - case RES_ID_TYPE: - { - unsigned short nbtdata[4]; - nubus_memcpy(slot, nbtdata, nubus_dirptr(nd), 8); - type_info.category=nbtdata[0]; - type_info.type=nbtdata[1]; - type_info.DrHW=nbtdata[2]; - type_info.DrSW=nbtdata[3]; - break; - } - case RES_ID_NAME: - nubus_strncpy(slot, nubus_slots[slot].slot_cardname,nubus_dirptr(nd),64); - break; - default: - ; - } + /* MacOS driver. If we were NetBSD we might + use this :-) */ + struct nubus_dir drvr_dir; + struct nubus_dirent drvr_ent; + nubus_get_subdir(&ent, &drvr_dir); + nubus_readdir(&drvr_dir, &drvr_ent); + dev->driver = nubus_dirptr(&drvr_ent); + printk(KERN_INFO " driver at: 0x%p\n", + dev->driver); + break; } - - nubus_closedir(dir); - - /* - * Attempt to bind a driver to this slot - */ - - if (mode==0) { - printk("%s\n", - nubus_slots[slot].slot_cardname); - find_nubus_device(slot,&type_info); + case NUBUS_RESID_MINOR_BASEOS: + /* We will need this in order to support + multiple framebuffers. It might be handy + for Ethernet as well */ + nubus_get_rsrc_mem(&dev->iobase, &ent, 4); + printk(KERN_INFO " memory offset: 0x%08lx\n", + dev->iobase); + break; + case NUBUS_RESID_MINOR_LENGTH: + /* Ditto */ + nubus_get_rsrc_mem(&dev->iosize, &ent, 4); + printk(KERN_INFO " memory length: 0x%08lx\n", + dev->iosize); + break; + case NUBUS_RESID_FLAGS: + dev->flags = ent.data; + printk(KERN_INFO " flags: 0x%06x\n", dev->flags); + break; + case NUBUS_RESID_HWDEVID: + dev->hwdevid = ent.data; + printk(KERN_INFO " hwdevid: 0x%06x\n", dev->hwdevid); + break; + default: + /* Local/Private resources have their own + function */ + nubus_show_private_resource(dev, &ent); } - if (mode==1) - nubus_video_shutup(slot, &type_info); - - return; } + + return dev; } +/* This is cool. */ +static int __init nubus_get_vidnames(struct nubus_board* board, + const struct nubus_dirent* parent) +{ + struct nubus_dir dir; + struct nubus_dirent ent; + /* FIXME: obviously we want to put this in a header file soon */ + struct vidmode { + u32 size; + /* Don't know what this is yet */ + u16 id; + /* Longest one I've seen so far is 26 characters */ + char name[32]; + }; + + printk(KERN_INFO " video modes supported:\n"); + nubus_get_subdir(parent, &dir); + if (console_loglevel >= 10) + printk(KERN_DEBUG "nubus_get_vidnames: parent is 0x%p, dir is 0x%p\n", + parent->base, dir.base); -void nubus_probe_bus(void) -{ - int i; - for(i=9;i<15;i++) + while(nubus_readdir(&dir, &ent) != -1) { - /* printk("nubus: probing slot %d !\n", i); */ - nubus_probe_slot(i, 0); + struct vidmode mode; + u32 size; + + /* First get the length */ + nubus_get_rsrc_mem(&size, &ent, 4); + + /* Now clobber the whole thing */ + if (size > sizeof(mode) - 1) + size = sizeof(mode) - 1; + memset(&mode, sizeof(mode), 0); + nubus_get_rsrc_mem(&mode, &ent, size); + printk (KERN_INFO " %02X: (%02X) %s\n", ent.type, + mode.id, mode.name); } + return 0; } -/* - * RBV machines have level triggered video interrupts, and a VIA - * emulation that doesn't always seem to include being able to disable - * an interrupt. Totally lusing hardware. Before we can init irq's we - * have to install a handler to shut the bloody things up. - */ +/* This is *really* cool. */ +static int __init nubus_get_icon(struct nubus_board* board, + const struct nubus_dirent* ent) +{ + /* Should be 32x32 if my memory serves me correctly */ + unsigned char icon[128]; + int x, y; + + nubus_get_rsrc_mem(&icon, ent, 128); + printk(KERN_INFO " icon:\n"); -void nubus_sweep_video(void) + /* We should actually plot these somewhere in the framebuffer + init. This is just to demonstrate that they do, in fact, + exist */ + for (y = 0; y < 32; y++) { + printk(KERN_INFO " "); + for (x = 0; x < 32; x++) { + if (icon[y*4 + x/8] + & (0x80 >> (x%8))) + printk("*"); + else + printk(" "); + } + printk("\n"); + } + return 0; +} + +static int __init nubus_get_vendorinfo(struct nubus_board* board, + const struct nubus_dirent* parent) { - int i; - return; /* XXX why ?? */ - for(i=9;i<15;i++) + struct nubus_dir dir; + struct nubus_dirent ent; + static char* vendor_fields[6] = {"ID", "serial", "revision", + "part", "date", "unknown field"}; + + printk(KERN_INFO " vendor info:\n"); + nubus_get_subdir(parent, &dir); + if (console_loglevel >= 10) + printk(KERN_DEBUG "nubus_get_vendorinfo: parent is 0x%p, dir is 0x%p\n", + parent->base, dir.base); + + while(nubus_readdir(&dir, &ent) != -1) { - nubus_probe_slot(i,1); + char name[64]; + + /* These are all strings, we think */ + nubus_get_rsrc_str(name, &ent, 64); + if (ent.type > 5) + ent.type = 5; + printk(KERN_INFO " %s: %s\n", + vendor_fields[ent.type-1], name); } + return 0; } -/* - * Support functions - */ - -int nubus_ethernet_addr(int slot, unsigned char *addr) +static int __init nubus_get_board_resource(struct nubus_board* board, int slot, + const struct nubus_dirent* parent) { - struct nubus_dir *nb; - struct nubus_dirent *d; - int ng=-ENOENT; - - nb=nubus_openrootdir(slot); + struct nubus_dir dir; + struct nubus_dirent ent; - if(nb==NULL) - return -ENOENT; - - while((d=nubus_readdir(nb))!=NULL) + nubus_get_subdir(parent, &dir); + if (console_loglevel >= 10) + printk(KERN_DEBUG "nubus_get_board_resource: parent is 0x%p, dir is 0x%p\n", + parent->base, dir.base); + + while(nubus_readdir(&dir, &ent) != -1) { - if(d->type==0x80) /* First private resource */ + switch (ent.type) { + case NUBUS_RESID_TYPE: + { + unsigned short nbtdata[4]; + /* This type is always the same, and is not + useful except insofar as it tells us that + we really are looking at a board resource. */ + nubus_get_rsrc_mem(nbtdata, &ent, 8); + printk(KERN_INFO " type: [cat 0x%x type 0x%x hw 0x%x sw 0x%x]\n", + nbtdata[0], nbtdata[1], nbtdata[2], + nbtdata[3]); + if (nbtdata[0] != 1 || nbtdata[1] != 0 || + nbtdata[2] != 0 || nbtdata[3] != 0) + printk(KERN_ERR "this sResource is not a board resource!\n"); + break; + } + case NUBUS_RESID_NAME: + nubus_get_rsrc_str(board->name, &ent, 64); + printk(KERN_INFO " name: %s\n", board->name); + break; + case NUBUS_RESID_ICON: + nubus_get_icon(board, &ent); break; + case NUBUS_RESID_BOARDID: + printk(KERN_INFO " board id: 0x%x\n", ent.data); + break; + case NUBUS_RESID_PRIMARYINIT: + printk(KERN_INFO " primary init offset: 0x%06x\n", ent.data); + break; + case NUBUS_RESID_VENDORINFO: + nubus_get_vendorinfo(board, &ent); + break; + case NUBUS_RESID_FLAGS: + printk(KERN_INFO " flags: 0x%06x\n", ent.data); + break; + case NUBUS_RESID_HWDEVID: + printk(KERN_INFO " hwdevid: 0x%06x\n", ent.data); + break; + case NUBUS_RESID_SECONDINIT: + printk(KERN_INFO " secondary init offset: 0x%06x\n", ent.data); + break; + /* WTF isn't this in the functional resources? */ + case NUBUS_RESID_VIDNAMES: + nubus_get_vidnames(board, &ent); + break; + /* Same goes for this */ + case NUBUS_RESID_VIDMODES: + printk(KERN_INFO " video mode parameter directory offset: 0x%06x\n", + ent.data); + break; + default: + printk(KERN_INFO " unknown resource %02X, data 0x%06x\n", + ent.type, ent.data); + } + } + return 0; +} + +/* Attempt to bypass the somewhat non-obvious arrangement of + sResources in the motherboard ROM */ +static void __init nubus_find_rom_dir(struct nubus_board* board) +{ + unsigned char* rp; + unsigned char* romdir; + struct nubus_dir dir; + struct nubus_dirent ent; + + /* Check for the extra directory just under the format block */ + rp = board->fblock; + nubus_rewind(&rp, 4, board->lanes); + if (nubus_get_rom(&rp, 4, board->lanes) != NUBUS_TEST_PATTERN) { + /* OK, the ROM was telling the truth */ + board->directory = board->fblock; + nubus_move(&board->directory, + nubus_expand32(board->doffset), + board->lanes); + return; } - if(d==NULL) - return -ENOENT; + + /* On "slot zero", you have to walk down a few more + directories to get to the equivalent of a real card's root + directory. We don't know what they were smoking when they + came up with this. */ + romdir = nubus_rom_addr(board->slot); + nubus_rewind(&romdir, ROM_DIR_OFFSET, board->lanes); + dir.base = dir.ptr = romdir; + dir.done = 0; + dir.mask = board->lanes; + + /* This one points to an "Unknown Macintosh" directory */ + if (nubus_readdir(&dir, &ent) == -1) + goto badrom; + + if (console_loglevel >= 10) + printk(KERN_INFO "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data); + /* This one takes us to where we want to go. */ + if (nubus_readdir(&dir, &ent) == -1) + goto badrom; + if (console_loglevel >= 10) + printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data); + nubus_get_subdir(&ent, &dir); + + /* Resource ID 01, also an "Unknown Macintosh" */ + if (nubus_readdir(&dir, &ent) == -1) + goto badrom; + if (console_loglevel >= 10) + printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data); + + /* FIXME: the first one is *not* always the right one. We + suspect this has something to do with the ROM revision. + "The HORROR ROM" (LC-series) uses 0x7e, while "The HORROR + Continues" (Q630) uses 0x7b. The DAFB Macs evidently use + something else. Please run "Slots" on your Mac (see + include/linux/nubus.h for where to get this program) and + tell us where the 'SiDirPtr' for Slot 0 is. If you feel + brave, you should also use MacsBug to walk down the ROM + directories like this function does and try to find the + path to that address... */ + if (nubus_readdir(&dir, &ent) == -1) + goto badrom; + if (console_loglevel >= 10) + printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data); - nb=nubus_opensubdir(d); + /* Bwahahahaha... */ + nubus_get_subdir(&ent, &dir); + board->directory = dir.base; + return; - while((d=nubus_readdir(nb))!=NULL) - { - if(d->type==0x80) /* First private field is the mac */ - { - int i; - nubus_memcpy(slot, addr, nubus_dirptr(d), 6); -/* printk("d.base=%lX, d.value=%lX\n", - d->base,d->value); - memcpy(addr,"\xC0\xC1\xC2\xC3\xC4\xC5",6);*/ - printk("MAC address: "); - for(i=0;i<6;i++) - { - printk("%s%02X", i?":":"", addr[i]); - } - ng=0; - break; + /* Even more evil laughter... */ + badrom: + board->directory = board->fblock; + nubus_move(&board->directory, nubus_expand32(board->doffset), board->lanes); + printk(KERN_ERR "nubus_get_rom_dir: ROM weirdness! Notify the developers...\n"); +} + +/* Add a board (might be many devices) to the list */ +static struct nubus_board* __init nubus_add_board(int slot, int bytelanes) +{ + struct nubus_board* board; + struct nubus_board** boardp; + + unsigned char *rp; + unsigned long dpat; + struct nubus_dir dir; + struct nubus_dirent ent; + + /* Move to the start of the format block */ + rp = nubus_rom_addr(slot); + nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes); + + /* Actually we should probably panic if this fails */ + if ((board = kmalloc(sizeof(*board), GFP_ATOMIC)) == NULL) + return NULL; + memset(board, 0, sizeof(*board)); + board->fblock = rp; + + /* Dump the format block for debugging purposes */ + if (console_loglevel >= 10) { + int i; + printk(KERN_DEBUG "Slot %X, format block at 0x%p\n", + slot, rp); + printk(KERN_DEBUG "Format block: "); + for (i = 0; i < FORMAT_BLOCK_SIZE; i += 4) { + unsigned short foo, bar; + foo = nubus_get_rom(&rp, 2, bytelanes); + bar = nubus_get_rom(&rp, 2, bytelanes); + printk("%04x %04x ", foo, bar); } - else - printk("ID=%d val=%x\n", - d->type, d->value); + printk("\n"); + rp = board->fblock; + } + + board->slot = slot; + board->slot_addr = (unsigned long) nubus_slot_addr(slot); + board->doffset = nubus_get_rom(&rp, 4, bytelanes); + /* rom_length is *supposed* to be the total length of the + * ROM. In practice it is the "amount of ROM used to compute + * the CRC." So some jokers decide to set it to zero and + * set the crc to zero so they don't have to do any math. + * See the Performa 460 ROM, for example. Those Apple "engineers". + */ + board->rom_length = nubus_get_rom(&rp, 4, bytelanes); + board->crc = nubus_get_rom(&rp, 4, bytelanes); + board->rev = nubus_get_rom(&rp, 1, bytelanes); + board->format = nubus_get_rom(&rp,1, bytelanes); + board->lanes = bytelanes; + + /* Directory offset should be small and negative... */ + if(!(board->doffset & 0x00FF0000)) + printk(KERN_WARNING "Dodgy doffset!\n"); + dpat = nubus_get_rom(&rp, 4, bytelanes); + if(dpat != NUBUS_TEST_PATTERN) + printk(KERN_WARNING "Wrong test pattern %08lx!\n", dpat); + + /* + * I wonder how the CRC is meant to work - + * any takers ? + * CSA: According to MAC docs, not all cards pass the CRC anyway, + * since the initial Macintosh ROM releases skipped the check. + */ + + /* Attempt to work around slot zero weirdness */ + nubus_find_rom_dir(board); + nubus_get_root_dir(board, &dir); + + /* We're ready to rock */ + printk(KERN_INFO "Slot %X:\n", slot); + + /* Each slot should have one board resource and any number of + functional resources. So we'll fill in some fields in the + struct nubus_board from the board resource, then walk down + the list of functional resources, spinning out a nubus_dev + for each of them. */ + if (nubus_readdir(&dir, &ent) == -1) { + /* We can't have this! */ + printk(KERN_ERR "Board resource not found!\n"); + return NULL; + } else { + printk(KERN_INFO " Board resource:\n"); + nubus_get_board_resource(board, slot, &ent); + } + + /* Aaaarrrrgghh! The LC III motherboard has *two* board + resources. I have no idea WTF to do about this. */ + + while (nubus_readdir(&dir, &ent) != -1) { + struct nubus_dev* dev; + struct nubus_dev** devp; + dev = nubus_get_functional_resource(board, slot, &ent); + if (dev == NULL) + continue; + + /* We zeroed this out above */ + if (board->first_dev == NULL) + board->first_dev = dev; + + /* Put it on the global NuBus device chain. Keep entries in order. */ + for (devp=&nubus_devices; *devp!=NULL; devp=&((*devp)->next)) + /* spin */; + *devp = dev; + dev->next = NULL; } - return ng; + + /* Put it on the global NuBus board chain. Keep entries in order. */ + for (boardp=&nubus_boards; *boardp!=NULL; boardp=&((*boardp)->next)) + /* spin */; + *boardp = board; + board->next = NULL; + + return board; } -#ifdef CONFIG_PROC_FS +void __init nubus_probe_slot(int slot) +{ + unsigned char dp; + unsigned char* rp; + int i; -/* - * /proc for Nubus devices - */ - -static int sprint_nubus_config(int slot, char *ptr, int len) + rp = nubus_rom_addr(slot); + for(i = 4; i; i--) + { + unsigned long flags; + int card_present; + + rp--; + save_flags(flags); + cli(); + card_present = hwreg_present(rp); + restore_flags(flags); + + if (!card_present) + continue; + + printk(KERN_DEBUG "Now probing slot %X at %p\n", slot, rp); + dp = *rp; + if(dp == 0) + continue; + + /* The last byte of the format block consists of two + nybbles which are "mirror images" of each other. + These show us the valid bytelanes */ + if ((((dp>>4) ^ dp) & 0x0F) != 0x0F) + continue; + /* Check that this value is actually *on* one of the + bytelanes it claims are valid! */ + if ((dp & 0x0F) >= (1<slot, board->name); + return strlen(ptr); } +/* We're going to have to be a bit more sophisticated about this, I + think, because it doesn't really seem to work right when you do a + full listing of boards and devices */ int get_nubus_list(char *buf) { int nprinted, len, size; - int slot; + struct nubus_board* board; #define MSG "\nwarning: page-size limit reached!\n" /* reserve same for truncation warning message: */ size = PAGE_SIZE - (strlen(MSG) + 1); - len = sprintf(buf, "Nubus devices found:\n"); + len = sprintf(buf, "Nubus boards found:\n"); - for (slot=0; slot< 16; slot++) + /* Walk the list of NuBus boards */ + for (board = nubus_boards; board != NULL; board = board->next) { - if(!(nubus_slots[slot].slot_flags&NUBUS_DEVICE_PRESENT)) - continue; - nprinted = sprint_nubus_config(slot, buf + len, size - len); + nprinted = sprint_nubus_board(board, buf + len, size - len); if (nprinted < 0) { return len + sprintf(buf + len, MSG); } @@ -594,46 +988,53 @@ return len; } -static struct proc_dir_entry proc_nubus = { +static struct proc_dir_entry proc_old_nubus = { PROC_NUBUS, 5, "nubus", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_array_inode_operations }; -#endif +#endif /* CONFIG_PROC_FS */ -void nubus_init(void) +void __init nubus_scan_bus(void) { - /* - * Register cards - */ -#ifdef CONFIG_DAYNAPORT - extern struct nubus_device_specifier nubus_8390; + int slot; + /* This might not work on your machine */ +#ifdef I_WANT_TO_PROBE_SLOT_ZERO + nubus_probe_slot(0); #endif + for(slot = 9; slot < 15; slot++) + { + nubus_probe_slot(slot); + } +} +void __init nubus_init(void) +{ if (!MACH_IS_MAC) return; -#ifdef LCIII_WEIRDNESS - if (macintosh_config->ident == MAC_MODEL_LCIII) { - printk("nubus init: LCIII has no nubus!\n"); - return; + /* Initialize the NuBus interrupts */ + if (oss_present) { + oss_nubus_init(); + } else { + via_nubus_init(); } -#endif -#ifdef CONFIG_DAYNAPORT - register_nubus_device(&nubus_8390); +#ifdef TRY_TO_DODGE_WSOD + /* Rogue Ethernet interrupts can kill the machine if we don't + do this. Obviously this is bogus. Hopefully the local VIA + gurus can fix the real cause of the problem. */ + mdelay(1000); #endif + + /* And probe */ + printk("NuBus: Scanning NuBus slots.\n"); + nubus_devices = NULL; + nubus_boards = NULL; + nubus_scan_bus(); - /* - * And probe - */ - - nubus_init_via(); - printk("Scanning nubus slots.\n"); - nubus_probe_bus(); #ifdef CONFIG_PROC_FS - proc_register(&proc_root, &proc_nubus); + proc_register(&proc_root, &proc_old_nubus); + nubus_proc_init(); #endif } - - \ No newline at end of file diff -u --recursive --new-file v2.3.16/linux/drivers/nubus/nubus_syms.c linux/drivers/nubus/nubus_syms.c --- v2.3.16/linux/drivers/nubus/nubus_syms.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/nubus/nubus_syms.c Sat Sep 4 13:08:32 1999 @@ -0,0 +1,27 @@ +/* Exported symbols for NuBus services + + (c) 1999 David Huggins-Daines */ + +#include +#include +#include +#include + +#ifdef CONFIG_PROC_FS +EXPORT_SYMBOL(nubus_proc_attach_device); +EXPORT_SYMBOL(nubus_proc_detach_device); +#endif + +EXPORT_SYMBOL(nubus_find_device); +EXPORT_SYMBOL(nubus_find_type); +EXPORT_SYMBOL(nubus_find_slot); +EXPORT_SYMBOL(nubus_get_root_dir); +EXPORT_SYMBOL(nubus_get_board_dir); +EXPORT_SYMBOL(nubus_get_func_dir); +EXPORT_SYMBOL(nubus_readdir); +EXPORT_SYMBOL(nubus_find_rsrc); +EXPORT_SYMBOL(nubus_rewinddir); +EXPORT_SYMBOL(nubus_get_subdir); +EXPORT_SYMBOL(nubus_get_rsrc_mem); +EXPORT_SYMBOL(nubus_get_rsrc_str); + diff -u --recursive --new-file v2.3.16/linux/drivers/nubus/proc.c linux/drivers/nubus/proc.c --- v2.3.16/linux/drivers/nubus/proc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/nubus/proc.c Sat Sep 4 13:08:32 1999 @@ -0,0 +1,183 @@ +/* drivers/nubus/proc.c: Proc FS interface for NuBus. + + By David Huggins-Daines + + Much code and many ideas from drivers/pci/proc.c: + Copyright (c) 1997, 1998 Martin Mares + + This is initially based on the Zorro and PCI interfaces. However, + it works somewhat differently. The intent is to provide a + structure in /proc analogous to the structure of the NuBus ROM + resources. + + Therefore each NuBus device is in fact a directory, which may in + turn contain subdirectories. The "files" correspond to NuBus + resource records. For those types of records which we know how to + convert to formats that are meaningful to userspace (mostly just + icons) these files will provide "cooked" data. Otherwise they will + simply provide raw access (read-only of course) to the ROM. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int +get_nubus_dev_info(char *buf, char **start, off_t pos, int count, int wr) +{ + struct nubus_dev *dev = nubus_devices; + off_t at = 0; + int len, cnt; + + cnt = 0; + while (dev && count > cnt) { + len = sprintf(buf, "%x\t%04x %04x %04x %04x", + dev->board->slot, + dev->category, + dev->type, + dev->dr_sw, + dev->dr_hw); + len += sprintf(buf+len, + "\t%08lx", + dev->board->slot_addr); + buf[len++] = '\n'; + at += len; + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else + cnt += len; + buf += len; + } + dev = dev->next; + } + return (count > cnt) ? cnt : count; +} + +static struct proc_dir_entry proc_nubus_devices = { + PROC_BUS_NUBUS_DEVICES, 7, "devices", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, + get_nubus_dev_info +}; + +static struct proc_dir_entry *proc_bus_nubus_dir; + +static void nubus_proc_subdir(struct nubus_dev* dev, + struct proc_dir_entry* parent, + struct nubus_dir* dir) +{ + struct nubus_dirent ent; + + /* Some of these are directories, others aren't */ + while (nubus_readdir(dir, &ent) != -1) { + char name[8]; + struct proc_dir_entry* e; + + sprintf(name, "%x", ent.type); + e = create_proc_entry(name, S_IFREG | S_IRUGO | + S_IWUSR, parent); + if (!e) return; + } +} + +/* Can't do this recursively since the root directory is structured + somewhat differently from the subdirectories */ +static void nubus_proc_populate(struct nubus_dev* dev, + struct proc_dir_entry* parent, + struct nubus_dir* root) +{ + struct nubus_dirent ent; + + /* We know these are all directories (board resource + one or + more functional resources) */ + while (nubus_readdir(root, &ent) != -1) { + char name[8]; + struct proc_dir_entry* e; + struct nubus_dir dir; + + sprintf(name, "%x", ent.type); + e = create_proc_entry(name, S_IFDIR, parent); + if (!e) return; + + /* And descend */ + if (nubus_get_subdir(&ent, &dir) == -1) { + /* This shouldn't happen */ + printk(KERN_ERR "NuBus root directory node %x:%x has no subdir!\n", + dev->board->slot, ent.type); + continue; + } else { + nubus_proc_subdir(dev, e, &dir); + } + } +} + +int nubus_proc_attach_device(struct nubus_dev *dev) +{ + struct proc_dir_entry *e; + struct nubus_dir root; + char name[8]; + + if (dev == NULL) { + printk(KERN_ERR + "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n"); + return -1; + } + + if (dev->board == NULL) { + printk(KERN_ERR + "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n"); + printk("dev = %p, dev->board = %p\n", dev, dev->board); + return -1; + } + + /* Create a directory */ + sprintf(name, "%x", dev->board->slot); + e = dev->procdir = create_proc_entry(name, S_IFDIR, + proc_bus_nubus_dir); + if (!e) + return -ENOMEM; + + /* Now recursively populate it with files */ + nubus_get_root_dir(dev->board, &root); + nubus_proc_populate(dev, e, &root); + + return 0; +} + +/* FIXME: this is certainly broken! */ +int nubus_proc_detach_device(struct nubus_dev *dev) +{ + struct proc_dir_entry *e; + + if ((e = dev->procdir)) { + if (e->count) + return -EBUSY; + remove_proc_entry(e->name, proc_bus_nubus_dir); + dev->procdir = NULL; + } + return 0; +} + +void __init proc_bus_nubus_add_devices(void) +{ + struct nubus_dev *dev; + + for(dev = nubus_devices; dev; dev = dev->next) + nubus_proc_attach_device(dev); +} + +void __init nubus_proc_init(void) +{ + if (!MACH_IS_MAC) + return; + proc_bus_nubus_dir = create_proc_entry("nubus", S_IFDIR, proc_bus); + proc_register(proc_bus_nubus_dir, &proc_nubus_devices); + proc_bus_nubus_add_devices(); +} diff -u --recursive --new-file v2.3.16/linux/drivers/pci/Makefile linux/drivers/pci/Makefile --- v2.3.16/linux/drivers/pci/Makefile Thu Aug 26 13:05:38 1999 +++ linux/drivers/pci/Makefile Wed Sep 1 14:37:25 1999 @@ -25,6 +25,6 @@ L_OBJS += proc.o endif -L_OBJS += compat.o quirks.o names.o +L_OBJS += compat.o quirks.o names.o syscall.o setup.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.16/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.3.16/linux/drivers/pci/pci.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/pci/pci.c Wed Sep 1 14:37:25 1999 @@ -295,7 +295,7 @@ pci_write_config_word(dev, PCI_COMMAND, cmd); } -static void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child) +void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child) { u8 io_base_lo, io_limit_lo; u16 mem_base_lo, mem_limit_lo, io_base_hi, io_limit_hi; @@ -513,7 +513,6 @@ child->primary = bus->secondary; child->subordinate = 0xff; sprintf(child->name, "PCI Bus #%02x", child->number); - pci_read_bridge_bases(dev, child); /* * Clear all status bits and turn off memory, * I/O and master enables. diff -u --recursive --new-file v2.3.16/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c --- v2.3.16/linux/drivers/pci/quirks.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/pci/quirks.c Wed Sep 1 14:37:25 1999 @@ -67,13 +67,8 @@ struct resource *r = &dev->resource[0]; if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) { - printk("PCI: Re-allocating buggy S3 card at %s: ", dev->name); r->start = 0; r->end = 0x3ffffff; - if (pcibios_assign_resource(dev, 0)) - printk("FAILED\n"); - else - printk("moved to %08lx\n", r->start); } } @@ -90,8 +85,8 @@ * quantity. */ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M }, - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M }, { 0 } }; diff -u --recursive --new-file v2.3.16/linux/drivers/pci/setup.c linux/drivers/pci/setup.c --- v2.3.16/linux/drivers/pci/setup.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pci/setup.c Wed Sep 1 14:37:25 1999 @@ -0,0 +1,324 @@ +/* + * drivers/pci/setup.c + * + * Extruded from code written by + * Dave Rusling (david.rusling@reo.mts.dec.com) + * David Mosberger (davidm@cs.arizona.edu) + * David Miller (davem@redhat.com) + * + * Support routines for initializing a PCI subsystem. + */ + +#include +#include +#include +#include +#include + +#include +#include + + +#define DEBUG_CONFIG 0 +#if DEBUG_CONFIG +# define DBGC(args) printk args +#else +# define DBGC(args) +#endif + + +int __init +pci_claim_resource(struct pci_dev *dev, int resource) +{ + struct resource *res = &dev->resource[resource]; + struct resource *root = pci_find_parent_resource(dev, res); + int err; + + err = -EINVAL; + if (root != NULL) { + /* If `dev' is on a secondary pci bus, `root' may not be + at the origin. In that case, adjust the resource into + range. */ + res->start += root->start; + res->end += root->start; + + err = request_resource(root, res); + } + if (err) { + printk(KERN_ERR "PCI: Address space collision on region %d " + "of device %s\n", resource, dev->name); + } + + return err; +} + +static void +pdev_assign_unassigned_resources(struct pci_dev *dev, u32 min_io, u32 min_mem) +{ + u32 reg; + u16 cmd; + int i; + + DBGC(("PCI assign unassigned: (%s)\n", dev->name)); + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *root, *res; + unsigned long size, min; + + res = &dev->resource[i]; + + if (res->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + else if (res->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + + /* If it is already assigned or the resource does + not exist, there is nothing to do. */ + if (res->parent != NULL || res->flags == 0) + continue; + + /* Determine the root we allocate from. */ + root = pci_find_parent_resource(dev, res); + if (root == NULL) + continue; + + min = (res->flags & IORESOURCE_IO ? min_io : min_mem); + min += root->start; + size = res->end - res->start + 1; + + DBGC((" for root[%lx:%lx] min[%lx] size[%lx]\n", + root->start, root->end, min, size)); + + if (allocate_resource(root, res, size, min, -1, size) < 0) { + printk(KERN_ERR + "PCI: Failed to allocate resource %d for %s\n", + i, dev->name); + continue; + } + + DBGC((" got res[%lx:%lx] for resource %d\n", + res->start, res->end, i)); + + /* Update PCI config space. */ + pcibios_update_resource(dev, root, res, i); + } + + /* Special case, disable the ROM. Several devices act funny + (ie. do not respond to memory space writes) when it is left + enabled. A good example are QlogicISP adapters. */ + + pci_read_config_dword(dev, PCI_ROM_ADDRESS, ®); + reg &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg); + + /* All of these (may) have I/O scattered all around and may not + use I/O base address registers at all. So we just have to + always enable IO to these devices. */ + if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED + || (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA + || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE + || (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { + cmd |= PCI_COMMAND_IO; + } + + /* ??? Always turn on bus mastering. If the device doesn't support + it, the bit will go into the bucket. */ + cmd |= PCI_COMMAND_MASTER; + + /* Enable the appropriate bits in the PCI command register. */ + pci_write_config_word(dev, PCI_COMMAND, cmd); + + DBGC((" cmd reg 0x%x\n", cmd)); + + /* If this is a PCI bridge, set the cache line correctly. */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, + (L1_CACHE_BYTES / sizeof(u32))); + } +} + +void __init +pci_assign_unassigned_resources(u32 min_io, u32 min_mem) +{ + struct pci_dev *dev; + for (dev = pci_devices; dev; dev = dev->next) + pdev_assign_unassigned_resources(dev, min_io, min_mem); +} + +struct pbus_set_ranges_data +{ + int found_vga; + unsigned int io_start, io_end; + unsigned int mem_start, mem_end; +}; + +#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define ROUND_DOWN(x, a) ((x) & ~((a) - 1)) + +static void __init +pbus_set_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *outer) +{ + struct pbus_set_ranges_data inner; + struct pci_bus *child; + struct pci_dev *dev; + + inner.found_vga = 0; + inner.mem_start = inner.io_start = ~0; + inner.mem_end = inner.io_end = 0; + + /* Collect information about how our direct children are layed out. */ + for (dev = bus->devices; dev; dev = dev->sibling) { + int i; + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *res = &dev->resource[i]; + if (res->flags & IORESOURCE_IO) { + if (res->start < inner.io_start) + inner.io_start = res->start; + if (res->end > inner.io_end) + inner.io_end = res->end; + } else if (res->flags & IORESOURCE_MEM) { + if (res->start < inner.mem_start) + inner.mem_start = res->start; + if (res->end > inner.mem_end) + inner.mem_end = res->end; + } + } + if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) + inner.found_vga = 1; + } + + /* And for all of the sub-busses. */ + for (child = bus->children; child; child = child->next) + pbus_set_ranges(child, &inner); + + /* Align the values. */ + inner.io_start = ROUND_DOWN(inner.io_start, 4*1024); + inner.io_end = ROUND_UP(inner.io_end, 4*1024); + + inner.mem_start = ROUND_DOWN(inner.mem_start, 1*1024*1024); + inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024); + + /* Configure the bridge, if possible. */ + if (bus->self) { + struct pci_dev *bridge = bus->self; + u32 l; + + /* Set up the top and bottom of the PCI I/O segment + for this bus. */ + pci_read_config_dword(bridge, PCI_IO_BASE, &l); + l &= 0xffff0000; + l |= (inner.io_start >> 8) & 0x00f0; + l |= (inner.io_end - 1) & 0xf000; + pci_write_config_dword(bridge, PCI_IO_BASE, l); + + /* + * Clear out the upper 16 bits of IO base/limit. + * Clear out the upper 32 bits of PREF base/limit. + */ + pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0); + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0); + pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); + + /* Set up the top and bottom of the PCI Memory segment + for this bus. */ + l = (inner.mem_start & 0xfff00000) >> 16; + l |= (inner.mem_end - 1) & 0xfff00000; + pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); + + /* + * Turn off downstream PF memory address range, unless + * there is a VGA behind this bridge, in which case, we + * enable the PREFETCH range to include BIOS ROM at C0000. + * + * NOTE: this is a bit of a hack, done with PREFETCH for + * simplicity, rather than having to add it into the above + * non-PREFETCH range, which could then be bigger than we want. + * We might assume that we could relocate the BIOS ROM, but + * that would depend on having it found by those who need it + * (the DEC BIOS emulator would find it, but I do not know + * about the Xservers). So, we do it this way for now... ;-) + */ + l = (inner.found_vga) ? 0 : 0x0000ffff; + pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); + + /* + * Tell bridge that there is an ISA bus in the system, + * and (possibly) a VGA as well. + */ + l = (inner.found_vga) ? 0x0c : 0x04; + pci_write_config_byte(bridge, PCI_BRIDGE_CONTROL, l); + + /* + * Clear status bits, + * turn on I/O enable (for downstream I/O), + * turn on memory enable (for downstream memory), + * turn on master enable (for upstream memory and I/O). + */ + pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007); + } + + if (outer) { + outer->found_vga |= inner.found_vga; + if (inner.io_start < outer->io_start) + outer->io_start = inner.io_start; + if (inner.io_end > outer->io_end) + outer->io_end = inner.io_end; + if (inner.mem_start < outer->mem_start) + outer->mem_start = inner.mem_start; + if (inner.mem_end > outer->mem_end) + outer->mem_end = inner.mem_end; + } +} + +void __init +pci_set_bus_ranges(void) +{ + struct pci_bus *bus; + for (bus = pci_root; bus; bus = bus->next) + pbus_set_ranges(bus, NULL); +} + +static void +pdev_fixup_irq(struct pci_dev *dev, + u8 (*swizzle)(struct pci_dev *, u8 *), + int (*map_irq)(struct pci_dev *, u8, u8)) +{ + u8 pin, slot; + int irq; + + /* If this device is not on the primary bus, we need to figure out + which interrupt pin it will come in on. We know which slot it + will come in on 'cos that slot is where the bridge is. Each + time the interrupt line passes through a PCI-PCI bridge we must + apply the swizzle function. */ + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + /* Cope with 0 and illegal. */ + if (pin == 0 || pin > 4) + pin = 1; + + /* Follow the chain of bridges, swizzling as we go. */ + slot = (*swizzle)(dev, &pin); + + irq = (*map_irq)(dev, slot, pin); + if (irq == -1) + irq = 0; + dev->irq = irq; + + DBGC(("PCI fixup irq: (%s) got %d\n", dev->name, dev->irq)); + + /* Always tell the device, so the driver knows what is + the real IRQ to use; the device does not use it. */ + pcibios_update_irq(dev, irq); +} + +void __init +pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), + int (*map_irq)(struct pci_dev *, u8, u8)) +{ + struct pci_dev *dev; + for (dev = pci_devices; dev; dev = dev->next) + pdev_fixup_irq(dev, swizzle, map_irq); +} diff -u --recursive --new-file v2.3.16/linux/drivers/pci/syscall.c linux/drivers/pci/syscall.c --- v2.3.16/linux/drivers/pci/syscall.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pci/syscall.c Wed Sep 1 16:41:09 1999 @@ -0,0 +1,145 @@ +/* + * pci_syscall.c + * + * For architectures where we want to allow direct access + * to the PCI config stuff - it would probably be preferable + * on PCs too, but there people just do it by hand with the + * magic northbridge registers.. + */ + +#include +#include +#include +#include +#include +#include + + +asmlinkage long +sys_pciconfig_read(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, void *buf) +{ + struct pci_dev *dev; + u8 byte; + u16 word; + u32 dword; + long err, cfg_ret; + + err = -EPERM; + if (!capable(CAP_SYS_ADMIN)) + goto error; + + err = -ENODEV; + dev = pci_find_slot(bus, dfn); + if (!dev) + goto error; + + lock_kernel(); + switch (len) { + case 1: + cfg_ret = pci_read_config_byte(dev, off, &byte); + break; + case 2: + cfg_ret = pci_read_config_word(dev, off, &word); + break; + case 4: + cfg_ret = pci_read_config_dword(dev, off, &dword); + break; + default: + err = -EINVAL; + unlock_kernel(); + goto error; + }; + unlock_kernel(); + + err = -EIO; + if (cfg_ret != PCIBIOS_SUCCESSFUL) + goto error; + + switch (len) { + case 1: + err = put_user(byte, (unsigned char *)buf); + break; + case 2: + err = put_user(word, (unsigned short *)buf); + break; + case 4: + err = put_user(dword, (unsigned int *)buf); + break; + }; + return err; + +error: + /* ??? XFree86 doesn't even check the return value. They + just look for 0xffffffff in the output, since that's what + they get instead of a machine check on x86. */ + switch (len) { + case 1: + put_user(-1, (unsigned char *)buf); + break; + case 2: + put_user(-1, (unsigned short *)buf); + break; + case 4: + put_user(-1, (unsigned int *)buf); + break; + }; + return err; +} + +asmlinkage long +sys_pciconfig_write(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, void *buf) +{ + struct pci_dev *dev; + u8 byte; + u16 word; + u32 dword; + int err = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pcibios_present()) + return -ENOSYS; + + dev = pci_find_slot(bus, dfn); + if (!dev) + return -ENODEV; + + lock_kernel(); + switch(len) { + case 1: + err = get_user(byte, (u8 *)buf); + if (err) + break; + err = pci_write_config_byte(dev, off, byte); + if (err != PCIBIOS_SUCCESSFUL) + err = -EIO; + break; + + case 2: + err = get_user(word, (u16 *)buf); + if (err) + break; + err = pci_write_config_byte(dev, off, word); + if (err != PCIBIOS_SUCCESSFUL) + err = -EIO; + break; + + case 4: + err = get_user(dword, (u32 *)buf); + if (err) + break; + pci_write_config_byte(dev, off, dword); + if (err != PCIBIOS_SUCCESSFUL) + err = -EIO; + break; + + default: + err = -EINVAL; + break; + }; + unlock_kernel(); + + return err; +} diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/Config.in linux/drivers/pcmcia/Config.in --- v2.3.16/linux/drivers/pcmcia/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/Config.in Fri Sep 3 12:36:41 1999 @@ -0,0 +1,12 @@ +# +# PCMCIA bus subsystem configuration +# +mainmenu_option next_comment +comment 'PCMCIA/Cardbus support' + +tristate 'PCMCIA/Cardbus support' CONFIG_PCMCIA +if [ "$CONFIG_PCMCIA" != "n" ]; then + bool ' CardBus support' CONFIG_CARDBUS +fi + +endmenu diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/Makefile linux/drivers/pcmcia/Makefile --- v2.3.16/linux/drivers/pcmcia/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/Makefile Fri Sep 3 14:21:38 1999 @@ -0,0 +1,28 @@ +# +# Makefile for the kernel pcmcia subsystem (c/o David Hinds) +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := pcmcia.o + +O_OBJS := i82365.o tcic.o cistpl.o rsrc_mgr.o bulkmem.o +OX_OBJS := ds.o cs.o + +ifeq ($(CONFIG_CARDBUS),y) + O_OBJS += cardbus.o +else + ifeq ($(CONFIG_CARDBUS),m) + MX_OBJS += cardbus.o + endif +endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/bulkmem.c linux/drivers/pcmcia/bulkmem.c --- v2.3.16/linux/drivers/pcmcia/bulkmem.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/bulkmem.c Fri Sep 3 13:41:38 1999 @@ -0,0 +1,624 @@ +/*====================================================================== + + PCMCIA Bulk Memory Services + + bulkmem.c 1.29 1999/08/28 04:01:45 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#define __NO_VERSION__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define IN_CARD_SERVICES +#include +#include +#include +#include +#include +#include "cs_internal.h" + +/*====================================================================== + + This function handles submitting an MTD request, and retrying + requests when an MTD is busy. + + An MTD request should never block. + +======================================================================*/ + +static int do_mtd_request(memory_handle_t handle, mtd_request_t *req, + caddr_t buf) +{ + int ret, tries; + client_t *mtd; + socket_info_t *s; + + mtd = handle->mtd; + if (mtd == NULL) + return CS_GENERAL_FAILURE; + s = SOCKET(mtd); + for (tries = 0; tries < 100; tries++) { + mtd->event_callback_args.mtdrequest = req; + mtd->event_callback_args.buffer = buf; + ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW); + if (ret != CS_BUSY) + break; + switch (req->Status) { + case MTD_WAITREQ: + /* Not that we should ever need this... */ + interruptible_sleep_on_timeout(&mtd->mtd_req, HZ); + break; + case MTD_WAITTIMER: + case MTD_WAITRDY: + interruptible_sleep_on_timeout(&mtd->mtd_req, req->Timeout*HZ/1000); + req->Function |= MTD_REQ_TIMEOUT; + break; + case MTD_WAITPOWER: + interruptible_sleep_on(&mtd->mtd_req); + break; + } + if (signal_pending(current)) + printk(KERN_NOTICE "cs: do_mtd_request interrupted!\n"); + } + if (tries == 20) { + printk(KERN_NOTICE "cs: MTD request timed out!\n"); + ret = CS_GENERAL_FAILURE; + } + wake_up_interruptible(&mtd->mtd_req); + retry_erase_list(&mtd->erase_busy, 0); + return ret; +} /* do_mtd_request */ + +/*====================================================================== + + This stuff is all for handling asynchronous erase requests. It + is complicated because all the retry stuff has to be dealt with + in timer interrupts or in the card status event handler. + +======================================================================*/ + +static void insert_queue(erase_busy_t *head, erase_busy_t *entry) +{ + DEBUG(2, ("cs: adding 0x%p to queue 0x%p\n", entry, head)); + entry->next = head; + entry->prev = head->prev; + head->prev->next = entry; + head->prev = entry; +} + +static void remove_queue(erase_busy_t *entry) +{ + DEBUG(2, ("cs: unqueueing 0x%p\n", entry)); + entry->next->prev = entry->prev; + entry->prev->next = entry->next; +} + +static void retry_erase(erase_busy_t *busy, u_int cause) +{ + eraseq_entry_t *erase = busy->erase; + mtd_request_t req; + client_t *mtd; + socket_info_t *s; + int ret; + + DEBUG(2, ("cs: trying erase request 0x%p...\n", busy)); + if (busy->next) + remove_queue(busy); + req.Function = MTD_REQ_ERASE | cause; + req.TransferLength = erase->Size; + req.DestCardOffset = erase->Offset + erase->Handle->info.CardOffset; + req.MediaID = erase->Handle->MediaID; + mtd = erase->Handle->mtd; + s = SOCKET(mtd); + mtd->event_callback_args.mtdrequest = &req; + ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW); + if (ret == CS_BUSY) { + DEBUG(2, (" Status = %d, requeueing.\n", req.Status)); + switch (req.Status) { + case MTD_WAITREQ: + case MTD_WAITPOWER: + insert_queue(&mtd->erase_busy, busy); + break; + case MTD_WAITTIMER: + case MTD_WAITRDY: + if (req.Status == MTD_WAITRDY) + insert_queue(&s->erase_busy, busy); + busy->timeout.expires = jiffies + req.Timeout*HZ/1000; + add_timer(&busy->timeout); + break; + } + } else { + /* update erase queue status */ + DEBUG(2, (" Ret = %d\n", ret)); + switch (ret) { + case CS_SUCCESS: + erase->State = ERASE_PASSED; break; + case CS_WRITE_PROTECTED: + erase->State = ERASE_MEDIA_WRPROT; break; + case CS_BAD_OFFSET: + erase->State = ERASE_BAD_OFFSET; break; + case CS_BAD_SIZE: + erase->State = ERASE_BAD_SIZE; break; + case CS_NO_CARD: + erase->State = ERASE_BAD_SOCKET; break; + default: + erase->State = ERASE_FAILED; break; + } + busy->client->event_callback_args.info = erase; + EVENT(busy->client, CS_EVENT_ERASE_COMPLETE, CS_EVENT_PRI_LOW); + kfree_s(busy, sizeof(*busy)); + /* Resubmit anything waiting for a request to finish */ + wake_up_interruptible(&mtd->mtd_req); + retry_erase_list(&mtd->erase_busy, 0); + } +} /* retry_erase */ + +void retry_erase_list(erase_busy_t *list, u_int cause) +{ + erase_busy_t tmp = *list; + + DEBUG(2, ("cs: rescanning erase queue list 0x%p\n", list)); + if (list->next == list) + return; + /* First, truncate the original list */ + list->prev->next = &tmp; + list->next->prev = &tmp; + list->prev = list->next = list; + tmp.prev->next = &tmp; + tmp.next->prev = &tmp; + + /* Now, retry each request, in order. */ + while (tmp.next != &tmp) + retry_erase(tmp.next, cause); +} /* retry_erase_list */ + +static void handle_erase_timeout(u_long arg) +{ + DEBUG(0, ("cs: erase timeout for entry 0x%lx\n", arg)); + retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT); +} + +static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase) +{ + erase_busy_t *busy; + region_info_t *info; + + if (CHECK_REGION(erase->Handle)) + erase->State = ERASE_BAD_SOCKET; + else { + info = &erase->Handle->info; + if ((erase->Offset >= info->RegionSize) || + (erase->Offset & (info->BlockSize-1))) + erase->State = ERASE_BAD_OFFSET; + else if ((erase->Offset+erase->Size > info->RegionSize) || + (erase->Size & (info->BlockSize-1))) + erase->State = ERASE_BAD_SIZE; + else { + erase->State = 1; + busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL); + busy->erase = erase; + busy->client = handle; + busy->timeout.prev = busy->timeout.next = NULL; + busy->timeout.data = (u_long)busy; + busy->timeout.function = &handle_erase_timeout; + busy->prev = busy->next = NULL; + retry_erase(busy, 0); + } + } +} /* setup_erase_request */ + +/*====================================================================== + + MTD helper functions + +======================================================================*/ + +static int mtd_modify_window(window_handle_t win, mtd_mod_win_t *req) +{ + if ((win == NULL) || (win->magic != WINDOW_MAGIC)) + return CS_BAD_HANDLE; + win->ctl.flags = MAP_16BIT | MAP_ACTIVE; + if (req->Attributes & WIN_USE_WAIT) + win->ctl.flags |= MAP_USE_WAIT; + if (req->Attributes & WIN_MEMORY_TYPE) + win->ctl.flags |= MAP_ATTRIB; + win->ctl.speed = req->AccessSpeed; + win->ctl.card_start = req->CardOffset; + win->sock->ss_entry(win->sock->sock, SS_SetMemMap, &win->ctl); + return CS_SUCCESS; +} + +static int mtd_set_vpp(client_handle_t handle, mtd_vpp_req_t *req) +{ + socket_info_t *s; + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + if (req->Vpp1 != req->Vpp2) + return CS_BAD_VPP; + s = SOCKET(handle); + s->socket.Vpp = req->Vpp1; + if (s->ss_entry(s->sock, SS_SetSocket, &s->socket)) + return CS_BAD_VPP; + return CS_SUCCESS; +} + +static int mtd_rdy_mask(client_handle_t handle, mtd_rdy_req_t *req) +{ + socket_info_t *s; + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); + if (req->Mask & CS_EVENT_READY_CHANGE) + s->socket.csc_mask |= SS_READY; + else + s->socket.csc_mask &= ~SS_READY; + if (s->ss_entry(s->sock, SS_SetSocket, &s->socket)) + return CS_GENERAL_FAILURE; + return CS_SUCCESS; +} + +int MTDHelperEntry(int func, void *a1, void *a2) +{ + switch (func) { + case MTDRequestWindow: + return CardServices(RequestWindow, a1, a2, NULL); + case MTDReleaseWindow: + return CardServices(ReleaseWindow, a1, NULL, NULL); + case MTDModifyWindow: + return mtd_modify_window(a1, a2); break; + case MTDSetVpp: + return mtd_set_vpp(a1, a2); break; + case MTDRDYMask: + return mtd_rdy_mask(a1, a2); break; + default: + return CS_UNSUPPORTED_FUNCTION; break; + } +} /* MTDHelperEntry */ + +/*====================================================================== + + This stuff is used by Card Services to initialize the table of + region info used for subsequent calls to GetFirstRegion and + GetNextRegion. + +======================================================================*/ + +static void setup_regions(client_handle_t handle, int attr, + memory_handle_t *list) +{ + int i, code, has_jedec, has_geo; + u_int offset; + cistpl_device_t device; + cistpl_jedec_t jedec; + cistpl_device_geo_t geo; + memory_handle_t r; + + DEBUG(1, ("cs: setup_regions(0x%p, %d, 0x%p)\n", + handle, attr, list)); + + code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE; + if (read_tuple(handle, code, &device) != CS_SUCCESS) + return; + code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C; + has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS); + if (has_jedec && (device.ndev != jedec.nid)) { +#ifdef PCMCIA_DEBUG + printk(KERN_DEBUG "cs: Device info does not match JEDEC info.\n"); +#endif + has_jedec = 0; + } + code = (attr) ? CISTPL_DEVICE_GEO_A : CISTPL_DEVICE_GEO; + has_geo = (read_tuple(handle, code, &geo) == CS_SUCCESS); + if (has_geo && (device.ndev != geo.ngeo)) { +#ifdef PCMCIA_DEBUG + printk(KERN_DEBUG "cs: Device info does not match geometry tuple.\n"); +#endif + has_geo = 0; + } + + offset = 0; + for (i = 0; i < device.ndev; i++) { + if ((device.dev[i].type != CISTPL_DTYPE_NULL) && + (device.dev[i].size != 0)) { + r = kmalloc(sizeof(*r), GFP_KERNEL); + r->region_magic = REGION_MAGIC; + r->state = 0; + r->dev_info[0] = '\0'; + r->mtd = NULL; + r->info.Attributes = (attr) ? REGION_TYPE_AM : 0; + r->info.CardOffset = offset; + r->info.RegionSize = device.dev[i].size; + r->info.AccessSpeed = device.dev[i].speed; + if (has_jedec) { + r->info.JedecMfr = jedec.id[i].mfr; + r->info.JedecInfo = jedec.id[i].info; + } else + r->info.JedecMfr = r->info.JedecInfo = 0; + if (has_geo) { + r->info.BlockSize = geo.geo[i].buswidth * + geo.geo[i].erase_block * geo.geo[i].interleave; + r->info.PartMultiple = + r->info.BlockSize * geo.geo[i].partition; + } else + r->info.BlockSize = r->info.PartMultiple = 1; + r->info.next = *list; *list = r; + } + offset += device.dev[i].size; + } +} /* setup_regions */ + +/*====================================================================== + + This is tricky. When get_first_region() is called by Driver + Services, we initialize the region info table in the socket + structure. When it is called by an MTD, we can just scan the + table for matching entries. + +======================================================================*/ + +static int match_region(client_handle_t handle, memory_handle_t list, + region_info_t *match) +{ + while (list != NULL) { + if (!(handle->Attributes & INFO_MTD_CLIENT) || + (strcmp(handle->dev_info, list->dev_info) == 0)) { + *match = list->info; + return CS_SUCCESS; + } + list = list->info.next; + } + return CS_NO_MORE_ITEMS; +} /* match_region */ + +int get_first_region(client_handle_t handle, region_info_t *rgn) +{ + socket_info_t *s = SOCKET(handle); + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + + if ((handle->Attributes & INFO_MASTER_CLIENT) && + (!(s->state & SOCKET_REGION_INFO))) { + setup_regions(handle, 0, &s->c_region); + setup_regions(handle, 1, &s->a_region); + s->state |= SOCKET_REGION_INFO; + } + + if (rgn->Attributes & REGION_TYPE_AM) + return match_region(handle, s->a_region, rgn); + else + return match_region(handle, s->c_region, rgn); +} /* get_first_region */ + +int get_next_region(client_handle_t handle, region_info_t *rgn) +{ + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + return match_region(handle, rgn->next, rgn); +} /* get_next_region */ + +/*====================================================================== + + Connect an MTD with a memory region. + +======================================================================*/ + +int register_mtd(client_handle_t handle, mtd_reg_t *reg) +{ + memory_handle_t list; + socket_info_t *s; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); + if (reg->Attributes & REGION_TYPE_AM) + list = s->a_region; + else + list = s->c_region; + DEBUG(1, ("cs: register_mtd(0x%p, '%s', 0x%x)\n", + handle, handle->dev_info, reg->Offset)); + while (list) { + if (list->info.CardOffset == reg->Offset) break; + list = list->info.next; + } + if (list && (list->mtd == NULL) && + (strcmp(handle->dev_info, list->dev_info) == 0)) { + list->info.Attributes = reg->Attributes; + list->MediaID = reg->MediaID; + list->mtd = handle; + handle->mtd_count++; + return CS_SUCCESS; + } else + return CS_BAD_OFFSET; +} /* register_mtd */ + +/*====================================================================== + + + +======================================================================*/ + +int register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header) +{ + eraseq_t *queue; + + if ((handle == NULL) || CHECK_HANDLE(*handle)) + return CS_BAD_HANDLE; + queue = kmalloc(sizeof(*queue), GFP_KERNEL); + queue->eraseq_magic = ERASEQ_MAGIC; + queue->handle = *handle; + queue->count = header->QueueEntryCnt; + queue->entry = header->QueueEntryArray; + *handle = (client_handle_t)queue; + return CS_SUCCESS; +} /* register_erase_queue */ + +int deregister_erase_queue(eraseq_handle_t eraseq) +{ + int i; + if (CHECK_ERASEQ(eraseq)) + return CS_BAD_HANDLE; + for (i = 0; i < eraseq->count; i++) + if (ERASE_IN_PROGRESS(eraseq->entry[i].State)) break; + if (i < eraseq->count) + return CS_BUSY; + eraseq->eraseq_magic = 0; + kfree_s(eraseq, sizeof(*eraseq)); + return CS_SUCCESS; +} /* deregister_erase_queue */ + +int check_erase_queue(eraseq_handle_t eraseq) +{ + int i; + if (CHECK_ERASEQ(eraseq)) + return CS_BAD_HANDLE; + for (i = 0; i < eraseq->count; i++) + if (eraseq->entry[i].State == ERASE_QUEUED) + setup_erase_request(eraseq->handle, &eraseq->entry[i]); + return CS_SUCCESS; +} /* check_erase_queue */ + +/*====================================================================== + + Look up the memory region matching the request, and return a + memory handle. + +======================================================================*/ + +int open_memory(client_handle_t *handle, open_mem_t *open) +{ + socket_info_t *s; + memory_handle_t region; + + if ((handle == NULL) || CHECK_HANDLE(*handle)) + return CS_BAD_HANDLE; + s = SOCKET(*handle); + if (open->Attributes & MEMORY_TYPE_AM) + region = s->a_region; + else + region = s->c_region; + while (region) { + if (region->info.CardOffset == open->Offset) break; + region = region->info.next; + } + if (region && region->mtd) { + *handle = (client_handle_t)region; + DEBUG(1, ("cs: open_memory(0x%p, 0x%x) = 0x%p\n", + handle, open->Offset, region)); + return CS_SUCCESS; + } else + return CS_BAD_OFFSET; +} /* open_memory */ + +/*====================================================================== + + Close a memory handle from an earlier call to OpenMemory. + + For the moment, I don't think this needs to do anything. + +======================================================================*/ + +int close_memory(memory_handle_t handle) +{ + DEBUG(1, ("cs: close_memory(0x%p)\n", handle)); + if (CHECK_REGION(handle)) + return CS_BAD_HANDLE; + return CS_SUCCESS; +} /* close_memory */ + +/*====================================================================== + + Read from a memory device, using a handle previously returned + by a call to OpenMemory. + +======================================================================*/ + +int read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf) +{ + mtd_request_t mtd; + if (CHECK_REGION(handle)) + return CS_BAD_HANDLE; + if (req->Offset >= handle->info.RegionSize) + return CS_BAD_OFFSET; + if (req->Offset+req->Count > handle->info.RegionSize) + return CS_BAD_SIZE; + + mtd.SrcCardOffset = req->Offset + handle->info.CardOffset; + mtd.TransferLength = req->Count; + mtd.MediaID = handle->MediaID; + mtd.Function = MTD_REQ_READ; + if (req->Attributes & MEM_OP_BUFFER_KERNEL) + mtd.Function |= MTD_REQ_KERNEL; + return do_mtd_request(handle, &mtd, buf); +} /* read_memory */ + +/*====================================================================== + + Write to a memory device, using a handle previously returned by + a call to OpenMemory. + +======================================================================*/ + +int write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf) +{ + mtd_request_t mtd; + if (CHECK_REGION(handle)) + return CS_BAD_HANDLE; + if (req->Offset >= handle->info.RegionSize) + return CS_BAD_OFFSET; + if (req->Offset+req->Count > handle->info.RegionSize) + return CS_BAD_SIZE; + + mtd.DestCardOffset = req->Offset + handle->info.CardOffset; + mtd.TransferLength = req->Count; + mtd.MediaID = handle->MediaID; + mtd.Function = MTD_REQ_WRITE; + if (req->Attributes & MEM_OP_BUFFER_KERNEL) + mtd.Function |= MTD_REQ_KERNEL; + return do_mtd_request(handle, &mtd, buf); +} /* write_memory */ + +/*====================================================================== + + +======================================================================*/ + +int copy_memory(memory_handle_t handle, copy_op_t *req) +{ + if (CHECK_REGION(handle)) + return CS_BAD_HANDLE; + return CS_UNSUPPORTED_FUNCTION; +} /* close_memory */ + diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c --- v2.3.16/linux/drivers/pcmcia/cardbus.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/cardbus.c Tue Sep 7 11:13:24 1999 @@ -0,0 +1,638 @@ +/*====================================================================== + + Cardbus device configuration + + cardbus.c 1.57 1999/09/07 15:19:32 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + + These routines handle allocating resources for Cardbus cards, as + well as setting up and shutting down Cardbus sockets. They are + called from cs.c in response to Request/ReleaseConfiguration and + Request/ReleaseIO calls. + +======================================================================*/ + +#define __NO_VERSION__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PCMCIA_DEBUG +#define PCMCIA_DEBUG 1 +#endif +static int pc_debug = PCMCIA_DEBUG; + +#define IN_CARD_SERVICES +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" +#include "rsrc_mgr.h" + +/*====================================================================*/ + +#define FIND_FIRST_BIT(n) ((n) - ((n) & ((n)-1))) + +#define pci_readb pcibios_read_config_byte +#define pci_writeb pcibios_write_config_byte +#define pci_readw pcibios_read_config_word +#define pci_writew pcibios_write_config_word +#define pci_readl pcibios_read_config_dword +#define pci_writel pcibios_write_config_dword + +#define CB_BAR(n) (PCI_BASE_ADDRESS_0+(4*(n))) +#define CB_ROM_BASE 0x0030 + +/* Offsets in the Expansion ROM Image Header */ +#define ROM_SIGNATURE 0x0000 /* 2 bytes */ +#define ROM_DATA_PTR 0x0018 /* 2 bytes */ + +/* Offsets in the CardBus PC Card Data Structure */ +#define PCDATA_SIGNATURE 0x0000 /* 4 bytes */ +#define PCDATA_VPD_PTR 0x0008 /* 2 bytes */ +#define PCDATA_LENGTH 0x000a /* 2 bytes */ +#define PCDATA_REVISION 0x000c +#define PCDATA_IMAGE_SZ 0x0010 /* 2 bytes */ +#define PCDATA_ROM_LEVEL 0x0012 /* 2 bytes */ +#define PCDATA_CODE_TYPE 0x0014 +#define PCDATA_INDICATOR 0x0015 + +typedef struct cb_config_t { + u_int size[7]; + struct pci_dev dev; +} cb_config_t; + +#define BASE(dev,n) ((dev).resource[n].start) +#define ROM(dev) ((dev).resource[6].start) + +/* There are three classes of bridge maps: IO ports, + non-prefetchable memory, and prefetchable memory */ +typedef enum { B_IO, B_M1, B_M2 } bridge_type; + +/*===================================================================== + + Expansion ROM's have a special layout, and pointers specify an + image number and an offset within that image. check_rom() + verifies that the expansion ROM exists and has the standard + layout. xlate_rom_addr() converts an image/offset address to an + absolute offset from the ROM's base address. + +=====================================================================*/ + +static int check_rom(u_char *b, u_long len) +{ + u_int img = 0, ofs = 0, sz; + u_short data; + DEBUG(0, "ROM image dump:\n"); + while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) { + data = readb(b+ROM_DATA_PTR) + + (readb(b+ROM_DATA_PTR+1) << 8); + sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) + + (readb(b+data+PCDATA_IMAGE_SZ+1) << 8)); + DEBUG(0, " image %d: 0x%06x-0x%06x, signature %c%c%c%c\n", + img, ofs, ofs+sz-1, + readb(b+data+PCDATA_SIGNATURE), + readb(b+data+PCDATA_SIGNATURE+1), + readb(b+data+PCDATA_SIGNATURE+2), + readb(b+data+PCDATA_SIGNATURE+3)); + ofs += sz; img++; + if ((readb(b+data+PCDATA_INDICATOR) & 0x80) || + (sz == 0) || (ofs >= len)) break; + b += sz; + } + return img; +} + +static u_int xlate_rom_addr(u_char *b, u_int addr) +{ + u_int img = 0, ofs = 0, sz; + u_short data; + while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) { + if (img == (addr >> 28)) + return (addr & 0x0fffffff) + ofs; + data = readb(b+ROM_DATA_PTR) + (readb(b+ROM_DATA_PTR+1) << 8); + sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) + + (readb(b+data+PCDATA_IMAGE_SZ+1) << 8)); + if ((sz == 0) || (readb(b+data+PCDATA_INDICATOR) & 0x80)) + break; + b += sz; ofs += sz; img++; + } + return 0; +} + +/*===================================================================== + + These are similar to setup_cis_mem and release_cis_mem for 16-bit + cards. The "result" that is used externally is the cb_cis_virt + pointer in the socket_info_t structure. + +=====================================================================*/ + +int cb_setup_cis_mem(socket_info_t *s, int space) +{ + cb_bridge_map *m = &s->cb_cis_map; + u_long base = 0; + u_int sz, br; + + if (space == s->cb_cis_space) + return CS_SUCCESS; + else if (s->cb_cis_space != 0) + cb_release_cis_mem(s); + DEBUG(1, "cs: cb_setup_cis_mem(space %d)\n", space); + /* If socket is configured, then use existing memory mapping */ + if (s->lock_count) { + s->cb_cis_virt = + ioremap(BASE(s->cb_config[0].dev, space-1), + s->cb_config[0].size[space-1] & ~3); + s->cb_cis_space = space; + return CS_SUCCESS; + } + + /* Not configured? Then set up temporary map */ + br = (space == 7) ? CB_ROM_BASE : CB_BAR(space-1); + pci_writel(s->cap.cardbus, 0, br, 0xffffffff); + pci_readl(s->cap.cardbus, 0, br, &sz); + sz &= PCI_BASE_ADDRESS_MEM_MASK; + sz = FIND_FIRST_BIT(sz); + if (sz < PAGE_SIZE) sz = PAGE_SIZE; + if (find_mem_region(&base, sz, "cb_enabler", sz, 0) != 0) { + printk(KERN_NOTICE "cs: could not allocate %dK memory for" + " CardBus socket %d\n", sz/1024, s->sock); + return CS_OUT_OF_RESOURCE; + } + s->cb_cis_space = space; + s->cb_cis_virt = ioremap(base, sz); + DEBUG(1, " phys 0x%08lx-0x%08lx, virt 0x%08lx\n", + base, base+sz-1, (u_long)s->cb_cis_virt); + pci_writel(s->cap.cardbus, 0, br, base | 1); + pci_writeb(s->cap.cardbus, 0, PCI_COMMAND, PCI_COMMAND_MEMORY); + m->map = 0; m->flags = MAP_ACTIVE; + m->start = base; m->stop = base+sz-1; + s->ss_entry(s->sock, SS_SetBridge, m); + if ((space == 7) && (check_rom(s->cb_cis_virt, sz) == 0)) { + printk(KERN_NOTICE "cs: no valid ROM images found!\n"); + return CS_READ_FAILURE; + } + return CS_SUCCESS; +} + +void cb_release_cis_mem(socket_info_t *s) +{ + cb_bridge_map *m = &s->cb_cis_map; + u_int br; + if (s->cb_cis_virt) { + DEBUG(1, "cs: cb_release_cis_mem()\n"); + iounmap(s->cb_cis_virt); + s->cb_cis_virt = NULL; + s->cb_cis_space = 0; + } + if (m->start) { + /* This is overkill: we probably only need to release the + memory region, but the rest should be safe */ + br = (s->cb_cis_space == 7) ? + CB_ROM_BASE : CB_BAR(s->cb_cis_space-1); + m->map = 0; m->flags = 0; + s->ss_entry(s->sock, SS_SetBridge, m); + pci_writeb(s->cap.cardbus, 0, PCI_COMMAND, 0); + pci_writel(s->cap.cardbus, 0, br, 0); + release_mem_region(m->start, m->stop - m->start + 1); + m->start = 0; + } +} + +/*===================================================================== + + This is used by the CIS processing code to read CIS information + from a CardBus device. + +=====================================================================*/ + +void read_cb_mem(socket_info_t *s, u_char fn, int space, + u_int addr, u_int len, void *ptr) +{ + DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len); + if (space == 0) { + if (addr+len > 0x100) goto fail; + for (; len; addr++, ptr++, len--) + pci_readb(s->cap.cardbus, fn, addr, (u_char *)ptr); + } else { + if (cb_setup_cis_mem(s, space) != 0) goto fail; + if (space == 7) { + addr = xlate_rom_addr(s->cb_cis_virt, addr); + if (addr == 0) goto fail; + } + if (addr+len > s->cb_cis_map.stop - s->cb_cis_map.start) + goto fail; + if (s->cb_cis_virt != NULL) + for (; len; addr++, ptr++, len--) + *(u_char *)ptr = readb(s->cb_cis_virt+addr); + } + return; + fail: + memset(ptr, 0xff, len); + return; +} + +/*===================================================================== + + cb_alloc() and cb_free() allocate and free the kernel data + structures for a Cardbus device, and handle the lowest level PCI + device setup issues. + +=====================================================================*/ + +int cb_alloc(socket_info_t *s) +{ + struct pci_dev tmp; + u_short vend, v, dev; + u_char i, hdr, fn, bus = s->cap.cardbus; + cb_config_t *c; + + tmp.bus = s->cap.cb_bus; tmp.devfn = 0; + tmp.next = pci_devices; pci_devices = &tmp; + + pci_readw(bus, 0, PCI_VENDOR_ID, &vend); + pci_readw(bus, 0, PCI_DEVICE_ID, &dev); + printk(KERN_INFO "cs: cb_alloc(bus %d): vendor 0x%04x, " + "device 0x%04x\n", bus, vend, dev); + + pci_readb(bus, 0, PCI_HEADER_TYPE, &hdr); + if (hdr & 0x80) { + /* Count functions */ + for (fn = 0; fn < 8; fn++) { + tmp.devfn = fn; + pci_readw(bus, fn, PCI_VENDOR_ID, &v); + if (v != vend) break; + } + } else fn = 1; + s->functions = fn; + + c = kmalloc(fn * sizeof(struct cb_config_t), GFP_ATOMIC); + if (!c) return CS_OUT_OF_RESOURCE; + memset(c, 0, fn * sizeof(struct cb_config_t)); + s->cb_config = c; + + pci_devices = tmp.next; + for (i = 0; i < fn; i++) { + c[i].dev.bus = s->cap.cb_bus; + c[i].dev.devfn = i; + if (i < fn-1) { + c[i].dev.sibling = c[i].dev.next = &c[i+1].dev; + } + } + s->cap.cb_bus->devices = &c[0].dev; + /* Link into PCI device chain */ + c[s->functions-1].dev.next = pci_devices; + pci_devices = &c[0].dev; + for (i = 0; i < fn; i++) { + c[i].dev.vendor = vend; + pci_readw(bus, i, PCI_DEVICE_ID, &c[i].dev.device); + pci_readl(bus, i, PCI_CLASS_REVISION, &c[i].dev.class); + c[i].dev.class >>= 8; + c[i].dev.hdr_type = hdr; + pci_proc_attach_device(&c[i].dev); + } + + return CS_SUCCESS; +} + +void cb_free(socket_info_t *s) +{ + struct pci_dev **p, *q; + cb_config_t *c = s->cb_config; + + if (c) { + /* Unlink from PCI device chain */ + for (p = &pci_devices; *p; p = &((*p)->next)) + if (*p == &c[0].dev) break; + for (q = *p; q; q = q->next) { + if (q->bus != (*p)->bus) break; + pci_proc_detach_device(q); + } + if (*p) *p = q; + s->cap.cb_bus->devices = NULL; + } + printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cardbus); + if (s->cb_config) { + kfree(s->cb_config); + s->cb_config = NULL; + } +} + +/*===================================================================== + + cb_config() has the job of allocating all system resources that + a Cardbus card requires. Rather than using the CIS (which seems + to not always be present), it treats the card as an ordinary PCI + device, and probes the base address registers to determine each + function's IO and memory space needs. + + It is called from the RequestIO card service. + +======================================================================*/ + +int cb_config(socket_info_t *s) +{ + cb_config_t *c = s->cb_config; + u_char fn = s->functions; + u_char i, j, bus = s->cap.cardbus, *name; + u_int sz, align, m, mask[3], num[3], base[3]; + int irq, try, ret; + + printk(KERN_INFO "cs: cb_config(bus %d)\n", s->cap.cardbus); + + /* Determine IO and memory space needs */ + num[B_IO] = num[B_M1] = num[B_M2] = 0; + mask[B_IO] = mask[B_M1] = mask[B_M2] = 0; + for (i = 0; i < fn; i++) { + for (j = 0; j < 6; j++) { + pci_writel(bus, i, CB_BAR(j), 0xffffffff); + pci_readl(bus, i, CB_BAR(j), &sz); + if (sz == 0) continue; + if (sz & PCI_BASE_ADDRESS_SPACE) { + m = B_IO; + sz &= PCI_BASE_ADDRESS_IO_MASK; + } else { + m = (sz & PCI_BASE_ADDRESS_MEM_PREFETCH) ? B_M2 : B_M1; + sz &= PCI_BASE_ADDRESS_MEM_MASK; + } + sz = FIND_FIRST_BIT(sz); + c[i].size[j] = sz | m; + if (m && (sz < PAGE_SIZE)) sz = PAGE_SIZE; + num[m] += sz; mask[m] |= sz; + } + pci_writel(bus, i, CB_ROM_BASE, 0xffffffff); + pci_readl(bus, i, CB_ROM_BASE, &sz); + if (sz != 0) { + sz = FIND_FIRST_BIT(sz & ~0x00000001); + c[i].size[6] = sz | B_M1; + if (sz < PAGE_SIZE) sz = PAGE_SIZE; + num[B_M1] += sz; mask[B_M1] |= sz; + } + } + + /* Allocate system resources */ + name = "cb_enabler"; + s->io[0].NumPorts = num[B_IO]; + s->io[0].BasePort = 0; + if (num[B_IO]) { + if (find_io_region(&s->io[0].BasePort, num[B_IO], name) != 0) { + printk(KERN_NOTICE "cs: could not allocate %d IO ports for" + " CardBus socket %d\n", num[B_IO], s->sock); + goto failed; + } + base[B_IO] = s->io[0].BasePort + num[B_IO]; + } + s->win[0].size = num[B_M1]; + s->win[0].base = 0; + if (num[B_M1]) { + if (find_mem_region(&s->win[0].base, num[B_M1], + name, num[B_M1], 0) != 0) { + printk(KERN_NOTICE "cs: could not allocate %dK memory for" + " CardBus socket %d\n", num[B_M1]/1024, s->sock); + goto failed; + } + base[B_M1] = s->win[0].base + num[B_M1]; + } + s->win[1].size = num[B_M2]; + s->win[1].base = 0; + if (num[B_M2]) { + if (find_mem_region(&s->win[1].base, num[B_M2], + name, num[B_M2], 0) != 0) { + printk(KERN_NOTICE "cs: could not allocate %dK memory for" + " CardBus socket %d\n", num[B_M2]/1024, s->sock); + goto failed; + } + base[B_M2] = s->win[1].base + num[B_M2]; + } + + /* Set up base address registers */ + while (mask[B_IO] | mask[B_M1] | mask[B_M2]) { + num[B_IO] = FIND_FIRST_BIT(mask[B_IO]); mask[B_IO] -= num[B_IO]; + num[B_M1] = FIND_FIRST_BIT(mask[B_M1]); mask[B_M1] -= num[B_M1]; + num[B_M2] = FIND_FIRST_BIT(mask[B_M2]); mask[B_M2] -= num[B_M2]; + for (i = 0; i < fn; i++) { + for (j = 0; j < 7; j++) { + sz = c[i].size[j]; + m = sz & 3; sz &= ~3; + align = (m && (sz < PAGE_SIZE)) ? PAGE_SIZE : sz; + if (sz && (align == num[m])) { + base[m] -= align; + if (j < 6) + printk(KERN_INFO " fn %d bar %d: ", i, j+1); + else + printk(KERN_INFO " fn %d rom: ", i); + printk("%s 0x%x-0x%x\n", (m) ? "mem" : "io", + base[m], base[m]+sz-1); + BASE(c[i].dev, j) = base[m]; + } + } + } + } + + /* Allocate interrupt if needed */ + s->irq.AssignedIRQ = irq = 0; ret = -1; + for (i = 0; i < fn; i++) { + pci_readb(bus, i, PCI_INTERRUPT_PIN, &j); + if (j == 0) continue; + if (irq == 0) { + if (s->cap.irq_mask & (1 << s->cap.pci_irq)) { + irq = s->cap.pci_irq; + ret = 0; + } +#ifdef CONFIG_ISA + else + for (try = 0; try < 2; try++) { + for (irq = 0; irq < 32; irq++) + if ((s->cap.irq_mask >> irq) & 1) { + ret = try_irq(IRQ_TYPE_EXCLUSIVE, irq, try); + if (ret == 0) break; + } + if (ret == 0) break; + } + if (ret != 0) { + printk(KERN_NOTICE "cs: could not allocate interrupt" + " for CardBus socket %d\n", s->sock); + goto failed; + } +#endif + s->irq.AssignedIRQ = irq; + } + } + c[0].dev.irq = irq; + + return CS_SUCCESS; + +failed: + cb_release(s); + return CS_OUT_OF_RESOURCE; +} + +/*====================================================================== + + cb_release() releases all the system resources (IO and memory + space, and interrupt) committed for a Cardbus card by a prior call + to cb_config(). + + It is called from the ReleaseIO() service. + +======================================================================*/ + +void cb_release(socket_info_t *s) +{ + cb_config_t *c = s->cb_config; + + DEBUG(0, "cs: cb_release(bus %d)\n", s->cap.cardbus); + + if (s->win[0].size > 0) + release_mem_region(s->win[0].base, s->win[0].size); + if (s->win[1].size > 0) + release_mem_region(s->win[1].base, s->win[1].size); + if (s->io[0].NumPorts > 0) + release_region(s->io[0].BasePort, s->io[0].NumPorts); + s->io[0].NumPorts = 0; +#ifdef CONFIG_ISA + if ((c[0].dev.irq != 0) && (c[0].dev.irq != s->cap.pci_irq)) + undo_irq(IRQ_TYPE_EXCLUSIVE, c[0].dev.irq); +#endif +} + +/*===================================================================== + + cb_enable() has the job of configuring a socket for a Cardbus + card, and initializing the card's PCI configuration registers. + + It first sets up the Cardbus bridge windows, for IO and memory + accesses. Then, it initializes each card function's base address + registers, interrupt line register, and command register. + + It is called as part of the RequestConfiguration card service. + It should be called after a previous call to cb_config() (via the + RequestIO service). + +======================================================================*/ + +void cb_enable(socket_info_t *s) +{ + u_char i, j, bus = s->cap.cardbus; + cb_config_t *c = s->cb_config; + + DEBUG(0, "cs: cb_enable(bus %d)\n", bus); + + /* Configure bridge */ + if (s->cb_cis_map.start) + cb_release_cis_mem(s); + for (i = 0; i < 3; i++) { + cb_bridge_map m; + switch (i) { + case B_IO: + m.map = 0; m.flags = MAP_IOSPACE | MAP_ACTIVE; + m.start = s->io[0].BasePort; + m.stop = m.start + s->io[0].NumPorts - 1; + break; + case B_M1: + m.map = 0; m.flags = MAP_ACTIVE; + m.start = s->win[0].base; + m.stop = m.start + s->win[0].size - 1; + break; + case B_M2: + m.map = 1; m.flags = MAP_PREFETCH | MAP_ACTIVE; + m.start = s->win[1].base; + m.stop = m.start + s->win[1].size - 1; + break; + } + if (m.start == 0) continue; + DEBUG(0, " bridge %s map %d (flags 0x%x): 0x%x-0x%x\n", + (m.flags & MAP_IOSPACE) ? "io" : "mem", + m.map, m.flags, m.start, m.stop); + s->ss_entry(s->sock, SS_SetBridge, &m); + } + + /* Set up base address registers */ + for (i = 0; i < s->functions; i++) { + for (j = 0; j < 6; j++) { + if (BASE(c[i].dev, j) != 0) + pci_writel(bus, i, CB_BAR(j), BASE(c[i].dev, j)); + } + if (ROM(c[i].dev) != 0) + pci_writel(bus, i, CB_ROM_BASE, ROM(c[i].dev) | 1); + } + + /* Set up PCI interrupt and command registers */ + for (i = 0; i < s->functions; i++) { + pci_writeb(bus, i, PCI_COMMAND, PCI_COMMAND_MASTER | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_writeb(bus, i, PCI_CACHE_LINE_SIZE, 8); + } + + if (s->irq.AssignedIRQ) { + for (i = 0; i < s->functions; i++) + pci_writeb(bus, i, PCI_INTERRUPT_LINE, + s->irq.AssignedIRQ); + s->socket.io_irq = s->irq.AssignedIRQ; + s->ss_entry(s->sock, SS_SetSocket, &s->socket); + } +} + +/*====================================================================== + + cb_disable() unconfigures a Cardbus card previously set up by + cb_enable(). + + It is called from the ReleaseConfiguration service. + +======================================================================*/ + +void cb_disable(socket_info_t *s) +{ + u_char i; + cb_bridge_map m = { 0, 0, 0, 0xffff }; + + DEBUG(0, "cs: cb_disable(bus %d)\n", s->cap.cardbus); + + /* Turn off bridge windows */ + if (s->cb_cis_map.start) + cb_release_cis_mem(s); + for (i = 0; i < 3; i++) { + switch (i) { + case B_IO: m.map = 0; m.flags = MAP_IOSPACE; break; + case B_M1: m.map = m.flags = 0; break; + case B_M2: m.map = 1; m.flags = 0; break; + } + s->ss_entry(s->sock, SS_SetBridge, &m); + } +} diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cb_enabler.c linux/drivers/pcmcia/cb_enabler.c --- v2.3.16/linux/drivers/pcmcia/cb_enabler.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/cb_enabler.c Fri Sep 3 13:49:12 1999 @@ -0,0 +1,405 @@ +/*====================================================================== + + Cardbus device enabler + + cb_enabler.c 1.21 1999/08/28 04:01:45 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + + The general idea: + + A client driver registers using register_driver(). This module + then creates a Card Services pseudo-client and registers it, and + configures the socket if this is the first client. It then + invokes the appropriate PCI client routines in response to Card + Services events. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"cb_enabler.c 1.21 1999/08/28 04:01:45 (David Hinds)"; +#else +#define DEBUG(n, args...) do { } while (0) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/*====================================================================*/ + +typedef struct driver_info_t { + dev_link_t *(*attach)(void); + dev_info_t dev_info; + driver_operations *ops; + dev_link_t *dev_list; +} driver_info_t; + +static dev_link_t *cb_attach(int n); +#define MK_ENTRY(fn, n) \ +static dev_link_t *fn(void) { return cb_attach(n); } + +#define MAX_DRIVER 4 + +MK_ENTRY(attach_0, 0); +MK_ENTRY(attach_1, 1); +MK_ENTRY(attach_2, 2); +MK_ENTRY(attach_3, 3); + +static driver_info_t driver[4] = { + { attach_0 }, { attach_1 }, { attach_2 }, { attach_3 } +}; + +typedef struct bus_info_t { + u_char bus; + int flags, ncfg, nuse; + dev_link_t *owner; +} bus_info_t; + +#define DID_REQUEST 1 +#define DID_CONFIG 2 + +static void cb_release(u_long arg); +static int cb_event(event_t event, int priority, + event_callback_args_t *args); + +static void cb_detach(dev_link_t *); + +static bus_info_t bus_table[MAX_DRIVER]; + + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================*/ + +struct dev_link_t *cb_attach(int n) +{ + client_reg_t client_reg; + dev_link_t *link; + int ret; + + DEBUG(0, "cb_attach(%d)\n", n); + + MOD_INC_USE_COUNT; + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &cb_release; + link->release.data = (u_long)link; + + link->conf.IntType = INT_CARDBUS; + link->conf.Vcc = 33; + + /* Insert into instance chain for this driver */ + link->priv = &driver[n]; + link->next = driver[n].dev_list; + driver[n].dev_list = link; + + /* Register with Card Services */ + client_reg.dev_info = &driver[n].dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.event_handler = &cb_event; + client_reg.EventMask = + CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + cb_detach(link); + return NULL; + } + return link; +} + +/*====================================================================*/ + +static void cb_detach(dev_link_t *link) +{ + driver_info_t *dev = link->priv; + dev_link_t **linkp; + bus_info_t *b = (void *)link->win; + u_long flags; + + DEBUG(0, "cb_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev->dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + save_flags(flags); + cli(); + if (link->state & DEV_RELEASE_PENDING) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + restore_flags(flags); + + if (link->state & DEV_CONFIG) + cb_release((u_long)link); + + /* Don't drop Card Services connection if we are the bus owner */ + if ((b->flags != 0) && (link == b->owner)) { + link->state |= DEV_STALE_LINK; + return; + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + *linkp = link->next; + kfree_s(link, sizeof(struct dev_link_t)); + MOD_DEC_USE_COUNT; +} + +/*====================================================================*/ + +static void cb_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + driver_info_t *drv = link->priv; + dev_locator_t loc; + bus_info_t *b; + config_info_t config; + u_char bus, devfn; + int i; + + DEBUG(0, "cb_config(0x%p)\n", link); + link->state |= DEV_CONFIG; + + /* Get PCI bus info */ + CardServices(GetConfigurationInfo, handle, &config); + bus = config.Option; devfn = config.Function; + + /* Is this a new bus? */ + for (i = 0; i < MAX_DRIVER; i++) + if (bus == bus_table[i].bus) break; + if (i == MAX_DRIVER) { + for (i = 0; i < MAX_DRIVER; i++) + if (bus_table[i].bus == 0) break; + b = &bus_table[i]; link->win = (void *)b; + b->bus = bus; + b->flags = 0; + b->ncfg = b->nuse = 1; + + /* Special hook: CS know what to do... */ + i = CardServices(RequestIO, handle, NULL); + if (i != CS_SUCCESS) { + cs_error(handle, RequestIO, i); + return; + } + b->flags |= DID_REQUEST; + b->owner = link; + i = CardServices(RequestConfiguration, handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(handle, RequestConfiguration, i); + return; + } + b->flags |= DID_CONFIG; + } else { + b = &bus_table[i]; link->win = (void *)b; + if (b->flags & DID_CONFIG) { + b->ncfg++; b->nuse++; + } + } + loc.bus = LOC_PCI; + loc.b.pci.bus = bus; + loc.b.pci.devfn = devfn; + link->dev = drv->ops->attach(&loc); + + link->state &= ~DEV_CONFIG_PENDING; +} + +/*====================================================================*/ + +static void cb_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + driver_info_t *drv = link->priv; + bus_info_t *b = (void *)link->win; + + DEBUG(0, "cb_release(0x%p)\n", link); + + if (link->dev != NULL) { + drv->ops->detach(link->dev); + link->dev = NULL; + } + if (link->state & DEV_CONFIG) { + /* If we're suspended, config was already released */ + if (link->state & DEV_SUSPEND) + b->flags &= ~DID_CONFIG; + else if ((b->flags & DID_CONFIG) && (--b->ncfg == 0)) { + CardServices(ReleaseConfiguration, b->owner->handle, + &b->owner->conf); + b->flags &= ~DID_CONFIG; + } + if ((b->flags & DID_REQUEST) && (--b->nuse == 0)) { + CardServices(ReleaseIO, b->owner->handle, NULL); + b->flags &= ~DID_REQUEST; + } + if (b->flags == 0) { + if (b->owner && (b->owner->state & DEV_STALE_LINK)) + cb_detach(b->owner); + b->bus = 0; b->owner = NULL; + } + } + link->state &= ~DEV_CONFIG; +} + +/*====================================================================*/ + +static int cb_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + driver_info_t *drv = link->priv; + bus_info_t *b = (void *)link->win; + + DEBUG(0, "cb_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + cb_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (drv->ops->suspend != NULL) + drv->ops->suspend(link->dev); + b->ncfg--; + if (b->ncfg == 0) + CardServices(ReleaseConfiguration, link->handle, + &link->conf); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + b->ncfg++; + if (b->ncfg == 1) + CardServices(RequestConfiguration, link->handle, + &link->conf); + if (drv->ops->resume != NULL) + drv->ops->resume(link->dev); + } + break; + } + return 0; +} + +/*====================================================================*/ + +int register_driver(struct driver_operations *ops) +{ + int i; + + DEBUG(0, "register_driver('%s')\n", ops->name); + + for (i = 0; i < MAX_DRIVER; i++) + if (driver[i].ops == NULL) break; + if (i == MAX_DRIVER) + return -1; + + MOD_INC_USE_COUNT; + driver[i].ops = ops; + strcpy(driver[i].dev_info, ops->name); + register_pccard_driver(&driver[i].dev_info, driver[i].attach, + &cb_detach); + return 0; +} + +void unregister_driver(struct driver_operations *ops) +{ + int i; + + DEBUG(0, "unregister_driver('%s')\n", ops->name); + for (i = 0; i < MAX_DRIVER; i++) + if (driver[i].ops == ops) break; + if (i < MAX_DRIVER) { + unregister_pccard_driver(&driver[i].dev_info); + driver[i].ops = NULL; + MOD_DEC_USE_COUNT; + } +} + +/*====================================================================*/ + +int init_module(void) { + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "cb_enabler: Card Services release " + "does not match!\n"); + return -1; + } + return 0; +} + +void cleanup_module(void) { + DEBUG(0, "cb_enabler: unloading\n"); +} + +/*====================================================================*/ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cirrus.h linux/drivers/pcmcia/cirrus.h --- v2.3.16/linux/drivers/pcmcia/cirrus.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/cirrus.h Fri Sep 3 12:27:58 1999 @@ -0,0 +1,157 @@ +/* + * cirrus.h 1.3 1999/08/28 04:01:46 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CIRRUS_H +#define _LINUX_CIRRUS_H + +#ifndef PCI_VENDOR_ID_CIRRUS +#define PCI_VENDOR_ID_CIRRUS 0x1013 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_6729 +#define PCI_DEVICE_ID_CIRRUS_6729 0x1100 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_6832 +#define PCI_DEVICE_ID_CIRRUS_6832 0x1110 +#endif + +#define PD67_MISC_CTL_1 0x16 /* Misc control 1 */ +#define PD67_FIFO_CTL 0x17 /* FIFO control */ +#define PD67_MISC_CTL_2 0x1E /* Misc control 2 */ +#define PD67_CHIP_INFO 0x1f /* Chip information */ +#define PD67_ATA_CTL 0x026 /* 6730: ATA control */ +#define PD67_EXT_INDEX 0x2e /* Extension index */ +#define PD67_EXT_DATA 0x2f /* Extension data */ + +/* PD6722 extension registers -- indexed in PD67_EXT_INDEX */ +#define PD67_DATA_MASK0 0x01 /* Data mask 0 */ +#define PD67_DATA_MASK1 0x02 /* Data mask 1 */ +#define PD67_DMA_CTL 0x03 /* DMA control */ + +/* PD6730 extension registers -- indexed in PD67_EXT_INDEX */ +#define PD67_EXT_CTL_1 0x03 /* Extension control 1 */ +#define PD67_MEM_PAGE(n) ((n)+5) /* PCI window bits 31:24 */ +#define PD67_EXTERN_DATA 0x0a +#define PD67_MISC_CTL_3 0x25 +#define PD67_SMB_PWR_CTL 0x26 + +/* I/O window address offset */ +#define PD67_IO_OFF(w) (0x36+((w)<<1)) + +/* Timing register sets */ +#define PD67_TIME_SETUP(n) (0x3a + 3*(n)) +#define PD67_TIME_CMD(n) (0x3b + 3*(n)) +#define PD67_TIME_RECOV(n) (0x3c + 3*(n)) + +/* Flags for PD67_MISC_CTL_1 */ +#define PD67_MC1_5V_DET 0x01 /* 5v detect */ +#define PD67_MC1_MEDIA_ENA 0x01 /* 6730: Multimedia enable */ +#define PD67_MC1_VCC_3V 0x02 /* 3.3v Vcc */ +#define PD67_MC1_PULSE_MGMT 0x04 +#define PD67_MC1_PULSE_IRQ 0x08 +#define PD67_MC1_SPKR_ENA 0x10 +#define PD67_MC1_INPACK_ENA 0x80 + +/* Flags for PD67_FIFO_CTL */ +#define PD67_FIFO_EMPTY 0x80 + +/* Flags for PD67_MISC_CTL_2 */ +#define PD67_MC2_FREQ_BYPASS 0x01 +#define PD67_MC2_DYNAMIC_MODE 0x02 +#define PD67_MC2_SUSPEND 0x04 +#define PD67_MC2_5V_CORE 0x08 +#define PD67_MC2_LED_ENA 0x10 /* IRQ 12 is LED enable */ +#define PD67_MC2_FAST_PCI 0x10 /* 6729: PCI bus > 25 MHz */ +#define PD67_MC2_3STATE_BIT7 0x20 /* Floppy change bit */ +#define PD67_MC2_DMA_MODE 0x40 +#define PD67_MC2_IRQ15_RI 0x80 /* IRQ 15 is ring enable */ + +/* Flags for PD67_CHIP_INFO */ +#define PD67_INFO_SLOTS 0x20 /* 0 = 1 slot, 1 = 2 slots */ +#define PD67_INFO_CHIP_ID 0xc0 +#define PD67_INFO_REV 0x1c + +/* Fields in PD67_TIME_* registers */ +#define PD67_TIME_SCALE 0xc0 +#define PD67_TIME_SCALE_1 0x00 +#define PD67_TIME_SCALE_16 0x40 +#define PD67_TIME_SCALE_256 0x80 +#define PD67_TIME_SCALE_4096 0xc0 +#define PD67_TIME_MULT 0x3f + +/* Fields in PD67_DMA_CTL */ +#define PD67_DMA_MODE 0xc0 +#define PD67_DMA_OFF 0x00 +#define PD67_DMA_DREQ_INPACK 0x40 +#define PD67_DMA_DREQ_WP 0x80 +#define PD67_DMA_DREQ_BVD2 0xc0 +#define PD67_DMA_PULLUP 0x20 /* Disable socket pullups? */ + +/* Fields in PD67_EXT_CTL_1 */ +#define PD67_EC1_VCC_PWR_LOCK 0x01 +#define PD67_EC1_AUTO_PWR_CLEAR 0x02 +#define PD67_EC1_LED_ENA 0x04 +#define PD67_EC1_INV_CARD_IRQ 0x08 +#define PD67_EC1_INV_MGMT_IRQ 0x10 +#define PD67_EC1_PULLUP_CTL 0x20 + +/* Fields in PD67_MISC_CTL_3 */ +#define PD67_MC3_IRQ_MASK 0x03 +#define PD67_MC3_IRQ_PCPCI 0x00 +#define PD67_MC3_IRQ_EXTERN 0x01 +#define PD67_MC3_IRQ_PCIWAY 0x02 +#define PD67_MC3_IRQ_PCI 0x03 +#define PD67_MC3_PWR_MASK 0x0c +#define PD67_MC3_PWR_SERIAL 0x00 +#define PD67_MC3_PWR_TI2202 0x08 +#define PD67_MC3_PWR_SMB 0x0c + +/* Register definitions for Cirrus PD6832 PCI-to-CardBus bridge */ + +/* PD6832 extension registers -- indexed in PD67_EXT_INDEX */ +#define PD68_EXT_CTL_2 0x0b +#define PD68_PCI_SPACE 0x22 +#define PD68_PCCARD_SPACE 0x23 +#define PD68_WINDOW_TYPE 0x24 +#define PD68_EXT_CSC 0x2e +#define PD68_MISC_CTL_4 0x2f +#define PD68_MISC_CTL_5 0x30 +#define PD68_MISC_CTL_6 0x31 + +/* Extra flags in PD67_MISC_CTL_3 */ +#define PD68_MC3_HW_SUSP 0x10 +#define PD68_MC3_MM_EXPAND 0x40 +#define PD68_MC3_MM_ARM 0x80 + +/* Bridge Control Register */ +#define PD6832_BCR_MGMT_IRQ_ENA 0x0800 + +/* Socket Number Register */ +#define PD6832_SOCKET_NUMBER 0x004c /* 8 bit */ + +#endif /* _LINUX_CIRRUS_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cistpl.c linux/drivers/pcmcia/cistpl.c --- v2.3.16/linux/drivers/pcmcia/cistpl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/cistpl.c Tue Sep 7 11:03:10 1999 @@ -0,0 +1,1394 @@ +/*====================================================================== + + PCMCIA Card Information Structure parser + + cistpl.c 1.70 1999/09/07 15:18:58 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#define __NO_VERSION__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" +#include "rsrc_mgr.h" + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +static const u_char mantissa[] = { + 10, 12, 13, 15, 20, 25, 30, 35, + 40, 45, 50, 55, 60, 70, 80, 90 +}; + +static const u_int exponent[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 +}; + +/* Convert an extended speed byte to a time in nanoseconds */ +#define SPEED_CVT(v) \ + (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10) +/* Convert a power byte to a current in 0.1 microamps */ +#define POWER_CVT(v) \ + (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10) +#define POWER_SCALE(v) (exponent[(v)&7]) + +/* Upper limit on reasonable # of tuples */ +#define MAX_TUPLES 200 + +/*====================================================================== + + Low-level functions to read and write CIS memory. I think the + write routine is only useful for writing one-byte registers. + +======================================================================*/ + +void read_cis_mem(socket_info_t *s, int attr, u_int addr, + u_int len, void *ptr) +{ + pccard_mem_map *mem = &s->cis_mem; + u_char *sys; + u_int inc = 1; + + DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len); + if (setup_cis_mem(s) != 0) { + memset(ptr, 0xff, len); + return; + } + mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB; + if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } + sys = s->cis_virt + (addr & (s->cap.map_size-1)); + mem->card_start = addr & ~(s->cap.map_size-1); + + for (; len > 0; sys = s->cis_virt) { + s->ss_entry(s->sock, SS_SetMemMap, mem); + DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x %#2.2x ...\n", + bus_readb(s->cap.bus, sys), + bus_readb(s->cap.bus, sys+inc), + bus_readb(s->cap.bus, sys+2*inc), + bus_readb(s->cap.bus, sys+3*inc), + bus_readb(s->cap.bus, sys+4*inc)); + for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) { + if (sys == s->cis_virt+s->cap.map_size) break; + *(u_char *)ptr = bus_readb(s->cap.bus, sys); + } + mem->card_start += s->cap.map_size; + } +} + +void write_cis_mem(socket_info_t *s, int attr, u_int addr, + u_int len, void *ptr) +{ + pccard_mem_map *mem = &s->cis_mem; + u_char *sys; + int inc = 1; + + DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len); + if (setup_cis_mem(s) != 0) return; + mem->flags &= ~MAP_ATTRIB; + if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } + sys = s->cis_virt + (addr & (s->cap.map_size-1)); + mem->card_start = addr & ~(s->cap.map_size-1); + + for (; len > 0; sys = s->cis_virt) { + s->ss_entry(s->sock, SS_SetMemMap, mem); + for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) { + if (sys == s->cis_virt+s->cap.map_size) break; + bus_writeb(s->cap.bus, *(u_char *)ptr, sys); + } + mem->card_start += s->cap.map_size; + } +} + +/*====================================================================== + + This is tricky... when we set up CIS memory, we try to validate + the memory window space allocations. + +======================================================================*/ + +/* Scratch pointer to the socket we use for validation */ +static socket_info_t *vs = NULL; + +/* Validation function for cards with a valid CIS */ +static int cis_readable(u_long base) +{ + cisinfo_t info1, info2; + int ret; + vs->cis_mem.sys_start = base; + vs->cis_mem.sys_stop = base+vs->cap.map_size-1; + vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size); + ret = validate_cis(vs->clients, &info1); + /* invalidate mapping and CIS cache */ + bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0; + if ((ret != 0) || (info1.Chains == 0)) + return 0; + vs->cis_mem.sys_start = base+vs->cap.map_size; + vs->cis_mem.sys_stop = base+2*vs->cap.map_size-1; + vs->cis_virt = bus_ioremap(vs->cap.bus, base+vs->cap.map_size, + vs->cap.map_size); + ret = validate_cis(vs->clients, &info2); + bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0; + return ((ret == 0) && (info1.Chains == info2.Chains)); +} + +/* Validation function for simple memory cards */ +static int checksum(u_long base) +{ + int i, a, b, d; + vs->cis_mem.sys_start = base; + vs->cis_mem.sys_stop = base+vs->cap.map_size-1; + vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size); + vs->cis_mem.card_start = 0; + vs->cis_mem.flags = MAP_ACTIVE; + vs->ss_entry(vs->sock, SS_SetMemMap, &vs->cis_mem); + /* Don't bother checking every word... */ + a = 0; b = -1; + for (i = 0; i < vs->cap.map_size; i += 44) { + d = bus_readl(vs->cap.bus, vs->cis_virt+i); + a += d; b &= d; + } + bus_iounmap(vs->cap.bus, vs->cis_virt); + return (b == -1) ? -1 : (a>>1); +} + +static int checksum_match(u_long base) +{ + int a = checksum(base), b = checksum(base+vs->cap.map_size); + return ((a == b) && (a >= 0)); +} + +int setup_cis_mem(socket_info_t *s) +{ + if (s->cis_mem.sys_start == 0) { + int low = !(s->cap.features & SS_CAP_PAGE_REGS); + vs = s; + validate_mem(cis_readable, checksum_match, low); + s->cis_mem.sys_start = 0; + vs = NULL; + if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size, + "card services", s->cap.map_size, low)) { + printk(KERN_NOTICE "cs: unable to map card memory!\n"); + return CS_OUT_OF_RESOURCE; + } + s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1; + s->cis_mem.flags |= MAP_ACTIVE; + s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start, + s->cap.map_size); + } + return 0; +} + +void release_cis_mem(socket_info_t *s) +{ + if (s->cis_mem.sys_start != 0) { + s->cis_mem.flags &= ~MAP_ACTIVE; + s->ss_entry(s->sock, SS_SetMemMap, &s->cis_mem); + release_mem_region(s->cis_mem.sys_start, s->cap.map_size); + bus_iounmap(s->cap.bus, s->cis_virt); + s->cis_mem.sys_start = 0; + } +} + +/*====================================================================== + + This is a wrapper around read_cis_mem, with the same interface, + but which caches information, for cards whose CIS may not be + readable all the time. + +======================================================================*/ + +static void read_cis_cache(socket_info_t *s, int attr, u_int addr, + u_int len, void *ptr) +{ + int i; + char *caddr; + + if (s->fake_cis) { + if (s->fake_cis_len > addr+len) + memcpy(ptr, s->fake_cis+addr, len); + else + memset(ptr, 0xff, len); + return; + } + caddr = s->cis_cache; + for (i = 0; i < s->cis_used; i++) { + if ((s->cis_table[i].addr == addr) && + (s->cis_table[i].len == len) && + (s->cis_table[i].attr == attr)) break; + caddr += s->cis_table[i].len; + } + if (i < s->cis_used) { + memcpy(ptr, caddr, len); + return; + } +#ifdef CONFIG_CARDBUS + if (s->state & SOCKET_CARDBUS) + read_cb_mem(s, 0, attr, addr, len, ptr); + else +#endif + read_cis_mem(s, attr, addr, len, ptr); + /* Copy data into the cache, if there is room */ + if ((i < MAX_CIS_TABLE) && + (caddr+len < s->cis_cache+MAX_CIS_DATA)) { + s->cis_table[i].addr = addr; + s->cis_table[i].len = len; + s->cis_table[i].attr = attr; + s->cis_used++; + memcpy(caddr, ptr, len); + } +} + +/*====================================================================== + + This verifies if the CIS of a card matches what is in the CIS + cache. + +======================================================================*/ + +int verify_cis_cache(socket_info_t *s) +{ + char buf[256], *caddr; + int i; + + caddr = s->cis_cache; + for (i = 0; i < s->cis_used; i++) { +#ifdef CONFIG_CARDBUS + if (s->state & SOCKET_CARDBUS) + read_cb_mem(s, 0, s->cis_table[i].attr, s->cis_table[i].addr, + s->cis_table[i].len, buf); + else +#endif + read_cis_mem(s, s->cis_table[i].attr, s->cis_table[i].addr, + s->cis_table[i].len, buf); + if (memcmp(buf, caddr, s->cis_table[i].len) != 0) + break; + caddr += s->cis_table[i].len; + } + return (i < s->cis_used); +} + +/*====================================================================== + + For really bad cards, we provide a facility for uploading a + replacement CIS. + +======================================================================*/ + +int replace_cis(client_handle_t handle, cisdump_t *cis) +{ + socket_info_t *s; + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); + if (s->fake_cis != NULL) { + kfree(s->fake_cis); + s->fake_cis = NULL; + } + if (cis->Length > CISTPL_MAX_CIS_SIZE) + return CS_BAD_SIZE; + s->fake_cis = kmalloc(cis->Length, GFP_KERNEL); + if (s->fake_cis == NULL) + return CS_OUT_OF_RESOURCE; + s->fake_cis_len = cis->Length; + memcpy(s->fake_cis, cis->Data, cis->Length); + return CS_SUCCESS; +} + +/*====================================================================== + + The high-level CIS tuple services + +======================================================================*/ + +typedef struct tuple_flags { + u_int link_space:3; + u_int has_link:1; + u_int mfc_fn:3; + u_int space:3; +} tuple_flags; + +#define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space) +#define HAS_LINK(f) (((tuple_flags *)(&(f)))->has_link) +#define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn) +#define SPACE(f) (((tuple_flags *)(&(f)))->space) + +int get_next_tuple(client_handle_t handle, tuple_t *tuple); + +int get_first_tuple(client_handle_t handle, tuple_t *tuple) +{ + socket_info_t *s; + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + tuple->TupleLink = tuple->Flags = 0; +#ifdef CONFIG_CARDBUS + if (s->state & SOCKET_CARDBUS) { + u_int ptr; + pcibios_read_config_dword(s->cap.cardbus, 0, 0x28, &ptr); + tuple->CISOffset = ptr & ~7; + SPACE(tuple->Flags) = (ptr & 7); + } else +#endif + { + /* Assume presence of a LONGLINK_C to address 0 */ + tuple->CISOffset = tuple->LinkOffset = 0; + SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; + } + if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) && + !(tuple->Attributes & TUPLE_RETURN_COMMON)) { + cisdata_t req = tuple->DesiredTuple; + tuple->DesiredTuple = CISTPL_LONGLINK_MFC; + if (get_next_tuple(handle, tuple) == CS_SUCCESS) { + tuple->DesiredTuple = CISTPL_LINKTARGET; + if (get_next_tuple(handle, tuple) != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + } else + tuple->CISOffset = tuple->TupleLink = 0; + tuple->DesiredTuple = req; + } + return get_next_tuple(handle, tuple); +} + +static int follow_link(socket_info_t *s, tuple_t *tuple) +{ + u_char link[5]; + u_int ofs; + + if (MFC_FN(tuple->Flags)) { + /* Get indirect link from the MFC tuple */ + read_cis_cache(s, LINK_SPACE(tuple->Flags), + tuple->LinkOffset, 5, link); + ofs = le32_to_cpu(*(u_int *)(link+1)); + SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); + /* Move to the next indirect link */ + tuple->LinkOffset += 5; + MFC_FN(tuple->Flags)--; + } else if (HAS_LINK(tuple->Flags)) { + ofs = tuple->LinkOffset; + SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags); + HAS_LINK(tuple->Flags) = 0; + } else { + return -1; + } + if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) { + /* This is ugly, but a common CIS error is to code the long + link offset incorrectly, so we check the right spot... */ + read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); + if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && + (strncmp(link+2, "CIS", 3) == 0)) + return ofs; + /* Then, we try the wrong spot... */ + ofs = ofs >> 1; + } + read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); + if ((link[0] != CISTPL_LINKTARGET) || (link[1] < 3) || + (strncmp(link+2, "CIS", 3) != 0)) + return -1; + return ofs; +} + +int get_next_tuple(client_handle_t handle, tuple_t *tuple) +{ + socket_info_t *s; + u_char link[2], tmp; + int ofs, i, attr; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + + link[1] = tuple->TupleLink; + ofs = tuple->CISOffset + tuple->TupleLink; + attr = SPACE(tuple->Flags); + + for (i = 0; i < MAX_TUPLES; i++) { + if (link[1] == 0xff) { + link[0] = CISTPL_END; + } else { + read_cis_cache(s, attr, ofs, 2, link); + if (link[0] == CISTPL_NULL) { + ofs++; continue; + } + } + + /* End of chain? Follow long link if possible */ + if (link[0] == CISTPL_END) { + if ((ofs = follow_link(s, tuple)) < 0) + return CS_NO_MORE_ITEMS; + attr = SPACE(tuple->Flags); + read_cis_cache(s, attr, ofs, 2, link); + } + + /* Is this a link tuple? Make a note of it */ + if ((link[0] == CISTPL_LONGLINK_A) || + (link[0] == CISTPL_LONGLINK_C) || + (link[0] == CISTPL_LONGLINK_MFC) || + (link[0] == CISTPL_LINKTARGET) || + (link[0] == CISTPL_NO_LINK)) { + switch (link[0]) { + case CISTPL_LONGLINK_A: + HAS_LINK(tuple->Flags) = 1; + LINK_SPACE(tuple->Flags) = 1; + read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); + break; + case CISTPL_LONGLINK_C: + HAS_LINK(tuple->Flags) = 1; + LINK_SPACE(tuple->Flags) = 0; + read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); + break; + case CISTPL_LONGLINK_MFC: + tuple->LinkOffset = ofs + 3; + LINK_SPACE(tuple->Flags) = attr; + if (handle->Function == BIND_FN_ALL) { + /* Follow all the MFC links */ + read_cis_cache(s, attr, ofs+2, 1, &tmp); + MFC_FN(tuple->Flags) = tmp; + } else { + /* Follow exactly one of the links */ + MFC_FN(tuple->Flags) = 1; + tuple->LinkOffset += handle->Function * 5; + } + break; + case CISTPL_NO_LINK: + HAS_LINK(tuple->Flags) = 0; + break; + } + if ((tuple->Attributes & TUPLE_RETURN_LINK) && + (tuple->DesiredTuple == RETURN_FIRST_TUPLE)) + break; + } else + if (tuple->DesiredTuple == RETURN_FIRST_TUPLE) + break; + + if (link[0] == tuple->DesiredTuple) + break; + ofs += link[1] + 2; + } + if (i == MAX_TUPLES) { + DEBUG(1, "cs: overrun in get_next_tuple for socket %d\n", + handle->Socket); + return CS_NO_MORE_ITEMS; + } + + tuple->TupleCode = link[0]; + tuple->TupleLink = link[1]; + tuple->CISOffset = ofs + 2; + return CS_SUCCESS; +} + +/*====================================================================*/ + +int get_tuple_data(client_handle_t handle, tuple_t *tuple) +{ + socket_info_t *s; + u_int len; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + + s = SOCKET(handle); + + if (tuple->TupleLink < tuple->TupleOffset) + return CS_NO_MORE_ITEMS; + len = tuple->TupleLink - tuple->TupleOffset; + tuple->TupleDataLen = tuple->TupleLink; + if (len == 0) + return CS_SUCCESS; + read_cis_cache(s, SPACE(tuple->Flags), + tuple->CISOffset + tuple->TupleOffset, + MIN(len, tuple->TupleDataMax), tuple->TupleData); + return CS_SUCCESS; +} + +/*====================================================================== + + Parsing routines for individual tuples + +======================================================================*/ + +static int parse_device(tuple_t *tuple, cistpl_device_t *device) +{ + int i; + u_char scale; + u_char *p, *q; + + p = (u_char *)tuple->TupleData; + q = p + tuple->TupleDataLen; + + device->ndev = 0; + for (i = 0; i < CISTPL_MAX_DEVICES; i++) { + + if (*p == 0xff) break; + device->dev[i].type = (*p >> 4); + device->dev[i].wp = (*p & 0x08) ? 1 : 0; + switch (*p & 0x07) { + case 0: device->dev[i].speed = 0; break; + case 1: device->dev[i].speed = 250; break; + case 2: device->dev[i].speed = 200; break; + case 3: device->dev[i].speed = 150; break; + case 4: device->dev[i].speed = 100; break; + case 7: + if (++p == q) return CS_BAD_TUPLE; + if (p == q) + return CS_BAD_TUPLE; + device->dev[i].speed = SPEED_CVT(*p); + while (*p & 0x80) + if (++p == q) return CS_BAD_TUPLE; + break; + default: + return CS_BAD_TUPLE; + } + + if (++p == q) return CS_BAD_TUPLE; + if (*p == 0xff) break; + scale = *p & 7; + if (scale == 7) return CS_BAD_TUPLE; + device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2)); + device->ndev++; + if (++p == q) break; + } + + return CS_SUCCESS; +} + +/*====================================================================*/ + +static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) +{ + u_char *p; + if (tuple->TupleDataLen < 5) + return CS_BAD_TUPLE; + p = (u_char *)tuple->TupleData; + csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2; + csum->len = le16_to_cpu(*(u_short *)(p + 2)); + csum->sum = *(p+4); + return CS_SUCCESS; +} + +/*====================================================================*/ + +static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) +{ + if (tuple->TupleDataLen < 4) + return CS_BAD_TUPLE; + link->addr = le32_to_cpu(*(u_int *)tuple->TupleData); + return CS_SUCCESS; +} + +/*====================================================================*/ + +static int parse_longlink_mfc(tuple_t *tuple, + cistpl_longlink_mfc_t *link) +{ + u_char *p; + int i; + + p = (u_char *)tuple->TupleData; + + link->nfn = *p; p++; + if (tuple->TupleDataLen <= link->nfn*5) + return CS_BAD_TUPLE; + for (i = 0; i < link->nfn; i++) { + link->fn[i].space = *p; p++; + link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4; + } + return CS_SUCCESS; +} + +/*====================================================================*/ + +static int parse_strings(u_char *p, u_char *q, int max, + char *s, u_char *ofs, u_char *found) +{ + int i, j, ns; + + if (p == q) return CS_BAD_TUPLE; + ns = 0; j = 0; + for (i = 0; i < max; i++) { + if (*p == 0xff) break; + ofs[i] = j; + ns++; + for (;;) { + s[j++] = (*p == 0xff) ? '\0' : *p; + if ((*p == '\0') || (*p == 0xff)) break; + if (++p == q) return CS_BAD_TUPLE; + } + if ((*p == 0xff) || (++p == q)) break; + } + if (found) { + *found = ns; + return CS_SUCCESS; + } else { + return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE; + } +} + +/*====================================================================*/ + +static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1) +{ + u_char *p, *q; + + p = (u_char *)tuple->TupleData; + q = p + tuple->TupleDataLen; + + vers_1->major = *p; p++; + vers_1->minor = *p; p++; + if (p >= q) return CS_BAD_TUPLE; + + return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS, + vers_1->str, vers_1->ofs, &vers_1->ns); +} + +/*====================================================================*/ + +static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr) +{ + u_char *p, *q; + + p = (u_char *)tuple->TupleData; + q = p + tuple->TupleDataLen; + + return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS, + altstr->str, altstr->ofs, &altstr->ns); +} + +/*====================================================================*/ + +static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec) +{ + u_char *p, *q; + int nid; + + p = (u_char *)tuple->TupleData; + q = p + tuple->TupleDataLen; + + for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) { + if (p > q-2) break; + jedec->id[nid].mfr = p[0]; + jedec->id[nid].info = p[1]; + p += 2; + } + jedec->nid = nid; + return CS_SUCCESS; +} + +/*====================================================================*/ + +static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) +{ + u_short *p; + if (tuple->TupleDataLen < 4) + return CS_BAD_TUPLE; + p = (u_short *)tuple->TupleData; + m->manf = le16_to_cpu(p[0]); + m->card = le16_to_cpu(p[1]); + return CS_SUCCESS; +} + +/*====================================================================*/ + +static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f) +{ + u_char *p; + if (tuple->TupleDataLen < 2) + return CS_BAD_TUPLE; + p = (u_char *)tuple->TupleData; + f->func = p[0]; + f->sysinit = p[1]; + return CS_SUCCESS; +} + +/*====================================================================*/ + +static int parse_funce(tuple_t *tuple, cistpl_funce_t *f) +{ + u_char *p; + int i; + if (tuple->TupleDataLen < 1) + return CS_BAD_TUPLE; + p = (u_char *)tuple->TupleData; + f->type = p[0]; + for (i = 1; i < tuple->TupleDataLen; i++) + f->data[i-1] = p[i]; + return CS_SUCCESS; +} + +/*====================================================================*/ + +static int parse_config(tuple_t *tuple, cistpl_config_t *config) +{ + int rasz, rmsz, i; + u_char *p; + + p = (u_char *)tuple->TupleData; + rasz = *p & 0x03; + rmsz = (*p & 0x3c) >> 2; + if (tuple->TupleDataLen < rasz+rmsz+4) + return CS_BAD_TUPLE; + config->last_idx = *(++p); + p++; + config->base = 0; + for (i = 0; i <= rasz; i++) + config->base += p[i] << (8*i); + p += rasz+1; + for (i = 0; i < 4; i++) + config->rmask[i] = 0; + for (i = 0; i <= rmsz; i++) + config->rmask[i>>2] += p[i] << (8*(i%4)); + config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4); + return CS_SUCCESS; +} + +/*====================================================================== + + The following routines are all used to parse the nightmarish + config table entries. + +======================================================================*/ + +static u_char *parse_power(u_char *p, u_char *q, + cistpl_power_t *pwr) +{ + int i; + u_int scale; + + if (p == q) return NULL; + pwr->present = *p; + pwr->flags = 0; + p++; + for (i = 0; i < 7; i++) + if (pwr->present & (1<param[i] = POWER_CVT(*p); + scale = POWER_SCALE(*p); + while (*p & 0x80) { + if (++p == q) return NULL; + if ((*p & 0x7f) < 100) + pwr->param[i] += (*p & 0x7f) * scale / 100; + else if (*p == 0x7d) + pwr->flags |= CISTPL_POWER_HIGHZ_OK; + else if (*p == 0x7e) + pwr->param[i] = 0; + else if (*p == 0x7f) + pwr->flags |= CISTPL_POWER_HIGHZ_REQ; + else + return NULL; + } + p++; + } + return p; +} + +/*====================================================================*/ + +static u_char *parse_timing(u_char *p, u_char *q, + cistpl_timing_t *timing) +{ + u_char scale; + + if (p == q) return NULL; + scale = *p; + if ((scale & 3) != 3) { + if (++p == q) return NULL; + timing->wait = SPEED_CVT(*p); + timing->waitscale = exponent[scale & 3]; + } else + timing->wait = 0; + scale >>= 2; + if ((scale & 7) != 7) { + if (++p == q) return NULL; + timing->ready = SPEED_CVT(*p); + timing->rdyscale = exponent[scale & 7]; + } else + timing->ready = 0; + scale >>= 3; + if (scale != 7) { + if (++p == q) return NULL; + timing->reserved = SPEED_CVT(*p); + timing->rsvscale = exponent[scale]; + } else + timing->reserved = 0; + p++; + return p; +} + +/*====================================================================*/ + +static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io) +{ + int i, j, bsz, lsz; + + if (p == q) return NULL; + io->flags = *p; + + if (!(*p & 0x80)) { + io->nwin = 1; + io->win[0].base = 0; + io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK)); + return p+1; + } + + if (++p == q) return NULL; + io->nwin = (*p & 0x0f) + 1; + bsz = (*p & 0x30) >> 4; + if (bsz == 3) bsz++; + lsz = (*p & 0xc0) >> 6; + if (lsz == 3) lsz++; + p++; + + for (i = 0; i < io->nwin; i++) { + io->win[i].base = 0; + io->win[i].len = 1; + for (j = 0; j < bsz; j++, p++) { + if (p == q) return NULL; + io->win[i].base += *p << (j*8); + } + for (j = 0; j < lsz; j++, p++) { + if (p == q) return NULL; + io->win[i].len += *p << (j*8); + } + } + return p; +} + +/*====================================================================*/ + +static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem) +{ + int i, j, asz, lsz, has_ha; + u_int len, ca, ha; + + if (p == q) return NULL; + + mem->nwin = (*p & 0x07) + 1; + lsz = (*p & 0x18) >> 3; + asz = (*p & 0x60) >> 5; + has_ha = (*p & 0x80); + if (++p == q) return NULL; + + for (i = 0; i < mem->nwin; i++) { + len = ca = ha = 0; + for (j = 0; j < lsz; j++, p++) { + if (p == q) return NULL; + len += *p << (j*8); + } + for (j = 0; j < asz; j++, p++) { + if (p == q) return NULL; + ca += *p << (j*8); + } + if (has_ha) + for (j = 0; j < asz; j++, p++) { + if (p == q) return NULL; + ha += *p << (j*8); + } + mem->win[i].len = len << 8; + mem->win[i].card_addr = ca << 8; + mem->win[i].host_addr = ha << 8; + } + return p; +} + +/*====================================================================*/ + +static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq) +{ + if (p == q) return NULL; + irq->IRQInfo1 = *p; p++; + if (irq->IRQInfo1 & IRQ_INFO2_VALID) { + if (p+2 > q) return NULL; + irq->IRQInfo2 = (p[1]<<8) + p[0]; + p += 2; + } + return p; +} + +/*====================================================================*/ + +static int parse_cftable_entry(tuple_t *tuple, + cistpl_cftable_entry_t *entry) +{ + u_char *p, *q, features; + + p = tuple->TupleData; + q = p + tuple->TupleDataLen; + entry->index = *p & 0x3f; + entry->flags = 0; + if (*p & 0x40) + entry->flags |= CISTPL_CFTABLE_DEFAULT; + if (*p & 0x80) { + if (++p == q) return CS_BAD_TUPLE; + if (*p & 0x10) + entry->flags |= CISTPL_CFTABLE_BVDS; + if (*p & 0x20) + entry->flags |= CISTPL_CFTABLE_WP; + if (*p & 0x40) + entry->flags |= CISTPL_CFTABLE_RDYBSY; + if (*p & 0x80) + entry->flags |= CISTPL_CFTABLE_MWAIT; + entry->interface = *p & 0x0f; + } else + entry->interface = 0; + + /* Process optional features */ + if (++p == q) return CS_BAD_TUPLE; + features = *p; p++; + + /* Power options */ + if ((features & 3) > 0) { + p = parse_power(p, q, &entry->vcc); + if (p == NULL) return CS_BAD_TUPLE; + } else + entry->vcc.present = 0; + if ((features & 3) > 1) { + p = parse_power(p, q, &entry->vpp1); + if (p == NULL) return CS_BAD_TUPLE; + } else + entry->vpp1.present = 0; + if ((features & 3) > 2) { + p = parse_power(p, q, &entry->vpp2); + if (p == NULL) return CS_BAD_TUPLE; + } else + entry->vpp2.present = 0; + + /* Timing options */ + if (features & 0x04) { + p = parse_timing(p, q, &entry->timing); + if (p == NULL) return CS_BAD_TUPLE; + } else { + entry->timing.wait = 0; + entry->timing.ready = 0; + entry->timing.reserved = 0; + } + + /* I/O window options */ + if (features & 0x08) { + p = parse_io(p, q, &entry->io); + if (p == NULL) return CS_BAD_TUPLE; + } else + entry->io.nwin = 0; + + /* Interrupt options */ + if (features & 0x10) { + p = parse_irq(p, q, &entry->irq); + if (p == NULL) return CS_BAD_TUPLE; + } else + entry->irq.IRQInfo1 = 0; + + switch (features & 0x60) { + case 0x00: + entry->mem.nwin = 0; + break; + case 0x20: + entry->mem.nwin = 1; + entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8; + entry->mem.win[0].card_addr = 0; + entry->mem.win[0].host_addr = 0; + p += 2; + if (p > q) return CS_BAD_TUPLE; + break; + case 0x40: + entry->mem.nwin = 1; + entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8; + entry->mem.win[0].card_addr = + le16_to_cpu(*(u_short *)(p+2)) << 8; + entry->mem.win[0].host_addr = 0; + p += 4; + if (p > q) return CS_BAD_TUPLE; + break; + case 0x60: + p = parse_mem(p, q, &entry->mem); + if (p == NULL) return CS_BAD_TUPLE; + break; + } + + /* Misc features */ + if (features & 0x80) { + if (p == q) return CS_BAD_TUPLE; + entry->flags |= (*p << 8); + while (*p & 0x80) + if (++p == q) return CS_BAD_TUPLE; + p++; + } + + entry->subtuples = q-p; + + return CS_SUCCESS; +} + +/*====================================================================*/ + +#ifdef CONFIG_CARDBUS + +static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) +{ + u_char *p; + if (tuple->TupleDataLen < 6) + return CS_BAD_TUPLE; + p = (u_char *)tuple->TupleData; + bar->attr = *p; + p += 2; + bar->size = le32_to_cpu(*(u_int *)p); + return CS_SUCCESS; +} + +static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) +{ + u_char *p; + + p = (u_char *)tuple->TupleData; + if ((*p != 3) || (tuple->TupleDataLen < 6)) + return CS_BAD_TUPLE; + config->last_idx = *(++p); + p++; + config->base = le32_to_cpu(*(u_int *)p); + config->subtuples = tuple->TupleDataLen - 6; + return CS_SUCCESS; +} + +static int parse_cftable_entry_cb(tuple_t *tuple, + cistpl_cftable_entry_cb_t *entry) +{ + u_char *p, *q, features; + + p = tuple->TupleData; + q = p + tuple->TupleDataLen; + entry->index = *p & 0x3f; + entry->flags = 0; + if (*p & 0x40) + entry->flags |= CISTPL_CFTABLE_DEFAULT; + + /* Process optional features */ + if (++p == q) return CS_BAD_TUPLE; + features = *p; p++; + + /* Power options */ + if ((features & 3) > 0) { + p = parse_power(p, q, &entry->vcc); + if (p == NULL) return CS_BAD_TUPLE; + } else + entry->vcc.present = 0; + if ((features & 3) > 1) { + p = parse_power(p, q, &entry->vpp1); + if (p == NULL) return CS_BAD_TUPLE; + } else + entry->vpp1.present = 0; + if ((features & 3) > 2) { + p = parse_power(p, q, &entry->vpp2); + if (p == NULL) return CS_BAD_TUPLE; + } else + entry->vpp2.present = 0; + + /* I/O window options */ + if (features & 0x08) { + if (p == q) return CS_BAD_TUPLE; + entry->io = *p; p++; + } else + entry->io = 0; + + /* Interrupt options */ + if (features & 0x10) { + p = parse_irq(p, q, &entry->irq); + if (p == NULL) return CS_BAD_TUPLE; + } else + entry->irq.IRQInfo1 = 0; + + if (features & 0x20) { + if (p == q) return CS_BAD_TUPLE; + entry->mem = *p; p++; + } else + entry->mem = 0; + + /* Misc features */ + if (features & 0x80) { + if (p == q) return CS_BAD_TUPLE; + entry->flags |= (*p << 8); + if (*p & 0x80) { + if (++p == q) return CS_BAD_TUPLE; + entry->flags |= (*p << 16); + } + while (*p & 0x80) + if (++p == q) return CS_BAD_TUPLE; + p++; + } + + entry->subtuples = q-p; + + return CS_SUCCESS; +} + +#endif + +/*====================================================================*/ + +static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo) +{ + u_char *p, *q; + int n; + + p = (u_char *)tuple->TupleData; + q = p + tuple->TupleDataLen; + + for (n = 0; n < CISTPL_MAX_DEVICES; n++) { + if (p > q-6) break; + geo->geo[n].buswidth = p[0]; + geo->geo[n].erase_block = 1 << (p[1]-1); + geo->geo[n].read_block = 1 << (p[2]-1); + geo->geo[n].write_block = 1 << (p[3]-1); + geo->geo[n].partition = 1 << (p[4]-1); + geo->geo[n].interleave = 1 << (p[5]-1); + p += 6; + } + geo->ngeo = n; + return CS_SUCCESS; +} + +/*====================================================================*/ + +static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) +{ + u_char *p, *q; + + if (tuple->TupleDataLen < 10) + return CS_BAD_TUPLE; + + p = tuple->TupleData; + q = p + tuple->TupleDataLen; + + v2->vers = p[0]; + v2->comply = p[1]; + v2->dindex = le16_to_cpu(*(u_short *)(p+2)); + v2->vspec8 = p[6]; + v2->vspec9 = p[7]; + v2->nhdr = p[8]; + p += 9; + return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL); +} + +/*====================================================================*/ + +static int parse_org(tuple_t *tuple, cistpl_org_t *org) +{ + u_char *p, *q; + int i; + + p = tuple->TupleData; + q = p + tuple->TupleDataLen; + if (p == q) return CS_BAD_TUPLE; + org->data_org = *p; + if (++p == q) return CS_BAD_TUPLE; + for (i = 0; i < 30; i++) { + org->desc[i] = *p; + if (*p == '\0') break; + if (++p == q) return CS_BAD_TUPLE; + } + return CS_SUCCESS; +} + +/*====================================================================*/ + +int parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + int ret = CS_SUCCESS; + + if (tuple->TupleDataLen > tuple->TupleDataMax) + return CS_BAD_TUPLE; + switch (tuple->TupleCode) { + case CISTPL_DEVICE: + case CISTPL_DEVICE_A: + ret = parse_device(tuple, &parse->device); + break; +#ifdef CONFIG_CARDBUS + case CISTPL_BAR: + ret = parse_bar(tuple, &parse->bar); + break; + case CISTPL_CONFIG_CB: + ret = parse_config_cb(tuple, &parse->config); + break; + case CISTPL_CFTABLE_ENTRY_CB: + ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb); + break; +#endif + case CISTPL_CHECKSUM: + ret = parse_checksum(tuple, &parse->checksum); + break; + case CISTPL_LONGLINK_A: + case CISTPL_LONGLINK_C: + ret = parse_longlink(tuple, &parse->longlink); + break; + case CISTPL_LONGLINK_MFC: + ret = parse_longlink_mfc(tuple, &parse->longlink_mfc); + break; + case CISTPL_VERS_1: + ret = parse_vers_1(tuple, &parse->version_1); + break; + case CISTPL_ALTSTR: + ret = parse_altstr(tuple, &parse->altstr); + break; + case CISTPL_JEDEC_A: + case CISTPL_JEDEC_C: + ret = parse_jedec(tuple, &parse->jedec); + break; + case CISTPL_MANFID: + ret = parse_manfid(tuple, &parse->manfid); + break; + case CISTPL_FUNCID: + ret = parse_funcid(tuple, &parse->funcid); + break; + case CISTPL_FUNCE: + ret = parse_funce(tuple, &parse->funce); + break; + case CISTPL_CONFIG: + ret = parse_config(tuple, &parse->config); + break; + case CISTPL_CFTABLE_ENTRY: + ret = parse_cftable_entry(tuple, &parse->cftable_entry); + break; + case CISTPL_DEVICE_GEO: + case CISTPL_DEVICE_GEO_A: + ret = parse_device_geo(tuple, &parse->device_geo); + break; + case CISTPL_VERS_2: + ret = parse_vers_2(tuple, &parse->vers_2); + break; + case CISTPL_ORG: + ret = parse_org(tuple, &parse->org); + break; + case CISTPL_NO_LINK: + case CISTPL_LINKTARGET: + ret = CS_SUCCESS; + break; + default: + ret = CS_UNSUPPORTED_FUNCTION; + break; + } + return ret; +} + +/*====================================================================== + + This is used internally by Card Services to look up CIS stuff. + +======================================================================*/ + +int read_tuple(client_handle_t handle, cisdata_t code, void *parse) +{ + tuple_t tuple; + cisdata_t buf[255]; + int ret; + + tuple.DesiredTuple = code; + tuple.Attributes = TUPLE_RETURN_COMMON; + ret = CardServices(GetFirstTuple, handle, &tuple, NULL); + if (ret != CS_SUCCESS) return ret; + tuple.TupleData = buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = sizeof(buf); + ret = CardServices(GetTupleData, handle, &tuple, NULL); + if (ret != CS_SUCCESS) return ret; + ret = CardServices(ParseTuple, handle, &tuple, parse); + return ret; +} + +/*====================================================================== + + This tries to determine if a card has a sensible CIS. It returns + the number of tuples in the CIS, or 0 if the CIS looks bad. The + checks include making sure several critical tuples are present and + valid; seeing if the total number of tuples is reasonable; and + looking for tuples that use reserved codes. + +======================================================================*/ + +int validate_cis(client_handle_t handle, cisinfo_t *info) +{ + tuple_t tuple; + cisparse_t p; + int ret, reserved, errors; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + + info->Chains = reserved = errors = 0; + tuple.DesiredTuple = RETURN_FIRST_TUPLE; + tuple.Attributes = TUPLE_RETURN_COMMON; + ret = get_first_tuple(handle, &tuple); + if (ret != CS_SUCCESS) + return CS_SUCCESS; + + /* First tuple should be DEVICE */ + if (tuple.TupleCode != CISTPL_DEVICE) + errors++; + /* All cards should have a MANFID tuple */ + if (read_tuple(handle, CISTPL_MANFID, &p) != CS_SUCCESS) + errors++; + /* All cards should have either a VERS_1 or a VERS_2 tuple. But + at worst, we'll accept a CFTABLE_ENTRY that parses. */ + if ((read_tuple(handle, CISTPL_VERS_1, &p) != CS_SUCCESS) && + (read_tuple(handle, CISTPL_VERS_2, &p) != CS_SUCCESS) && + (read_tuple(handle, CISTPL_CFTABLE_ENTRY, &p) != CS_SUCCESS) && + (read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, &p) != CS_SUCCESS)) + errors++; + if (errors > 1) + return CS_SUCCESS; + + for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) { + ret = get_next_tuple(handle, &tuple); + if (ret != CS_SUCCESS) break; + if (((tuple.TupleCode > 0x23) && (tuple.TupleCode < 0x40)) || + ((tuple.TupleCode > 0x47) && (tuple.TupleCode < 0x80)) || + ((tuple.TupleCode > 0x90) && (tuple.TupleCode < 0xff))) + reserved++; + } + if ((info->Chains == MAX_TUPLES) || (reserved > 5)) + info->Chains = 0; + + return CS_SUCCESS; +} + diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- v2.3.16/linux/drivers/pcmcia/cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/cs.c Tue Sep 7 11:03:10 1999 @@ -0,0 +1,2256 @@ +/*====================================================================== + + PCMCIA Card Services -- core services + + cs.c 1.225 1999/09/07 15:19:32 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IN_CARD_SERVICES +#include +#include +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" +#include "rsrc_mgr.h" + +#ifdef CONFIG_APM +#include +static int handle_apm_event(apm_event_t event); +#endif + +#ifdef PCMCIA_DEBUG +int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +static const char *version = +"cs.c 1.225 1999/09/07 15:19:32 (David Hinds)"; +#endif + +static const char *release = "Linux PCMCIA Card Services " CS_RELEASE; + +static const char *options = "options: " +#ifdef CONFIG_PCI +" [pci]" +#endif +#ifdef CONFIG_CARDBUS +" [cardbus]" +#endif +#ifdef CONFIG_APM +" [apm]" +#endif +#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_APM) +" none" +#endif +; + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +static int setup_delay = HZ/20; /* ticks */ +static int resume_delay = HZ/5; /* ticks */ +static int shutdown_delay = HZ/40; /* ticks */ +static int vcc_settle = HZ*3/10; /* ticks */ +static int reset_time = 10; /* usecs */ +static int unreset_delay = HZ/10; /* ticks */ +static int unreset_check = HZ/10; /* ticks */ +static int unreset_limit = 30; /* unreset_check's */ + +/* Access speed for attribute memory windows */ +static int cis_speed = 300; /* ns */ + +/* Access speed for IO windows */ +static int io_speed = 0; /* ns */ + +/* Optional features */ +#ifdef CONFIG_APM +static int do_apm = 1; +MODULE_PARM(do_apm, "i"); +#endif + +MODULE_PARM(setup_delay, "i"); +MODULE_PARM(resume_delay, "i"); +MODULE_PARM(shutdown_delay, "i"); +MODULE_PARM(vcc_settle, "i"); +MODULE_PARM(reset_time, "i"); +MODULE_PARM(unreset_delay, "i"); +MODULE_PARM(unreset_check, "i"); +MODULE_PARM(unreset_limit, "i"); +MODULE_PARM(cis_speed, "i"); +MODULE_PARM(io_speed, "i"); + +/*====================================================================*/ + +static socket_state_t dead_socket = { + 0, SS_DETECT, 0, 0, 0 +}; + +/* Table of sockets */ +socket_t sockets = 0; +socket_info_t *socket_table[MAX_SOCK]; + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *proc_pccard = NULL; +#endif + +/*====================================================================*/ + +/* String tables for error messages */ + +typedef struct lookup_t { + int key; + char *msg; +} lookup_t; + +static const lookup_t error_table[] = { + { CS_SUCCESS, "Operation succeeded" }, + { CS_BAD_ADAPTER, "Bad adapter" }, + { CS_BAD_ATTRIBUTE, "Bad attribute", }, + { CS_BAD_BASE, "Bad base address" }, + { CS_BAD_EDC, "Bad EDC" }, + { CS_BAD_IRQ, "Bad IRQ" }, + { CS_BAD_OFFSET, "Bad offset" }, + { CS_BAD_PAGE, "Bad page number" }, + { CS_READ_FAILURE, "Read failure" }, + { CS_BAD_SIZE, "Bad size" }, + { CS_BAD_SOCKET, "Bad socket" }, + { CS_BAD_TYPE, "Bad type" }, + { CS_BAD_VCC, "Bad Vcc" }, + { CS_BAD_VPP, "Bad Vpp" }, + { CS_BAD_WINDOW, "Bad window" }, + { CS_WRITE_FAILURE, "Write failure" }, + { CS_NO_CARD, "No card present" }, + { CS_UNSUPPORTED_FUNCTION, "Usupported function" }, + { CS_UNSUPPORTED_MODE, "Unsupported mode" }, + { CS_BAD_SPEED, "Bad speed" }, + { CS_BUSY, "Resource busy" }, + { CS_GENERAL_FAILURE, "General failure" }, + { CS_WRITE_PROTECTED, "Write protected" }, + { CS_BAD_ARG_LENGTH, "Bad argument length" }, + { CS_BAD_ARGS, "Bad arguments" }, + { CS_CONFIGURATION_LOCKED, "Configuration locked" }, + { CS_IN_USE, "Resource in use" }, + { CS_NO_MORE_ITEMS, "No more items" }, + { CS_OUT_OF_RESOURCE, "Out of resource" }, + { CS_BAD_HANDLE, "Bad handle" }, + { CS_BAD_TUPLE, "Bad CIS tuple" } +}; +#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t)) + +static const lookup_t service_table[] = { + { AccessConfigurationRegister, "AccessConfigurationRegister" }, + { AddSocketServices, "AddSocketServices" }, + { AdjustResourceInfo, "AdjustResourceInfo" }, + { CheckEraseQueue, "CheckEraseQueue" }, + { CloseMemory, "CloseMemory" }, + { DeregisterClient, "DeregisterClient" }, + { DeregisterEraseQueue, "DeregisterEraseQueue" }, + { GetCardServicesInfo, "GetCardServicesInfo" }, + { GetClientInfo, "GetClientInfo" }, + { GetConfigurationInfo, "GetConfigurationInfo" }, + { GetEventMask, "GetEventMask" }, + { GetFirstClient, "GetFirstClient" }, + { GetFirstRegion, "GetFirstRegion" }, + { GetFirstTuple, "GetFirstTuple" }, + { GetNextClient, "GetNextClient" }, + { GetNextRegion, "GetNextRegion" }, + { GetNextTuple, "GetNextTuple" }, + { GetStatus, "GetStatus" }, + { GetTupleData, "GetTupleData" }, + { MapMemPage, "MapMemPage" }, + { ModifyConfiguration, "ModifyConfiguration" }, + { ModifyWindow, "ModifyWindow" }, + { OpenMemory, "OpenMemory" }, + { ParseTuple, "ParseTuple" }, + { ReadMemory, "ReadMemory" }, + { RegisterClient, "RegisterClient" }, + { RegisterEraseQueue, "RegisterEraseQueue" }, + { RegisterMTD, "RegisterMTD" }, + { ReleaseConfiguration, "ReleaseConfiguration" }, + { ReleaseIO, "ReleaseIO" }, + { ReleaseIRQ, "ReleaseIRQ" }, + { ReleaseWindow, "ReleaseWindow" }, + { RequestConfiguration, "RequestConfiguration" }, + { RequestIO, "RequestIO" }, + { RequestIRQ, "RequestIRQ" }, + { RequestSocketMask, "RequestSocketMask" }, + { RequestWindow, "RequestWindow" }, + { ResetCard, "ResetCard" }, + { SetEventMask, "SetEventMask" }, + { ValidateCIS, "ValidateCIS" }, + { WriteMemory, "WriteMemory" }, + { BindDevice, "BindDevice" }, + { BindMTD, "BindMTD" }, + { ReportError, "ReportError" }, + { SuspendCard, "SuspendCard" }, + { ResumeCard, "ResumeCard" }, + { EjectCard, "EjectCard" }, + { InsertCard, "InsertCard" }, + { ReplaceCIS, "ReplaceCIS" } +}; +#define SERVICE_COUNT (sizeof(service_table)/sizeof(lookup_t)) + +/*====================================================================== + + Reset a socket to the default state + +======================================================================*/ + +static void init_socket(socket_info_t *s) +{ + int i; + pccard_io_map io = { 0, 0, 0, 0, 1 }; + pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; + + mem.sys_stop = s->cap.map_size; + s->socket = dead_socket; + s->ss_entry(s->sock, SS_SetSocket, &s->socket); + for (i = 0; i < 2; i++) { + io.map = i; + s->ss_entry(s->sock, SS_SetIOMap, &io); + } + for (i = 0; i < 5; i++) { + mem.map = i; + s->ss_entry(s->sock, SS_SetMemMap, &mem); + } +} + +/*====================================================================*/ + +#if defined(CONFIG_PROC_FS) && defined(PCMCIA_DEBUG) +int proc_read_clients(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + socket_info_t *s = data; + client_handle_t c; + char *p = buf; + + for (c = s->clients; c; c = c->next) + p += sprintf(p, "fn %x: '%s' [attr 0x%04x] [state 0x%04x]\n", + c->Function, c->dev_info, c->Attributes, c->state); + return (p - buf); +} +#endif + +/*====================================================================== + + Low-level PC Card interface drivers need to register with Card + Services using these calls. + +======================================================================*/ + +static void setup_socket(u_long i); +static void shutdown_socket(u_long i); +static void reset_socket(u_long i); +static void unreset_socket(u_long i); +static void parse_events(void *info, u_int events); + +int register_ss_entry(int nsock, ss_entry_t ss_entry) +{ + int i, ns; + socket_info_t *s; + + DEBUG(0, "cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry); + + for (ns = 0; ns < nsock; ns++) { + s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL); + memset(s, 0, sizeof(socket_info_t)); + + s->ss_entry = ss_entry; + s->sock = ns; + s->setup.data = sockets; + s->setup.function = &setup_socket; + s->shutdown.data = sockets; + s->shutdown.function = &shutdown_socket; + /* base address = 0, map = 0 */ + s->cis_mem.flags = 0; + s->cis_mem.speed = cis_speed; + s->erase_busy.next = s->erase_busy.prev = &s->erase_busy; + + for (i = 0; i < sockets; i++) + if (socket_table[i] == NULL) break; + socket_table[i] = s; + if (i == sockets) sockets++; + + init_socket(s); + ss_entry(ns, SS_InquireSocket, &s->cap); +#ifdef CONFIG_PROC_FS + if (proc_pccard) { + char name[3]; +#ifdef PCMCIA_DEBUG + struct proc_dir_entry *ent; +#endif + sprintf(name, "%02d", i); + s->proc = create_proc_entry(name, S_IFDIR, proc_pccard); +#ifdef PCMCIA_DEBUG + ent = create_proc_entry("clients", 0, s->proc); + ent->read_proc = proc_read_clients; + ent->data = s; +#endif + ss_entry(ns, SS_ProcSetup, s->proc); + } +#endif + } + + return 0; +} /* register_ss_entry */ + +/*====================================================================*/ + +void unregister_ss_entry(ss_entry_t ss_entry) +{ + int i, j; + socket_info_t *s = NULL; + client_t *client; + + for (;;) { + for (i = 0; i < sockets; i++) { + s = socket_table[i]; + if (s->ss_entry == ss_entry) break; + } + if (i == sockets) { + break; + } else { +#ifdef CONFIG_PROC_FS + if (proc_pccard) { + char name[3]; + sprintf(name, "%02d", i); +#ifdef PCMCIA_DEBUG + remove_proc_entry("clients", s->proc); +#endif + remove_proc_entry(name, proc_pccard); + } +#endif + while (s->clients) { + client = s->clients; + s->clients = s->clients->next; + kfree(client); + } + init_socket(s); + release_cis_mem(s); +#ifdef CONFIG_CARDBUS + cb_release_cis_mem(s); +#endif + s->ss_entry = NULL; + kfree(s); + socket_table[i] = NULL; + for (j = i; j < sockets-1; j++) + socket_table[j] = socket_table[j+1]; + sockets--; + } + } + +} /* unregister_ss_entry */ + +/*====================================================================== + + Shutdown_Socket() and setup_socket() are scheduled using add_timer + calls by the main event handler when card insertion and removal + events are received. Shutdown_Socket() unconfigures a socket and + turns off socket power. Setup_socket() turns on socket power + and resets the socket, in two stages. + +======================================================================*/ + +static void free_regions(memory_handle_t *list) +{ + memory_handle_t tmp; + while (*list != NULL) { + tmp = *list; + *list = tmp->info.next; + tmp->region_magic = 0; + kfree(tmp); + } +} + +static int send_event(socket_info_t *s, event_t event, int priority); + +static void shutdown_socket(u_long i) +{ + socket_info_t *s = socket_table[i]; + client_t **c; + + DEBUG(1, "cs: shutdown_socket(%ld)\n", i); + + /* Blank out the socket state */ + s->state &= SOCKET_PRESENT|SOCKET_SETUP_PENDING; + init_socket(s); + s->irq.AssignedIRQ = s->irq.Config = 0; + s->functions = 0; + s->lock_count = 0; + s->cis_used = 0; + if (s->fake_cis) { + kfree(s->fake_cis); + s->fake_cis = NULL; + } +#ifdef CONFIG_CARDBUS + cb_release_cis_mem(s); + cb_free(s); +#endif + if (s->config) { + kfree(s->config); + s->config = NULL; + } + for (c = &s->clients; *c; ) { + if ((*c)->state & CLIENT_UNBOUND) { + client_t *d = *c; + *c = (*c)->next; + kfree(d); + } else { + c = &((*c)->next); + } + } + free_regions(&s->a_region); + free_regions(&s->c_region); +} /* shutdown_socket */ + +static void setup_socket(u_long i) +{ + int val; + socket_info_t *s = socket_table[i]; + + s->ss_entry(s->sock, SS_GetStatus, &val); + if (val & SS_DETECT) { + DEBUG(1, "cs: setup_socket(%ld): applying power\n", i); + s->state |= SOCKET_PRESENT; + s->socket.flags = 0; + if (val & SS_3VCARD) + s->socket.Vcc = s->socket.Vpp = 33; + else if (!(val & SS_XVCARD)) + s->socket.Vcc = s->socket.Vpp = 50; + else { + printk(KERN_NOTICE "cs: socket %ld: unsupported " + "voltage key\n", i); + s->socket.Vcc = 0; + } + if (val & SS_CARDBUS) { + s->state |= SOCKET_CARDBUS; +#ifndef CONFIG_CARDBUS + printk(KERN_NOTICE "cs: unsupported card type detected!\n"); +#endif + } + s->ss_entry(s->sock, SS_SetSocket, &s->socket); + s->setup.function = &reset_socket; + s->setup.expires = jiffies + vcc_settle; + add_timer(&s->setup); + } else + DEBUG(0, "cs: setup_socket(%ld): no card!\n", i); +} /* setup_socket */ + +/*====================================================================== + + Reset_socket() and unreset_socket() handle hard resets. Resets + have several causes: card insertion, a call to reset_socket, or + recovery from a suspend/resume cycle. Unreset_socket() sends + a CS event that matches the cause of the reset. + +======================================================================*/ + +static void reset_socket(u_long i) +{ + socket_info_t *s = socket_table[i]; + + DEBUG(1, "cs: resetting socket %ld\n", i); + s->socket.flags |= SS_OUTPUT_ENA | SS_RESET; + s->ss_entry(s->sock, SS_SetSocket, &s->socket); + udelay((long)reset_time); + s->socket.flags &= ~SS_RESET; + s->ss_entry(s->sock, SS_SetSocket, &s->socket); + s->unreset_timeout = 0; + s->setup.expires = jiffies + unreset_delay; + s->setup.function = &unreset_socket; + add_timer(&s->setup); +} /* reset_socket */ + +#define EVENT_MASK \ +(SOCKET_SETUP_PENDING|SOCKET_SUSPEND|SOCKET_RESET_PENDING) + +static void unreset_socket(u_long i) +{ + socket_info_t *s = socket_table[i]; + int val; + + s->ss_entry(s->sock, SS_GetStatus, &val); + if (val & SS_READY) { + DEBUG(1, "cs: reset done on socket %ld\n", i); + if (s->state & SOCKET_SUSPEND) { + s->state &= ~EVENT_MASK; + if (verify_cis_cache(s) != 0) + parse_events(s, SS_DETECT); + else + send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); + } else if (s->state & SOCKET_SETUP_PENDING) { +#ifdef CONFIG_CARDBUS + if (s->state & SOCKET_CARDBUS) + cb_alloc(s); +#endif + send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); + s->state &= ~SOCKET_SETUP_PENDING; + } else { + send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW); + s->reset_handle->event_callback_args.info = NULL; + EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE, + CS_EVENT_PRI_LOW); + s->state &= ~EVENT_MASK; + } + } else { + DEBUG(2, "cs: socket %ld not ready yet\n", i); + if (s->unreset_timeout > unreset_limit) { + printk(KERN_NOTICE "cs: socket %ld timed out during" + " reset\n", i); + s->state &= ~EVENT_MASK; + } else { + s->unreset_timeout++; + s->setup.expires = jiffies + unreset_check; + add_timer(&s->setup); + } + } +} /* unreset_socket */ + +/*====================================================================== + + The central event handler. Send_event() sends an event to all + valid clients. Parse_events() interprets the event bits from + a card status change report. Do_shotdown() handles the high + priority stuff associated with a card removal. + +======================================================================*/ + +static int send_event(socket_info_t *s, event_t event, int priority) +{ + client_t *client = s->clients; + int ret; + DEBUG(1, "cs: send_event(sock %d, event %d, pri %d)\n", + s->sock, event, priority); + ret = 0; + for (; client; client = client->next) { + if (client->state & (CLIENT_UNBOUND|CLIENT_STALE)) + continue; + if (client->EventMask & event) { + ret = EVENT(client, event, priority); + if (ret != 0) + return ret; + } + } + return ret; +} /* send_event */ + +static void do_shutdown(socket_info_t *s) +{ + client_t *client; + if (s->state & SOCKET_SHUTDOWN_PENDING) + return; + s->state |= SOCKET_SHUTDOWN_PENDING; + send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); + for (client = s->clients; client; client = client->next) + if (!(client->Attributes & INFO_MASTER_CLIENT)) + client->state |= CLIENT_STALE; + if (s->state & (SOCKET_SETUP_PENDING|SOCKET_RESET_PENDING)) { + DEBUG(0, "cs: flushing pending setup\n"); + del_timer(&s->setup); + s->state &= ~EVENT_MASK; + } + s->shutdown.expires = jiffies + shutdown_delay; + add_timer(&s->shutdown); + s->state &= ~SOCKET_PRESENT; +} + +static void parse_events(void *info, u_int events) +{ + socket_info_t *s = info; + if (events & SS_DETECT) { + int status; + u_long flags; + spin_lock_irqsave(&s->lock, flags); + s->ss_entry(s->sock, SS_GetStatus, &status); + if ((s->state & SOCKET_PRESENT) && + (!(s->state & SOCKET_SUSPEND) || + !(status & SS_DETECT))) + do_shutdown(s); + if (status & SS_DETECT) { + if (s->state & SOCKET_SETUP_PENDING) { + del_timer(&s->setup); + DEBUG(1, "cs: delaying pending setup\n"); + } + s->state |= SOCKET_SETUP_PENDING; + s->setup.function = &setup_socket; + if (s->state & SOCKET_SUSPEND) + s->setup.expires = jiffies + resume_delay; + else + s->setup.expires = jiffies + setup_delay; + add_timer(&s->setup); + } + spin_unlock_irqrestore(&s->lock, flags); + } + if (events & SS_BATDEAD) + send_event(s, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW); + if (events & SS_BATWARN) + send_event(s, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW); + if (events & SS_READY) { + if (!(s->state & SOCKET_RESET_PENDING)) + send_event(s, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW); + else DEBUG(1, "cs: ready change during reset\n"); + } +} /* parse_events */ + +/*====================================================================== + + Another event handler, for power management events. + + This does not comply with the latest PC Card spec for handling + power management events. + +======================================================================*/ + +#ifdef CONFIG_APM +static int handle_apm_event(apm_event_t event) +{ + int i, stat; + socket_info_t *s; + static int down = 0; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + DEBUG(1, "cs: received suspend notification\n"); + if (down) { + printk(KERN_DEBUG "cs: received extra suspend event\n"); + break; + } + down = 1; + for (i = 0; i < sockets; i++) { + s = socket_table[i]; + if ((s->state & SOCKET_PRESENT) && + !(s->state & SOCKET_SUSPEND)){ + send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW); + s->ss_entry(s->sock, SS_SetSocket, &dead_socket); + s->state |= SOCKET_SUSPEND; + } + } + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + DEBUG(1, "cs: received resume notification\n"); + if (!down) { + printk(KERN_DEBUG "cs: received bogus resume event\n"); + break; + } + down = 0; + for (i = 0; i < sockets; i++) { + s = socket_table[i]; + /* Do this just to reinitialize the socket */ + init_socket(s); + s->ss_entry(s->sock, SS_GetStatus, &stat); + /* If there was or is a card here, we need to do something + about it... but parse_events will sort it all out. */ + if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT)) + parse_events(s, SS_DETECT); + } + break; + } + return 0; +} /* handle_apm_event */ +#endif + +/*====================================================================== + + Special stuff for managing IO windows, because they are scarce. + +======================================================================*/ + +static int alloc_io_space(socket_info_t *s, u_int attr, ioaddr_t *base, + ioaddr_t num, char *name) +{ + int i; + ioaddr_t try; + + for (i = 0; i < MAX_IO_WIN; i++) { + if (s->io[i].NumPorts == 0) { + if (find_io_region(base, num, name) == 0) { + s->io[i].Attributes = attr; + s->io[i].BasePort = *base; + s->io[i].NumPorts = s->io[i].InUse = num; + break; + } else + return 1; + } else if (s->io[i].Attributes != attr) + continue; + /* Try to extend top of window */ + try = s->io[i].BasePort + s->io[i].NumPorts; + if ((*base == 0) || (*base == try)) + if (find_io_region(&try, num, name) == 0) { + *base = try; + s->io[i].NumPorts += num; + s->io[i].InUse += num; + break; + } + /* Try to extend bottom of window */ + try = s->io[i].BasePort - num; + if ((*base == 0) || (*base == try)) + if (find_io_region(&try, num, name) == 0) { + s->io[i].BasePort = *base = try; + s->io[i].NumPorts += num; + s->io[i].InUse += num; + break; + } + } + return (i == MAX_IO_WIN); +} /* alloc_io_space */ + +static void release_io_space(socket_info_t *s, ioaddr_t base, + ioaddr_t num) +{ + int i; + release_region(base, num); + for (i = 0; i < MAX_IO_WIN; i++) { + if ((s->io[i].BasePort <= base) && + (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) { + s->io[i].InUse -= num; + /* Free the window if no one else is using it */ + if (s->io[i].InUse == 0) + s->io[i].NumPorts = 0; + } + } +} + +/*====================================================================== + + Access_configuration_register() reads and writes configuration + registers in attribute memory. Memory window 0 is reserved for + this and the tuple reading services. + +======================================================================*/ + +static int access_configuration_register(client_handle_t handle, + conf_reg_t *reg) +{ + socket_info_t *s; + config_t *c; + int addr; + u_char val; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); + if (handle->Function == BIND_FN_ALL) { + if (reg->Function >= s->functions) + return CS_BAD_ARGS; + c = &s->config[reg->Function]; + } else + c = CONFIG(handle); + if (!(c->state & CONFIG_LOCKED)) + return CS_CONFIGURATION_LOCKED; + + addr = (c->ConfigBase + reg->Offset) >> 1; + + switch (reg->Action) { + case CS_READ: + read_cis_mem(s, 1, addr, 1, &val); + reg->Value = val; + break; + case CS_WRITE: + val = reg->Value; + write_cis_mem(s, 1, addr, 1, &val); + break; + default: + return CS_BAD_ARGS; + break; + } + return CS_SUCCESS; +} /* access_configuration_register */ + +/*====================================================================== + + Bind_device() associates a device driver with a particular socket. + It is normally called by Driver Services after it has identified + a newly inserted card. An instance of that driver will then be + eligible to register as a client of this socket. + +======================================================================*/ + +static int bind_device(bind_req_t *req) +{ + client_t *client; + socket_info_t *s; + + if (CHECK_SOCKET(req->Socket)) + return CS_BAD_SOCKET; + s = SOCKET(req); + + client = (client_t *)kmalloc(sizeof(client_t), GFP_KERNEL); + memset(client, '\0', sizeof(client_t)); + client->client_magic = CLIENT_MAGIC; + strncpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN); + client->Socket = req->Socket; + client->Function = req->Function; + client->state = CLIENT_UNBOUND; + client->erase_busy.next = &client->erase_busy; + client->erase_busy.prev = &client->erase_busy; + init_waitqueue_head(&client->mtd_req); + client->next = s->clients; + s->clients = client; + DEBUG(1, "cs: bind_device(): client 0x%p, sock %d, dev %s\n", + client, client->Socket, client->dev_info); + return CS_SUCCESS; +} /* bind_device */ + +/*====================================================================== + + Bind_mtd() associates a device driver with a particular memory + region. It is normally called by Driver Services after it has + identified a memory device type. An instance of the corresponding + driver will then be able to register to control this region. + +======================================================================*/ + +static int bind_mtd(mtd_bind_t *req) +{ + socket_info_t *s; + memory_handle_t region; + + if (CHECK_SOCKET(req->Socket)) + return CS_BAD_SOCKET; + s = SOCKET(req); + + if (req->Attributes & REGION_TYPE_AM) + region = s->a_region; + else + region = s->c_region; + + while (region) { + if (region->info.CardOffset == req->CardOffset) break; + region = region->info.next; + } + if (!region || (region->mtd != NULL)) + return CS_BAD_OFFSET; + strncpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN); + + DEBUG(1, "cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n", + req->Attributes, req->CardOffset, (char *)req->dev_info); + return CS_SUCCESS; +} /* bind_mtd */ + +/*====================================================================*/ + +static int deregister_client(client_handle_t handle) +{ + client_t **client; + socket_info_t *s; + memory_handle_t region; + u_long flags; + int i, sn; + + DEBUG(1, "cs: deregister_client(%p)\n", handle); + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + if (handle->state & + (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) + return CS_IN_USE; + for (i = 0; i < MAX_WIN; i++) + if (handle->state & CLIENT_WIN_REQ(i)) + return CS_IN_USE; + + /* Disconnect all MTD links */ + s = SOCKET(handle); + if (handle->mtd_count) { + for (region = s->a_region; region; region = region->info.next) + if (region->mtd == handle) region->mtd = NULL; + for (region = s->c_region; region; region = region->info.next) + if (region->mtd == handle) region->mtd = NULL; + } + + sn = handle->Socket; s = socket_table[sn]; + + if ((handle->state & CLIENT_STALE) || + (handle->Attributes & INFO_MASTER_CLIENT)) { + spin_lock_irqsave(&s->lock, flags); + client = &s->clients; + while ((*client) && ((*client) != handle)) + client = &(*client)->next; + if (*client == NULL) + return CS_BAD_HANDLE; + *client = handle->next; + handle->client_magic = 0; + kfree(handle); + spin_unlock_irqrestore(&s->lock, flags); + } else { + handle->state = CLIENT_UNBOUND; + handle->mtd_count = 0; + handle->event_handler = NULL; + } + + if (--s->real_clients == 0) + s->ss_entry(sn, SS_RegisterCallback, NULL); + + return CS_SUCCESS; +} /* deregister_client */ + +/*====================================================================*/ + +static int get_configuration_info(client_handle_t handle, + config_info_t *config) +{ + socket_info_t *s; + config_t *c; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + + if (handle->Function == BIND_FN_ALL) { + if (config->Function && (config->Function >= s->functions)) + return CS_BAD_ARGS; + } else + config->Function = handle->Function; + +#ifdef CONFIG_CARDBUS + if (s->state & SOCKET_CARDBUS) { + u_char fn = config->Function; + memset(config, 0, sizeof(config_info_t)); + config->Function = fn; + config->Vcc = s->socket.Vcc; + config->Vpp1 = config->Vpp2 = s->socket.Vpp; + config->Option = s->cap.cardbus; + if (s->cb_config) { + config->Attributes = CONF_VALID_CLIENT; + config->IntType = INT_CARDBUS; + config->AssignedIRQ = s->irq.AssignedIRQ; + if (config->AssignedIRQ) + config->Attributes |= CONF_ENABLE_IRQ; + config->BasePort1 = s->io[0].BasePort; + config->NumPorts1 = s->io[0].NumPorts; + } + return CS_SUCCESS; + } +#endif + + c = (s->config != NULL) ? &s->config[config->Function] : NULL; + + if ((c == NULL) || !(c->state & CONFIG_LOCKED)) { + config->Attributes = 0; + config->Vcc = s->socket.Vcc; + config->Vpp1 = config->Vpp2 = s->socket.Vpp; + return CS_SUCCESS; + } + + /* !!! This is a hack !!! */ + memcpy(&config->Attributes, &c->Attributes, sizeof(config_t)); + config->Attributes |= CONF_VALID_CLIENT; + config->CardValues = c->CardValues; + config->IRQAttributes = c->irq.Attributes; + config->AssignedIRQ = s->irq.AssignedIRQ; + config->BasePort1 = c->io.BasePort1; + config->NumPorts1 = c->io.NumPorts1; + config->Attributes1 = c->io.Attributes1; + config->BasePort2 = c->io.BasePort2; + config->NumPorts2 = c->io.NumPorts2; + config->Attributes2 = c->io.Attributes2; + config->IOAddrLines = c->io.IOAddrLines; + + return CS_SUCCESS; +} /* get_configuration_info */ + +/*====================================================================== + + Return information about this version of Card Services. + +======================================================================*/ + +static int get_card_services_info(servinfo_t *info) +{ + info->Signature[0] = 'C'; + info->Signature[1] = 'S'; + info->Count = sockets; + info->Revision = CS_RELEASE_CODE; + info->CSLevel = 0x0210; + info->VendorString = (char *)release; + return CS_SUCCESS; +} /* get_card_services_info */ + +/*====================================================================== + + Note that get_first_client() *does* recognize the Socket field + in the request structure. + +======================================================================*/ + +static int get_first_client(client_handle_t *handle, client_req_t *req) +{ + socket_t s; + if (req->Attributes & CLIENT_THIS_SOCKET) + s = req->Socket; + else + s = 0; + if (CHECK_SOCKET(req->Socket)) + return CS_BAD_SOCKET; + if (socket_table[s]->clients == NULL) + return CS_NO_MORE_ITEMS; + *handle = socket_table[s]->clients; + return CS_SUCCESS; +} /* get_first_client */ + +/*====================================================================*/ + +static int get_next_client(client_handle_t *handle, client_req_t *req) +{ + socket_info_t *s; + if ((handle == NULL) || CHECK_HANDLE(*handle)) + return CS_BAD_HANDLE; + if ((*handle)->next == NULL) { + if (req->Attributes & CLIENT_THIS_SOCKET) + return CS_NO_MORE_ITEMS; + s = SOCKET(*handle); + if (s->clients == NULL) + return CS_NO_MORE_ITEMS; + *handle = s->clients; + } else + *handle = (*handle)->next; + return CS_SUCCESS; +} /* get_next_client */ + +/*====================================================================*/ + +static int get_window(window_handle_t *handle, int idx, win_req_t *req) +{ + socket_info_t *s; + window_t *win; + int w; + + if (idx == 0) + s = SOCKET((client_handle_t)*handle); + else + s = (*handle)->sock; + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + for (w = idx; w < MAX_WIN; w++) + if (s->state & SOCKET_WIN_REQ(w)) break; + if (w == MAX_WIN) + return CS_NO_MORE_ITEMS; + win = &s->win[w]; + req->Base = win->ctl.sys_start; + req->Size = win->ctl.sys_stop - win->ctl.sys_start + 1; + req->AccessSpeed = win->ctl.speed; + req->Attributes = 0; + if (win->ctl.flags & MAP_ATTRIB) + req->Attributes |= WIN_MEMORY_TYPE_AM; + if (win->ctl.flags & MAP_ACTIVE) + req->Attributes |= WIN_ENABLE; + if (win->ctl.flags & MAP_16BIT) + req->Attributes |= WIN_DATA_WIDTH; + if (win->ctl.flags & MAP_USE_WAIT) + req->Attributes |= WIN_USE_WAIT; + *handle = win; + return CS_SUCCESS; +} /* get_window */ + +static int get_first_window(client_handle_t *handle, win_req_t *req) +{ + if ((handle == NULL) || CHECK_HANDLE(*handle)) + return CS_BAD_HANDLE; + return get_window((window_handle_t *)handle, 0, req); +} + +static int get_next_window(window_handle_t *win, win_req_t *req) +{ + if ((win == NULL) || ((*win)->magic != WINDOW_MAGIC)) + return CS_BAD_HANDLE; + return get_window(win, (*win)->index+1, req); +} + +/*====================================================================== + + Get the current socket state bits. We don't support the latched + SocketState yet: I haven't seen any point for it. + +======================================================================*/ + +static int get_status(client_handle_t handle, cs_status_t *status) +{ + socket_info_t *s; + config_t *c; + int val; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); + s->ss_entry(s->sock, SS_GetStatus, &val); + status->CardState = status->SocketState = 0; + status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0; + status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0; + status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0; + status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0; + if (s->state & SOCKET_SUSPEND) + status->CardState |= CS_EVENT_PM_SUSPEND; + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + if (s->state & SOCKET_SETUP_PENDING) + status->CardState |= CS_EVENT_CARD_INSERTION; + + /* Get info from the PRR, if necessary */ + if (handle->Function == BIND_FN_ALL) { + if (status->Function && (status->Function >= s->functions)) + return CS_BAD_ARGS; + c = (s->config != NULL) ? &s->config[status->Function] : NULL; + } else + c = CONFIG(handle); + if ((c != NULL) && (c->state & CONFIG_LOCKED) && + (c->IntType & INT_MEMORY_AND_IO)) { + u_char reg; + if (c->Present & PRESENT_PIN_REPLACE) { + read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); + status->CardState |= + (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0; + status->CardState |= + (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0; + status->CardState |= + (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0; + status->CardState |= + (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0; + } else { + /* No PRR? Then assume we're always ready */ + status->CardState |= CS_EVENT_READY_CHANGE; + } + if (c->Present & PRESENT_EXT_STATUS) { + read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®); + status->CardState |= + (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0; + } + return CS_SUCCESS; + } + status->CardState |= + (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0; + status->CardState |= + (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0; + status->CardState |= + (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0; + status->CardState |= + (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0; + return CS_SUCCESS; +} /* get_status */ + +/*====================================================================== + + Change the card address of an already open memory window. + +======================================================================*/ + +static int get_mem_page(window_handle_t win, memreq_t *req) +{ + if ((win == NULL) || (win->magic != WINDOW_MAGIC)) + return CS_BAD_HANDLE; + req->Page = 0; + req->CardOffset = win->ctl.card_start; + return CS_SUCCESS; +} /* get_mem_page */ + +static int map_mem_page(window_handle_t win, memreq_t *req) +{ + socket_info_t *s; + if ((win == NULL) || (win->magic != WINDOW_MAGIC)) + return CS_BAD_HANDLE; + if (req->Page != 0) + return CS_BAD_PAGE; + s = win->sock; + win->ctl.card_start = req->CardOffset; + if (s->ss_entry(s->sock, SS_SetMemMap, &win->ctl) != 0) + return CS_BAD_OFFSET; + return CS_SUCCESS; +} /* map_mem_page */ + +/*====================================================================== + + Modify a locked socket configuration + +======================================================================*/ + +static int modify_configuration(client_handle_t handle, + modconf_t *mod) +{ + socket_info_t *s; + config_t *c; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); c = CONFIG(handle); + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + if (!(c->state & CONFIG_LOCKED)) + return CS_CONFIGURATION_LOCKED; + + if (mod->Attributes & CONF_IRQ_CHANGE_VALID) { + if (mod->Attributes & CONF_ENABLE_IRQ) { + c->Attributes |= CONF_ENABLE_IRQ; + s->socket.io_irq = s->irq.AssignedIRQ; + } else { + c->Attributes &= ~CONF_ENABLE_IRQ; + s->socket.io_irq = 0; + } + s->ss_entry(s->sock, SS_SetSocket, &s->socket); + } + + if (mod->Attributes & CONF_VCC_CHANGE_VALID) + return CS_BAD_VCC; + + /* We only allow changing Vpp1 and Vpp2 to the same value */ + if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) && + (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { + if (mod->Vpp1 != mod->Vpp2) + return CS_BAD_VPP; + c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1; + if (s->ss_entry(s->sock, SS_SetSocket, &s->socket)) + return CS_BAD_VPP; + } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || + (mod->Attributes & CONF_VPP2_CHANGE_VALID)) + return CS_BAD_VPP; + + return CS_SUCCESS; +} /* modify_configuration */ + +/*====================================================================== + + Modify the attributes of a window returned by RequestWindow. + +======================================================================*/ + +static int modify_window(window_handle_t win, modwin_t *req) +{ + if ((win == NULL) || (win->magic != WINDOW_MAGIC)) + return CS_BAD_HANDLE; + + win->ctl.flags &= ~(MAP_ATTRIB|MAP_ACTIVE); + if (req->Attributes & WIN_MEMORY_TYPE) + win->ctl.flags |= MAP_ATTRIB; + if (req->Attributes & WIN_ENABLE) + win->ctl.flags |= MAP_ACTIVE; + if (req->Attributes & WIN_DATA_WIDTH) + win->ctl.flags |= MAP_16BIT; + if (req->Attributes & WIN_USE_WAIT) + win->ctl.flags |= MAP_USE_WAIT; + win->ctl.speed = req->AccessSpeed; + win->sock->ss_entry(win->sock->sock, SS_SetMemMap, &win->ctl); + + return CS_SUCCESS; +} /* modify_window */ + +/*====================================================================== + + Register_client() uses the dev_info_t handle to match the + caller with a socket. The driver must have already been bound + to a socket with bind_device() -- in fact, bind_device() + allocates the client structure that will be used. + +======================================================================*/ + +static int register_client(client_handle_t *handle, client_reg_t *req) +{ + client_t *client; + socket_info_t *s; + socket_t ns; + + /* Look for unbound client with matching dev_info */ + client = NULL; + for (ns = 0; ns < sockets; ns++) { + client = socket_table[ns]->clients; + while (client != NULL) { + if ((strcmp(client->dev_info, (char *)req->dev_info) == 0) + && (client->state & CLIENT_UNBOUND)) break; + client = client->next; + } + if (client != NULL) break; + } + if (client == NULL) + return CS_OUT_OF_RESOURCE; + + s = socket_table[ns]; + if (++s->real_clients == 1) { + ss_callback_t call; + int status; + call.handler = &parse_events; + call.info = s; + s->ss_entry(ns, SS_RegisterCallback, &call); + s->ss_entry(ns, SS_GetStatus, &status); + if ((status & SS_DETECT) && + !(s->state & SOCKET_SETUP_PENDING)) { + s->state |= SOCKET_SETUP_PENDING; + setup_socket(ns); + } + } + + *handle = client; + client->state &= ~CLIENT_UNBOUND; + client->Socket = ns; + client->Attributes = req->Attributes; + client->EventMask = req->EventMask; + client->event_handler = req->event_handler; + client->event_callback_args = req->event_callback_args; + client->event_callback_args.client_handle = client; + client->event_callback_args.bus = s->cap.bus; + + if (s->state & SOCKET_CARDBUS) + client->state |= CLIENT_CARDBUS; + + if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) && + (client->Function != BIND_FN_ALL)) { + cistpl_longlink_mfc_t mfc; + if (read_tuple(client, CISTPL_LONGLINK_MFC, &mfc) + == CS_SUCCESS) + s->functions = mfc.nfn; + else + s->functions = 1; + s->config = kmalloc(sizeof(config_t) * s->functions, + GFP_KERNEL); + memset(s->config, 0, sizeof(config_t) * s->functions); + } + + DEBUG(1, "cs: register_client(): client 0x%p, sock %d, dev %s\n", + client, client->Socket, client->dev_info); + if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE) + EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW); + if ((socket_table[ns]->state & SOCKET_PRESENT) && + !(socket_table[ns]->state & SOCKET_SETUP_PENDING)) { + if (client->EventMask & CS_EVENT_CARD_INSERTION) + EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); + else + client->PendingEvents |= CS_EVENT_CARD_INSERTION; + } + return CS_SUCCESS; +} /* register_client */ + +/*====================================================================*/ + +static int release_configuration(client_handle_t handle, + socket_t *Socket) +{ + pccard_io_map io; + socket_info_t *s; + int i; + + if (CHECK_HANDLE(handle) || + !(handle->state & CLIENT_CONFIG_LOCKED)) + return CS_BAD_HANDLE; + handle->state &= ~CLIENT_CONFIG_LOCKED; + s = SOCKET(handle); + +#ifdef CONFIG_CARDBUS + if (handle->state & CLIENT_CARDBUS) { + cb_disable(s); + s->lock_count = 0; + return CS_SUCCESS; + } +#endif + + if (!(handle->state & CLIENT_STALE)) { + config_t *c = CONFIG(handle); + if (--(s->lock_count) == 0) { + s->socket.flags = SS_OUTPUT_ENA; + s->socket.Vpp = 0; + s->socket.io_irq = 0; + s->ss_entry(s->sock, SS_SetSocket, &s->socket); + } + if (c->state & CONFIG_IO_REQ) + for (i = 0; i < MAX_IO_WIN; i++) { + if (s->io[i].NumPorts == 0) + continue; + s->io[i].Config--; + if (s->io[i].Config != 0) + continue; + io.map = i; + s->ss_entry(s->sock, SS_GetIOMap, &io); + io.flags &= ~MAP_ACTIVE; + s->ss_entry(s->sock, SS_SetIOMap, &io); + } + c->state &= ~CONFIG_LOCKED; + } + + return CS_SUCCESS; +} /* release_configuration */ + +/*====================================================================== + + Release_io() releases the I/O ranges allocated by a client. This + may be invoked some time after a card ejection has already dumped + the actual socket configuration, so if the client is "stale", we + don't bother checking the port ranges against the current socket + values. + +======================================================================*/ + +static int release_io(client_handle_t handle, io_req_t *req) +{ + socket_info_t *s; + + if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ)) + return CS_BAD_HANDLE; + handle->state &= ~CLIENT_IO_REQ; + s = SOCKET(handle); + +#ifdef CONFIG_CARDBUS + if (handle->state & CLIENT_CARDBUS) { + cb_release(s); + return CS_SUCCESS; + } +#endif + + if (!(handle->state & CLIENT_STALE)) { + config_t *c = CONFIG(handle); + if (c->state & CONFIG_LOCKED) + return CS_CONFIGURATION_LOCKED; + if ((c->io.BasePort1 != req->BasePort1) || + (c->io.NumPorts1 != req->NumPorts1) || + (c->io.BasePort2 != req->BasePort2) || + (c->io.NumPorts2 != req->NumPorts2)) + return CS_BAD_ARGS; + c->state &= ~CONFIG_IO_REQ; + } + + release_io_space(s, req->BasePort1, req->NumPorts1); + if (req->NumPorts2) + release_io_space(s, req->BasePort2, req->NumPorts2); + + return CS_SUCCESS; +} /* release_io */ + +/*====================================================================*/ + +static int cs_release_irq(client_handle_t handle, irq_req_t *req) +{ + socket_info_t *s; + if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ)) + return CS_BAD_HANDLE; + handle->state &= ~CLIENT_IRQ_REQ; + s = SOCKET(handle); + + if (!(handle->state & CLIENT_STALE)) { + config_t *c = CONFIG(handle); + if (c->state & CONFIG_LOCKED) + return CS_CONFIGURATION_LOCKED; + if (c->irq.Attributes != req->Attributes) + return CS_BAD_ATTRIBUTE; + if (s->irq.AssignedIRQ != req->AssignedIRQ) + return CS_BAD_IRQ; + if (--s->irq.Config == 0) { + c->state &= ~CONFIG_IRQ_REQ; + s->irq.AssignedIRQ = 0; + } + } + + if (req->Attributes & IRQ_HANDLE_PRESENT) { + bus_free_irq(s->cap.bus, req->AssignedIRQ, req->Instance); + } + +#ifdef CONFIG_ISA + if (req->AssignedIRQ != s->cap.pci_irq) + undo_irq(req->Attributes, req->AssignedIRQ); +#endif + + return CS_SUCCESS; +} /* cs_release_irq */ + +/*====================================================================*/ + +static int release_window(window_handle_t win) +{ + socket_info_t *s; + + if ((win == NULL) || (win->magic != WINDOW_MAGIC)) + return CS_BAD_HANDLE; + s = win->sock; + if (!(win->handle->state & CLIENT_WIN_REQ(win->index))) + return CS_BAD_HANDLE; + + /* Shut down memory window */ + win->ctl.flags &= ~MAP_ACTIVE; + s->ss_entry(s->sock, SS_SetMemMap, &win->ctl); + s->state &= ~SOCKET_WIN_REQ(win->index); + + /* Release system memory */ + release_mem_region(win->base, win->size); + win->handle->state &= ~CLIENT_WIN_REQ(win->index); + + win->magic = 0; + + return CS_SUCCESS; +} /* release_window */ + +/*====================================================================*/ + +static int request_configuration(client_handle_t handle, + config_req_t *req) +{ + int i; + u_int base; + socket_info_t *s; + config_t *c; + pccard_io_map iomap; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + i = handle->Socket; s = socket_table[i]; + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + +#ifdef CONFIG_CARDBUS + if (handle->state & CLIENT_CARDBUS) { + if (!(req->IntType & INT_CARDBUS)) + return CS_UNSUPPORTED_MODE; + if (s->lock_count != 0) + return CS_CONFIGURATION_LOCKED; + cb_enable(s); + handle->state |= CLIENT_CONFIG_LOCKED; + s->lock_count++; + return CS_SUCCESS; + } +#endif + + if (req->IntType & INT_CARDBUS) + return CS_UNSUPPORTED_MODE; + c = CONFIG(handle); + if (c->state & CONFIG_LOCKED) + return CS_CONFIGURATION_LOCKED; + + /* Do power control. We don't allow changes in Vcc. */ + if (s->socket.Vcc != req->Vcc) + return CS_BAD_VCC; + if (req->Vpp1 != req->Vpp2) + return CS_BAD_VPP; + s->socket.Vpp = req->Vpp1; + if (s->ss_entry(s->sock, SS_SetSocket, &s->socket)) + return CS_BAD_VPP; + + c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1; + + /* Pick memory or I/O card, DMA mode, interrupt */ + c->IntType = req->IntType; + c->Attributes = req->Attributes; + if (req->IntType & INT_MEMORY_AND_IO) + s->socket.flags |= SS_IOCARD; + if (req->Attributes & CONF_ENABLE_DMA) + s->socket.flags |= SS_DMA_MODE; + if (req->Attributes & CONF_ENABLE_SPKR) + s->socket.flags |= SS_SPKR_ENA; + if (req->Attributes & CONF_ENABLE_IRQ) + s->socket.io_irq = s->irq.AssignedIRQ; + else + s->socket.io_irq = 0; + s->ss_entry(s->sock, SS_SetSocket, &s->socket); + s->lock_count++; + + /* Set up CIS configuration registers */ + base = c->ConfigBase = req->ConfigBase; + c->Present = c->CardValues = req->Present; + if (req->Present & PRESENT_COPY) { + c->Copy = req->Copy; + write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy); + } + if (req->Present & PRESENT_OPTION) { + if (s->functions == 1) + c->Option = req->ConfigIndex & COR_CONFIG_MASK; + else { + c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK; + c->Option |= COR_FUNC_ENA|COR_ADDR_DECODE|COR_IREQ_ENA; + } + if (c->state & CONFIG_IRQ_REQ) + if (!(c->irq.Attributes & IRQ_FORCED_PULSE)) + c->Option |= COR_LEVEL_REQ; + write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option); + udelay(40*1000); + } + if (req->Present & PRESENT_STATUS) { + c->Status = req->Status; + write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status); + } + if (req->Present & PRESENT_PIN_REPLACE) { + c->Pin = req->Pin; + write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin); + } + if (req->Present & PRESENT_EXT_STATUS) { + c->ExtStatus = req->ExtStatus; + write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus); + } + if (req->Present & PRESENT_IOBASE_0) { + i = c->io.BasePort1 & 0xff; + write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &i); + i = (c->io.BasePort1 >> 8) & 0xff; + write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &i); + } + if (req->Present & PRESENT_IOSIZE) { + i = c->io.NumPorts1 + c->io.NumPorts2 - 1; + write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &i); + } + + /* Configure I/O windows */ + if (c->state & CONFIG_IO_REQ) { + iomap.speed = io_speed; + for (i = 0; i < MAX_IO_WIN; i++) + if (s->io[i].NumPorts != 0) { + iomap.map = i; + iomap.flags = MAP_ACTIVE; + switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) { + case IO_DATA_PATH_WIDTH_16: + iomap.flags |= MAP_16BIT; break; + case IO_DATA_PATH_WIDTH_AUTO: + iomap.flags |= MAP_AUTOSZ; break; + default: + break; + } + iomap.start = s->io[i].BasePort; + iomap.stop = iomap.start + s->io[i].NumPorts - 1; + s->ss_entry(s->sock, SS_SetIOMap, &iomap); + s->io[i].Config++; + } + } + + c->state |= CONFIG_LOCKED; + handle->state |= CLIENT_CONFIG_LOCKED; + return CS_SUCCESS; +} /* request_configuration */ + +/*====================================================================== + + Request_io() reserves ranges of port addresses for a socket. + I have not implemented range sharing or alias addressing. + +======================================================================*/ + +static int request_io(client_handle_t handle, io_req_t *req) +{ + socket_info_t *s; + config_t *c; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + + if (handle->state & CLIENT_CARDBUS) { +#ifdef CONFIG_CARDBUS + int ret = cb_config(s); + if (ret == CS_SUCCESS) + handle->state |= CLIENT_IO_REQ; + return ret; +#else + return CS_UNSUPPORTED_FUNCTION; +#endif + } + + if (!req) + return CS_UNSUPPORTED_MODE; + c = CONFIG(handle); + if (c->state & CONFIG_LOCKED) + return CS_CONFIGURATION_LOCKED; + if (c->state & CONFIG_IO_REQ) + return CS_IN_USE; + if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) + return CS_BAD_ATTRIBUTE; + if ((req->NumPorts2 > 0) && + (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) + return CS_BAD_ATTRIBUTE; + + if (alloc_io_space(s, req->Attributes1, &req->BasePort1, + req->NumPorts1, handle->dev_info)) + return CS_IN_USE; + + if (req->NumPorts2) { + if (alloc_io_space(s, req->Attributes2, &req->BasePort2, + req->NumPorts2, handle->dev_info)) { + release_io_space(s, req->BasePort1, req->NumPorts1); + return CS_IN_USE; + } + } + + c->io = *req; + c->state |= CONFIG_IO_REQ; + handle->state |= CLIENT_IO_REQ; + return CS_SUCCESS; +} /* request_io */ + +/*====================================================================== + + Request_irq() reserves an irq for this client. + + Also, since Linux only reserves irq's when they are actually + hooked, we don't guarantee that an irq will still be available + when the configuration is locked. Now that I think about it, + there might be a way to fix this using a dummy handler. + +======================================================================*/ + +static int cs_request_irq(client_handle_t handle, irq_req_t *req) +{ + socket_info_t *s; + config_t *c; + int try, ret = 0, irq = 0; + u_int mask; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + s = SOCKET(handle); + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + c = CONFIG(handle); + if (c->state & CONFIG_LOCKED) + return CS_CONFIGURATION_LOCKED; + if (c->state & CONFIG_IRQ_REQ) + return CS_IN_USE; + + /* Short cut: if the interrupt is PCI, there are no options */ + if (s->cap.irq_mask == (1 << s->cap.pci_irq)) + irq = s->cap.pci_irq; +#ifdef CONFIG_ISA + else if (s->irq.AssignedIRQ != 0) { + /* If the interrupt is already assigned, it must match */ + irq = s->irq.AssignedIRQ; + if (req->IRQInfo1 & IRQ_INFO2_VALID) { + mask = req->IRQInfo2 & s->cap.irq_mask; + ret = ((mask >> irq) & 1) ? 0 : CS_BAD_ARGS; + } else + ret = ((req->IRQInfo1&IRQ_MASK) == irq) ? 0 : CS_BAD_ARGS; + } else { + ret = CS_IN_USE; + if (req->IRQInfo1 & IRQ_INFO2_VALID) { + mask = req->IRQInfo2 & s->cap.irq_mask; + mask &= ~(1 << s->cap.pci_irq); + for (try = 0; try < 2; try++) { + for (irq = 0; irq < 32; irq++) + if ((mask >> irq) & 1) { + ret = try_irq(req->Attributes, irq, try); + if (ret == 0) break; + } + if (ret == 0) break; + } + } else { + irq = req->IRQInfo1 & IRQ_MASK; + ret = try_irq(req->Attributes, irq, 1); + } + } +#endif + if (ret != 0) return ret; + + if (req->Attributes & IRQ_HANDLE_PRESENT) { + if (bus_request_irq(s->cap.bus, irq, req->Handler, + ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || + (s->functions > 1) || + (irq == s->cap.pci_irq)) ? SA_SHIRQ : 0, + handle->dev_info, req->Instance)) + return CS_IN_USE; + } + + c->irq.Attributes = req->Attributes; + s->irq.AssignedIRQ = req->AssignedIRQ = irq; + s->irq.Config++; + + c->state |= CONFIG_IRQ_REQ; + handle->state |= CLIENT_IRQ_REQ; + return CS_SUCCESS; +} /* cs_request_irq */ + +/*====================================================================== + + Request_window() establishes a mapping between card memory space + and system memory space. + +======================================================================*/ + +static int request_window(client_handle_t *handle, win_req_t *req) +{ + socket_info_t *s; + window_t *win; + int w; + + if (CHECK_HANDLE(*handle)) + return CS_BAD_HANDLE; + s = SOCKET(*handle); + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + if (req->Attributes & (WIN_PAGED | WIN_SHARED)) + return CS_BAD_ATTRIBUTE; + + for (w = 0; w < MAX_WIN; w++) + if (!(s->state & SOCKET_WIN_REQ(w))) break; + if (w == MAX_WIN) + return CS_OUT_OF_RESOURCE; + + /* Window size defaults to smallest available */ + if (req->Size == 0) + req->Size = s->cap.map_size; + + /* Allocate system memory window */ + win = &s->win[w]; + win->magic = WINDOW_MAGIC; + win->index = w; + win->handle = *handle; + win->sock = s; + win->base = req->Base; + win->size = req->Size; + if (find_mem_region(&win->base, win->size, (*handle)->dev_info, + ((s->cap.features & SS_CAP_MEM_ALIGN) ? + req->Size : s->cap.map_size), + (req->Attributes & WIN_MAP_BELOW_1MB) || + !(s->cap.features & SS_CAP_PAGE_REGS))) + return CS_IN_USE; + req->Base = win->base; + (*handle)->state |= CLIENT_WIN_REQ(w); + + /* Configure the socket controller */ + win->ctl.map = w+1; + win->ctl.flags = 0; + win->ctl.speed = req->AccessSpeed; + if (req->Attributes & WIN_MEMORY_TYPE) + win->ctl.flags |= MAP_ATTRIB; + if (req->Attributes & WIN_ENABLE) + win->ctl.flags |= MAP_ACTIVE; + if (req->Attributes & WIN_DATA_WIDTH) + win->ctl.flags |= MAP_16BIT; + if (req->Attributes & WIN_USE_WAIT) + win->ctl.flags |= MAP_USE_WAIT; + win->ctl.sys_start = req->Base; + win->ctl.sys_stop = req->Base + req->Size-1; + win->ctl.card_start = 0; + if (s->ss_entry(s->sock, SS_SetMemMap, &win->ctl) != 0) + return CS_BAD_ARGS; + s->state |= SOCKET_WIN_REQ(w); + + /* Return window handle */ + *handle = (client_handle_t)win; + + return CS_SUCCESS; +} /* request_window */ + +/*====================================================================== + + I'm not sure which "reset" function this is supposed to use, + but for now, it uses the low-level interface's reset, not the + CIS register. + +======================================================================*/ + +static int reset_card(client_handle_t handle, client_req_t *req) +{ + int i, ret; + socket_info_t *s; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + i = handle->Socket; s = socket_table[i]; + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + if (s->state & SOCKET_RESET_PENDING) + return CS_IN_USE; + s->state |= SOCKET_RESET_PENDING; + + ret = send_event(s, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW); + if (ret != 0) { + s->state &= ~SOCKET_RESET_PENDING; + handle->event_callback_args.info = (void *)(u_long)ret; + EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW); + } else { + DEBUG(1, "cs: resetting socket %d\n", i); + send_event(s, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW); + s->reset_handle = handle; + reset_socket(i); + } + return CS_SUCCESS; +} /* reset_card */ + +/*====================================================================== + + These shut down or wake up a socket. They are sort of user + initiated versions of the APM suspend and resume actions. + +======================================================================*/ + +static int suspend_card(client_handle_t handle, client_req_t *req) +{ + int i; + socket_info_t *s; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + i = handle->Socket; s = socket_table[i]; + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + if (s->state & SOCKET_SUSPEND) + return CS_IN_USE; + + DEBUG(1, "cs: suspending socket %d\n", i); + send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW); + s->ss_entry(s->sock, SS_SetSocket, &dead_socket); + s->state |= SOCKET_SUSPEND; + + return CS_SUCCESS; +} /* suspend_card */ + +static int resume_card(client_handle_t handle, client_req_t *req) +{ + int i; + socket_info_t *s; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + i = handle->Socket; s = socket_table[i]; + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + if (!(s->state & SOCKET_SUSPEND)) + return CS_IN_USE; + + DEBUG(1, "cs: waking up socket %d\n", i); + setup_socket(i); + + return CS_SUCCESS; +} /* resume_card */ + +/*====================================================================== + + These handle user requests to eject or insert a card. + +======================================================================*/ + +static int eject_card(client_handle_t handle, client_req_t *req) +{ + int i, ret; + socket_info_t *s; + u_long flags; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + i = handle->Socket; s = socket_table[i]; + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + + DEBUG(1, "cs: user eject request on socket %d\n", i); + + ret = send_event(s, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW); + if (ret != 0) + return ret; + + spin_lock_irqsave(&s->lock, flags); + do_shutdown(s); + spin_unlock_irqrestore(&s->lock, flags); + + return CS_SUCCESS; + +} /* eject_card */ + +static int insert_card(client_handle_t handle, client_req_t *req) +{ + int i, status; + socket_info_t *s; + u_long flags; + + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + i = handle->Socket; s = socket_table[i]; + if (s->state & SOCKET_PRESENT) + return CS_IN_USE; + + DEBUG(1, "cs: user insert request on socket %d\n", i); + + spin_lock_irqsave(&s->lock, flags); + if (!(s->state & SOCKET_SETUP_PENDING)) { + s->state |= SOCKET_SETUP_PENDING; + spin_unlock_irqrestore(&s->lock, flags); + s->ss_entry(i, SS_GetStatus, &status); + if (status & SS_DETECT) + setup_socket(i); + else { + s->state &= ~SOCKET_SETUP_PENDING; + return CS_NO_CARD; + } + } else + spin_unlock_irqrestore(&s->lock, flags); + + return CS_SUCCESS; +} /* insert_card */ + +/*====================================================================== + + Maybe this should send a CS_EVENT_CARD_INSERTION event if we + haven't sent one to this client yet? + +======================================================================*/ + +static int set_event_mask(client_handle_t handle, eventmask_t *mask) +{ + u_int events, bit; + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + if (handle->Attributes & CONF_EVENT_MASK_VALID) + return CS_BAD_SOCKET; + handle->EventMask = mask->EventMask; + events = handle->PendingEvents & handle->EventMask; + handle->PendingEvents -= events; + while (events != 0) { + bit = ((events ^ (events-1)) + 1) >> 1; + EVENT(handle, bit, CS_EVENT_PRI_LOW); + events -= bit; + } + return CS_SUCCESS; +} /* set_event_mask */ + +/*====================================================================*/ + +static int report_error(client_handle_t handle, error_info_t *err) +{ + int i; + char *serv; + + if (CHECK_HANDLE(handle)) + printk(KERN_NOTICE); + else + printk(KERN_NOTICE "%s: ", handle->dev_info); + + for (i = 0; i < SERVICE_COUNT; i++) + if (service_table[i].key == err->func) break; + if (i < SERVICE_COUNT) + serv = service_table[i].msg; + else + serv = "Unknown service number"; + + for (i = 0; i < ERROR_COUNT; i++) + if (error_table[i].key == err->retcode) break; + if (i < ERROR_COUNT) + printk("%s: %s\n", serv, error_table[i].msg); + else + printk("%s: Unknown error code %#x\n", serv, err->retcode); + + return CS_SUCCESS; +} /* report_error */ + +/*====================================================================*/ + +int CardServices(int func, void *a1, void *a2, void *a3) +{ + +#ifdef PCMCIA_DEBUG + if (pc_debug > 1) { + int i; + for (i = 0; i < SERVICE_COUNT; i++) + if (service_table[i].key == func) break; + if (i < SERVICE_COUNT) + printk(KERN_DEBUG "cs: CardServices(%s, 0x%p, 0x%p)\n", + service_table[i].msg, a1, a2); + else + printk(KERN_DEBUG "cs: CardServices(Unknown func %d, " + "0x%p, 0x%p)\n", func, a1, a2); + } +#endif + switch (func) { + case AccessConfigurationRegister: + return access_configuration_register(a1, a2); break; + case AdjustResourceInfo: + return adjust_resource_info(a1, a2); break; + case CheckEraseQueue: + return check_erase_queue(a1); break; + case CloseMemory: + return close_memory(a1); break; + case CopyMemory: + return copy_memory(a1, a2); break; + case DeregisterClient: + return deregister_client(a1); break; + case DeregisterEraseQueue: + return deregister_erase_queue(a1); break; + case GetFirstClient: + return get_first_client(a1, a2); break; + case GetCardServicesInfo: + return get_card_services_info(a1); break; + case GetConfigurationInfo: + return get_configuration_info(a1, a2); break; + case GetNextClient: + return get_next_client(a1, a2); break; + case GetFirstRegion: + return get_first_region(a1, a2); break; + case GetFirstTuple: + return get_first_tuple(a1, a2); break; + case GetNextRegion: + return get_next_region(a1, a2); break; + case GetNextTuple: + return get_next_tuple(a1, a2); break; + case GetStatus: + return get_status(a1, a2); break; + case GetTupleData: + return get_tuple_data(a1, a2); break; + case MapMemPage: + return map_mem_page(a1, a2); break; + case ModifyConfiguration: + return modify_configuration(a1, a2); break; + case ModifyWindow: + return modify_window(a1, a2); break; + case OpenMemory: + return open_memory(a1, a2); + case ParseTuple: + return parse_tuple(a1, a2, a3); break; + case ReadMemory: + return read_memory(a1, a2, a3); break; + case RegisterClient: + return register_client(a1, a2); break; + case RegisterEraseQueue: + return register_erase_queue(a1, a2); break; + case RegisterMTD: + return register_mtd(a1, a2); break; + case ReleaseConfiguration: + return release_configuration(a1, a2); break; + case ReleaseIO: + return release_io(a1, a2); break; + case ReleaseIRQ: + return cs_release_irq(a1, a2); break; + case ReleaseWindow: + return release_window(a1); break; + case RequestConfiguration: + return request_configuration(a1, a2); break; + case RequestIO: + return request_io(a1, a2); break; + case RequestIRQ: + return cs_request_irq(a1, a2); break; + case RequestWindow: + return request_window(a1, a2); break; + case ResetCard: + return reset_card(a1, a2); break; + case SetEventMask: + return set_event_mask(a1, a2); break; + case ValidateCIS: + return validate_cis(a1, a2); break; + case WriteMemory: + return write_memory(a1, a2, a3); break; + case BindDevice: + return bind_device(a1); break; + case BindMTD: + return bind_mtd(a1); break; + case ReportError: + return report_error(a1, a2); break; + case SuspendCard: + return suspend_card(a1, a2); break; + case ResumeCard: + return resume_card(a1, a2); break; + case EjectCard: + return eject_card(a1, a2); break; + case InsertCard: + return insert_card(a1, a2); break; + case ReplaceCIS: + return replace_cis(a1, a2); break; + case GetFirstWindow: + return get_first_window(a1, a2); break; + case GetNextWindow: + return get_next_window(a1, a2); break; + case GetMemPage: + return get_mem_page(a1, a2); break; + default: + return CS_UNSUPPORTED_FUNCTION; break; + } + +} /* CardServices */ + +/*====================================================================== + + OS-specific module glue goes here + +======================================================================*/ + +EXPORT_SYMBOL(register_ss_entry); +EXPORT_SYMBOL(unregister_ss_entry); +EXPORT_SYMBOL(CardServices); +EXPORT_SYMBOL(MTDHelperEntry); + +static int pcmcia_cs_init(void) +{ + printk(KERN_INFO "%s\n", release); + printk(KERN_INFO " %s\n", options); + DEBUG(0, "%s\n", version); +#ifdef CONFIG_APM + if (do_apm) + apm_register_callback(&handle_apm_event); +#endif +#ifdef CONFIG_PROC_FS + proc_pccard = create_proc_entry("pccard", S_IFDIR, proc_bus); +#endif + return 0; +} + +#ifdef MODULE + +int init_module(void) +{ + return pcmcia_cs_init(); +} + +void cleanup_module(void) +{ + printk(KERN_INFO "unloading PCMCIA Card Services\n"); +#ifdef CONFIG_PROC_FS + if (proc_pccard) { + remove_proc_entry("pccard", proc_bus); + } +#endif +#ifdef CONFIG_APM + if (do_apm) + apm_unregister_callback(&handle_apm_event); +#endif + release_resource_db(); +} + +#else + +extern int pcmcia_ds_init(void); +extern int pcmcia_i82365_init(void); + +int pcmcia_init(void) +{ + /* Start core services */ + pcmcia_cs_init(); + + /* Load the socket drivers */ + pcmcia_i82365_init(); + + /* Get the ball rolling.. */ + return pcmcia_ds_init(); +} + +#endif + +/*====================================================================*/ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h --- v2.3.16/linux/drivers/pcmcia/cs_internal.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/cs_internal.h Tue Sep 7 11:48:46 1999 @@ -0,0 +1,280 @@ +/* + * cs_internal.h 1.43 1999/09/07 15:19:04 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + */ + +#ifndef _LINUX_CS_INTERNAL_H +#define _LINUX_CS_INTERNAL_H + +typedef struct erase_busy_t { + eraseq_entry_t *erase; + client_handle_t client; + struct timer_list timeout; + struct erase_busy_t *prev, *next; +} erase_busy_t; + +#define ERASEQ_MAGIC 0xFA67 +typedef struct eraseq_t { + u_short eraseq_magic; + client_handle_t handle; + int count; + eraseq_entry_t *entry; +} eraseq_t; + +#define CLIENT_MAGIC 0x51E6 +typedef struct client_t { + u_short client_magic; + socket_t Socket; + u_char Function; + dev_info_t dev_info; + u_int Attributes; + u_int state; + event_t EventMask, PendingEvents; + int (*event_handler)(event_t event, int priority, + event_callback_args_t *); + event_callback_args_t event_callback_args; + struct client_t *next; + u_int mtd_count; + wait_queue_head_t mtd_req; + erase_busy_t erase_busy; +} client_t; + +/* Flags in client state */ +#define CLIENT_CONFIG_LOCKED 0x0001 +#define CLIENT_IRQ_REQ 0x0002 +#define CLIENT_IO_REQ 0x0004 +#define CLIENT_UNBOUND 0x0008 +#define CLIENT_STALE 0x0010 +#define CLIENT_WIN_REQ(i) (0x20<<(i)) +#define CLIENT_CARDBUS 0x8000 + +typedef struct io_window_t { + u_int Attributes; + ioaddr_t BasePort, NumPorts; + ioaddr_t InUse, Config; +} io_window_t; + +#define WINDOW_MAGIC 0xB35C +typedef struct window_t { + u_short magic; + u_short index; + client_handle_t handle; + struct socket_info_t *sock; + u_long base; + u_long size; + pccard_mem_map ctl; +} window_t; + +#define REGION_MAGIC 0xE3C9 +typedef struct region_t { + u_short region_magic; + u_short state; + dev_info_t dev_info; + client_handle_t mtd; + u_int MediaID; + region_info_t info; +} region_t; + +#define REGION_STALE 0x01 + +/* Each card function gets one of these guys */ +typedef struct config_t { + u_int state; + u_int Attributes; + u_int Vcc, Vpp1, Vpp2; + u_int IntType; + u_int ConfigBase; + u_char Status, Pin, Copy, Option, ExtStatus; + u_int Present; + u_int CardValues; + io_req_t io; + struct { + u_int Attributes; + } irq; +} config_t; + +/* Maximum number of IO windows per socket */ +#define MAX_IO_WIN 2 + +/* Maximum number of memory windows per socket */ +#define MAX_WIN 4 + +/* The size of the CIS cache */ +#define MAX_CIS_TABLE 64 +#define MAX_CIS_DATA 512 + +typedef struct socket_info_t { + spinlock_t lock; + ss_entry_t ss_entry; + u_int sock; + socket_state_t socket; + socket_cap_t cap; + u_int state; + u_short functions; + u_short lock_count; + client_handle_t clients; + u_int real_clients; + client_handle_t reset_handle; + struct timer_list setup, shutdown; + u_long unreset_timeout; + pccard_mem_map cis_mem; + u_char *cis_virt; + config_t *config; +#ifdef CONFIG_CARDBUS + u_int cb_cis_space; + cb_bridge_map cb_cis_map; + u_char *cb_cis_virt; + struct cb_config_t *cb_config; +#endif + struct { + u_int AssignedIRQ; + u_int Config; + } irq; + io_window_t io[MAX_IO_WIN]; + window_t win[MAX_WIN]; + region_t *c_region, *a_region; + erase_busy_t erase_busy; + int cis_used; + struct { + u_int addr; + u_short len; + u_short attr; + } cis_table[MAX_CIS_TABLE]; + char cis_cache[MAX_CIS_DATA]; + u_int fake_cis_len; + char *fake_cis; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc; +#endif +} socket_info_t; + +/* Flags in config state */ +#define CONFIG_LOCKED 0x01 +#define CONFIG_IRQ_REQ 0x02 +#define CONFIG_IO_REQ 0x04 + +/* Flags in socket state */ +#define SOCKET_PRESENT 0x0008 +#define SOCKET_SETUP_PENDING 0x0010 +#define SOCKET_SHUTDOWN_PENDING 0x0020 +#define SOCKET_RESET_PENDING 0x0040 +#define SOCKET_SUSPEND 0x0080 +#define SOCKET_WIN_REQ(i) (0x0100<<(i)) +#define SOCKET_IO_REQ(i) (0x1000<<(i)) +#define SOCKET_REGION_INFO 0x4000 +#define SOCKET_CARDBUS 0x8000 + +#define CHECK_HANDLE(h) \ + (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC)) + +#define CHECK_SOCKET(s) \ + (((s) >= sockets) || (socket_table[s]->ss_entry == NULL)) + +#define SOCKET(h) (socket_table[(h)->Socket]) +#define CONFIG(h) (&SOCKET(h)->config[(h)->Function]) + +#define CHECK_REGION(r) \ + (((r) == NULL) || ((r)->region_magic != REGION_MAGIC)) + +#define CHECK_ERASEQ(q) \ + (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC)) + +#define EVENT(h, e, p) \ + ((h)->event_handler((e), (p), &(h)->event_callback_args)) + +/* In cardbus.c */ +int cb_alloc(socket_info_t *s); +void cb_free(socket_info_t *s); +int cb_config(socket_info_t *s); +void cb_release(socket_info_t *s); +void cb_enable(socket_info_t *s); +void cb_disable(socket_info_t *s); +void read_cb_mem(socket_info_t *s, u_char fn, int space, + u_int addr, u_int len, void *ptr); +int cb_setup_cis_mem(socket_info_t *s, int space); +void cb_release_cis_mem(socket_info_t *s); + +/* In cistpl.c */ +void read_cis_mem(socket_info_t *s, int attr, + u_int addr, u_int len, void *ptr); +void write_cis_mem(socket_info_t *s, int attr, + u_int addr, u_int len, void *ptr); +int setup_cis_mem(socket_info_t *s); +void release_cis_mem(socket_info_t *s); +int verify_cis_cache(socket_info_t *s); +void preload_cis_cache(socket_info_t *s); +int get_first_tuple(client_handle_t handle, tuple_t *tuple); +int get_next_tuple(client_handle_t handle, tuple_t *tuple); +int get_tuple_data(client_handle_t handle, tuple_t *tuple); +int parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse); +int validate_cis(client_handle_t handle, cisinfo_t *info); +int replace_cis(client_handle_t handle, cisdump_t *cis); +int read_tuple(client_handle_t handle, cisdata_t code, void *parse); + +/* In bulkmem.c */ +void retry_erase_list(struct erase_busy_t *list, u_int cause); +int get_first_region(client_handle_t handle, region_info_t *rgn); +int get_next_region(client_handle_t handle, region_info_t *rgn); +int register_mtd(client_handle_t handle, mtd_reg_t *reg); +int register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header); +int deregister_erase_queue(eraseq_handle_t eraseq); +int check_erase_queue(eraseq_handle_t eraseq); +int open_memory(client_handle_t *handle, open_mem_t *open); +int close_memory(memory_handle_t handle); +int read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf); +int write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf); +int copy_memory(memory_handle_t handle, copy_op_t *req); + +/* In rsrc_mgr */ +void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), + int force_low); +int find_io_region(ioaddr_t *base, ioaddr_t num, char *name); +int find_mem_region(u_long *base, u_long num, char *name, + u_long align, int force_low); +int try_irq(u_int Attributes, int irq, int specific); +void undo_irq(u_int Attributes, int irq); +int adjust_resource_info(client_handle_t handle, adjust_t *adj); +void release_resource_db(void); +int proc_read_io(char *buf, char **start, off_t pos, + int count, int *eof, void *data); +int proc_read_mem(char *buf, char **start, off_t pos, + int count, int *eof, void *data); + +/* in pnp components */ +int proc_read_irq(char *buf, char **start, off_t pos, + int count, int *eof, void *data); +void pnp_bios_init(void); +void pnp_proc_init(void); +void pnp_proc_done(void); +void pnp_rsrc_init(void); +void pnp_rsrc_done(void); + +#define MAX_SOCK 8 +extern socket_t sockets; +extern socket_info_t *socket_table[MAX_SOCK]; + +#ifdef CONFIG_PROC_FS +extern struct proc_dir_entry *proc_pccard; +#endif + +#ifdef PCMCIA_DEBUG +extern int pc_debug; +#define DEBUG(n, args...) do { if (pc_debug>(n)) printk(args); } while (0) +#else +#define DEBUG(n, args...) do { } while (0) +#endif + +#endif /* _LINUX_CS_INTERNAL_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c --- v2.3.16/linux/drivers/pcmcia/ds.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/ds.c Tue Sep 7 11:03:10 1999 @@ -0,0 +1,898 @@ +/*====================================================================== + + PC Card Driver Services + + ds.c 1.96 1999/09/02 18:35:34 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef PCMCIA_DEBUG +int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static const char *version = +"ds.c 1.96 1999/09/02 18:35:34 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +typedef struct driver_info_t { + dev_info_t dev_info; + int use_count; + dev_link_t *(*attach)(void); + void (*detach)(dev_link_t *); + struct driver_info_t *next; +} driver_info_t; + +typedef struct socket_bind_t { + driver_info_t *driver; + dev_link_t *instance; + struct socket_bind_t *next; +} socket_bind_t; + +/* Device user information */ +#define MAX_EVENTS 32 +#define USER_MAGIC 0x7ea4 +#define CHECK_USER(u) \ + (((u) == NULL) || ((u)->user_magic != USER_MAGIC)) +typedef struct user_info_t { + u_int user_magic; + int event_head, event_tail; + event_t event[MAX_EVENTS]; + struct user_info_t *next; +} user_info_t; + +/* Socket state information */ +typedef struct socket_info_t { + client_handle_t handle; + int state; + user_info_t *user; + int req_pending, req_result; + wait_queue_head_t queue, request; + struct timer_list removal; + socket_bind_t *bind; +} socket_info_t; + +#define SOCKET_PRESENT 0x01 +#define SOCKET_BUSY 0x02 +#define SOCKET_REMOVAL_PENDING 0x10 + +/*====================================================================*/ + +/* Device driver ID passed to Card Services */ +static dev_info_t dev_info = "Driver Services"; + +/* Linked list of all registered device drivers */ +static driver_info_t *root_driver = NULL; + +static int sockets = 0, major_dev = -1; +static socket_info_t *socket_table = NULL; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + Register_pccard_driver() and unregister_pccard_driver() are used + tell Driver Services that a PC Card client driver is available to + be bound to sockets. + +======================================================================*/ + +int register_pccard_driver(dev_info_t *dev_info, + dev_link_t *(*attach)(void), + void (*detach)(dev_link_t *)) +{ + driver_info_t *driver; + socket_bind_t *b; + int i; + + DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info); + for (driver = root_driver; driver; driver = driver->next) + if (strncmp((char *)dev_info, (char *)driver->dev_info, + DEV_NAME_LEN) == 0) + break; + if (!driver) { + driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL); + strncpy(driver->dev_info, (char *)dev_info, DEV_NAME_LEN); + driver->use_count = 0; + driver->next = root_driver; + root_driver = driver; + } + + driver->attach = attach; + driver->detach = detach; + if (driver->use_count == 0) return 0; + + /* Instantiate any already-bound devices */ + for (i = 0; i < sockets; i++) + for (b = socket_table[i].bind; b; b = b->next) { + if (b->driver != driver) continue; + b->instance = driver->attach(); + if (b->instance == NULL) + printk(KERN_NOTICE "ds: unable to create instance " + "of '%s'!\n", driver->dev_info); + } + + return 0; +} /* register_pccard_driver */ + +/*====================================================================*/ + +int unregister_pccard_driver(dev_info_t *dev_info) +{ + driver_info_t *target, **d = &root_driver; + socket_bind_t *b; + int i; + + DEBUG(0, "ds: unregister_pccard_driver('%s')\n", + (char *)dev_info); + while ((*d) && (strncmp((*d)->dev_info, (char *)dev_info, + DEV_NAME_LEN) != 0)) + d = &(*d)->next; + if (*d == NULL) + return -1; + + target = *d; + if (target->use_count == 0) { + *d = target->next; + kfree(target); + } else { + /* Blank out any left-over device instances */ + target->attach = NULL; target->detach = NULL; + for (i = 0; i < sockets; i++) + for (b = socket_table[i].bind; b; b = b->next) + if (b->driver == target) b->instance = NULL; + } + return 0; +} /* unregister_pccard_driver */ + +/*====================================================================== + + These manage a ring buffer of events pending for one user process + +======================================================================*/ + +static int queue_empty(user_info_t *user) +{ + return (user->event_head == user->event_tail); +} + +static event_t get_queued_event(user_info_t *user) +{ + user->event_tail = (user->event_tail+1) % MAX_EVENTS; + return user->event[user->event_tail]; +} + +static void queue_event(user_info_t *user, event_t event) +{ + user->event_head = (user->event_head+1) % MAX_EVENTS; + if (user->event_head == user->event_tail) + user->event_tail = (user->event_tail+1) % MAX_EVENTS; + user->event[user->event_head] = event; +} + +static void handle_event(socket_info_t *s, event_t event) +{ + user_info_t *user; + for (user = s->user; user; user = user->next) + queue_event(user, event); + wake_up_interruptible(&s->queue); +} + +static int handle_request(socket_info_t *s, event_t event) +{ + if (s->req_pending != 0) + return CS_IN_USE; + if (s->state & SOCKET_BUSY) + s->req_pending = 1; + handle_event(s, event); + if (s->req_pending > 0) { + interruptible_sleep_on(&s->request); + if (signal_pending(current)) + return CS_IN_USE; + else + return s->req_result; + } + return CS_SUCCESS; +} + +static void handle_removal(u_long sn) +{ + socket_info_t *s = &socket_table[sn]; + handle_event(s, CS_EVENT_CARD_REMOVAL); + s->state &= ~SOCKET_REMOVAL_PENDING; +} + +/*====================================================================== + + The card status event handler. + +======================================================================*/ + +static int ds_event(event_t event, int priority, + event_callback_args_t *args) +{ + socket_info_t *s; + int i; + + DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n", + event, priority, args->client_handle); + s = args->client_data; + i = s - socket_table; + + switch (event) { + + case CS_EVENT_CARD_REMOVAL: + s->state &= ~SOCKET_PRESENT; + if (!(s->state & SOCKET_REMOVAL_PENDING)) { + s->state |= SOCKET_REMOVAL_PENDING; + s->removal.expires = jiffies + HZ/10; + add_timer(&s->removal); + } + break; + + case CS_EVENT_CARD_INSERTION: + s->state |= SOCKET_PRESENT; + handle_event(s, event); + break; + + case CS_EVENT_EJECTION_REQUEST: + return handle_request(s, event); + break; + + default: + handle_event(s, event); + break; + } + + return 0; +} /* ds_event */ + +/*====================================================================== + + bind_mtd() connects a memory region with an MTD client. + +======================================================================*/ + +static int bind_mtd(int i, mtd_info_t *mtd_info) +{ + mtd_bind_t bind_req; + int ret; + + bind_req.dev_info = &mtd_info->dev_info; + bind_req.Attributes = mtd_info->Attributes; + bind_req.Socket = i; + bind_req.CardOffset = mtd_info->CardOffset; + ret = CardServices(BindMTD, &bind_req); + if (ret != CS_SUCCESS) { + cs_error(NULL, BindMTD, ret); + printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d" + " offset 0x%x\n", + (char *)bind_req.dev_info, i, bind_req.CardOffset); + return -ENODEV; + } + return 0; +} /* bind_mtd */ + +/*====================================================================== + + bind_request() connects a socket to a particular client driver. + It looks up the specified device ID in the list of registered + drivers, binds it to the socket, and tries to create an instance + of the device. unbind_request() deletes a driver instance. + +======================================================================*/ + +static int bind_request(int i, bind_info_t *bind_info) +{ + struct driver_info_t *driver; + socket_bind_t *b; + bind_req_t bind_req; + socket_info_t *s = &socket_table[i]; + int ret; + + DEBUG(2, "bind_request(%d, '%s')\n", i, + (char *)bind_info->dev_info); + for (driver = root_driver; driver; driver = driver->next) + if (strcmp((char *)driver->dev_info, + (char *)bind_info->dev_info) == 0) + break; + if (driver == NULL) { + driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL); + strncpy(driver->dev_info, bind_info->dev_info, DEV_NAME_LEN); + driver->use_count = 0; + driver->next = root_driver; + driver->attach = NULL; driver->detach = NULL; + root_driver = driver; + } + + for (b = s->bind; b; b = b->next) + if (driver == b->driver) + break; + if (b != NULL) { + bind_info->instance = b->instance; + return -EBUSY; + } + + bind_req.Socket = i; + bind_req.Function = bind_info->function; + bind_req.dev_info = &driver->dev_info; + ret = CardServices(BindDevice, &bind_req); + if (ret != CS_SUCCESS) { + cs_error(NULL, BindDevice, ret); + printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n", + (char *)dev_info, i); + return -ENODEV; + } + + /* Add binding to list for this socket */ + driver->use_count++; + b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL); + b->driver = driver; + b->instance = NULL; + b->next = s->bind; + s->bind = b; + + if (driver->attach) { + b->instance = driver->attach(); + if (b->instance == NULL) { + printk(KERN_NOTICE "ds: unable to create instance " + "of '%s'!\n", (char *)bind_info->dev_info); + return -ENODEV; + } + } + + return 0; +} /* bind_request */ + +/*====================================================================*/ + +static int get_device_info(int i, bind_info_t *bind_info, int first) +{ + socket_info_t *s = &socket_table[i]; + socket_bind_t *b; + dev_node_t *node; + + for (b = s->bind; b; b = b->next) + if (strcmp((char *)b->driver->dev_info, + (char *)bind_info->dev_info) == 0) + break; + if (b == NULL) return -ENODEV; + if ((b->instance == NULL) || + (b->instance->state & DEV_CONFIG_PENDING)) + return -EAGAIN; + if (first) + node = b->instance->dev; + else + for (node = b->instance->dev; node; node = node->next) + if (node == bind_info->next) break; + if (node == NULL) return -ENODEV; + + strncpy(bind_info->name, node->dev_name, DEV_NAME_LEN); + bind_info->name[DEV_NAME_LEN-1] = '\0'; + bind_info->major = node->major; + bind_info->minor = node->minor; + bind_info->next = node->next; + + return 0; +} /* get_device_info */ + +/*====================================================================*/ + +static int unbind_request(int i, bind_info_t *bind_info) +{ + socket_info_t *s = &socket_table[i]; + socket_bind_t **b, *c; + + DEBUG(2, "unbind_request(%d, '%s')\n", i, + (char *)bind_info->dev_info); + for (b = &s->bind; *b; b = &(*b)->next) + if (strcmp((char *)(*b)->driver->dev_info, + (char *)bind_info->dev_info) == 0) + break; + if (*b == NULL) + return -ENODEV; + + c = *b; + c->driver->use_count--; + if (c->driver->detach) { + if (c->instance) + c->driver->detach(c->instance); + } else { + if (c->driver->use_count == 0) { + driver_info_t **d; + for (d = &root_driver; *d; d = &((*d)->next)) + if (c->driver == *d) break; + *d = (*d)->next; + kfree_s(c->driver, sizeof(driver_info_t)); + } + } + *b = c->next; + kfree_s(c, sizeof(socket_bind_t)); + + return 0; +} /* unbind_request */ + +/*====================================================================== + + The user-mode PC Card device interface + +======================================================================*/ + +static int ds_open(struct inode *inode, struct file *file) +{ + socket_t i = MINOR(inode->i_rdev); + socket_info_t *s; + user_info_t *user; + + DEBUG(0, "ds_open(socket %d)\n", i); + if ((i >= sockets) || (sockets == 0)) + return -ENODEV; + s = &socket_table[i]; + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if (s->state & SOCKET_BUSY) + return -EBUSY; + else + s->state |= SOCKET_BUSY; + } + + MOD_INC_USE_COUNT; + user = kmalloc(sizeof(user_info_t), GFP_KERNEL); + user->event_tail = user->event_head = 0; + user->next = s->user; + user->user_magic = USER_MAGIC; + s->user = user; + file->private_data = user; + + if (s->state & SOCKET_PRESENT) + queue_event(user, CS_EVENT_CARD_INSERTION); + return 0; +} /* ds_open */ + +/*====================================================================*/ + +static int ds_release(struct inode *inode, struct file *file) +{ + socket_t i = MINOR(inode->i_rdev); + socket_info_t *s; + user_info_t *user, **link; + + DEBUG(0, "ds_release(socket %d)\n", i); + if ((i >= sockets) || (sockets == 0)) + return 0; + s = &socket_table[i]; + user = file->private_data; + if (CHECK_USER(user)) + return 0; + + /* Unlink user data structure */ + if ((file->f_flags & O_ACCMODE) != O_RDONLY) + s->state &= ~SOCKET_BUSY; + file->private_data = NULL; + for (link = &s->user; *link; link = &(*link)->next) + if (*link == user) break; + if (link == NULL) + return 0; + *link = user->next; + user->user_magic = 0; + kfree_s(user, sizeof(user_info_t)); + + MOD_DEC_USE_COUNT; + return 0; +} /* ds_release */ + +/*====================================================================*/ + +static ssize_t ds_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + socket_t i = MINOR(file->f_dentry->d_inode->i_rdev); + socket_info_t *s; + user_info_t *user; + + DEBUG(2, "ds_read(socket %d)\n", i); + + if ((i >= sockets) || (sockets == 0)) + return -ENODEV; + if (count < 4) + return -EINVAL; + s = &socket_table[i]; + user = file->private_data; + if (CHECK_USER(user)) + return -EIO; + + if (queue_empty(user)) { + interruptible_sleep_on(&s->queue); + if (signal_pending(current)) + return -EINTR; + } + put_user(get_queued_event(user), (int *)buf); + return 4; +} /* ds_read */ + +/*====================================================================*/ + +static ssize_t ds_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + socket_t i = MINOR(file->f_dentry->d_inode->i_rdev); + socket_info_t *s; + user_info_t *user; + + DEBUG(2, "ds_write(socket %d)\n", i); + + if ((i >= sockets) || (sockets == 0)) + return -ENODEV; + if (count != 4) + return -EINVAL; + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + return -EBADF; + s = &socket_table[i]; + user = file->private_data; + if (CHECK_USER(user)) + return -EIO; + + if (s->req_pending) { + s->req_pending--; + get_user(s->req_result, (int *)buf); + if ((s->req_result != 0) || (s->req_pending == 0)) + wake_up_interruptible(&s->request); + } else + return -EIO; + + return 4; +} /* ds_write */ + +/*====================================================================*/ + +static u_int ds_poll(struct file *file, poll_table *wait) +{ + socket_t i = MINOR(file->f_dentry->d_inode->i_rdev); + socket_info_t *s; + user_info_t *user; + + DEBUG(2, "ds_poll(socket %d)\n", i); + + if ((i >= sockets) || (sockets == 0)) + return POLLERR; + s = &socket_table[i]; + user = file->private_data; + if (CHECK_USER(user)) + return POLLERR; + poll_wait(file, &s->queue, wait); + if (!queue_empty(user)) + return POLLIN | POLLRDNORM; + return 0; +} /* ds_poll */ + +/*====================================================================*/ + +static int ds_ioctl(struct inode * inode, struct file * file, + u_int cmd, u_long arg) +{ + socket_t i = MINOR(inode->i_rdev); + socket_info_t *s; + u_int size; + int ret, err; + ds_ioctl_arg_t buf; + + DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg); + + if ((i >= sockets) || (sockets == 0)) + return -ENODEV; + s = &socket_table[i]; + + size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; + if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; + + /* Permission check */ + if (!(cmd & IOC_OUT) && !suser()) + return -EPERM; + + if (cmd & IOC_IN) { + err = verify_area(VERIFY_READ, (char *)arg, size); + if (err) { + DEBUG(3, "ds_ioctl(): verify_read = %d\n", err); + return err; + } + } + if (cmd & IOC_OUT) { + err = verify_area(VERIFY_WRITE, (char *)arg, size); + if (err) { + DEBUG(3, "ds_ioctl(): verify_write = %d\n", err); + return err; + } + } + + err = ret = 0; + + if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size); + + switch (cmd) { + case DS_ADJUST_RESOURCE_INFO: + ret = CardServices(AdjustResourceInfo, s->handle, &buf.adjust); + break; + case DS_GET_CARD_SERVICES_INFO: + ret = CardServices(GetCardServicesInfo, &buf.servinfo); + break; + case DS_GET_CONFIGURATION_INFO: + ret = CardServices(GetConfigurationInfo, s->handle, &buf.config); + break; + case DS_GET_FIRST_TUPLE: + ret = CardServices(GetFirstTuple, s->handle, &buf.tuple); + break; + case DS_GET_NEXT_TUPLE: + ret = CardServices(GetNextTuple, s->handle, &buf.tuple); + break; + case DS_GET_TUPLE_DATA: + buf.tuple.TupleData = buf.tuple_parse.data; + buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data); + ret = CardServices(GetTupleData, s->handle, &buf.tuple); + break; + case DS_PARSE_TUPLE: + buf.tuple.TupleData = buf.tuple_parse.data; + ret = CardServices(ParseTuple, s->handle, &buf.tuple, + &buf.tuple_parse.parse); + break; + case DS_RESET_CARD: + ret = CardServices(ResetCard, s->handle, NULL); + break; + case DS_GET_STATUS: + ret = CardServices(GetStatus, s->handle, &buf.status); + break; + case DS_VALIDATE_CIS: + ret = CardServices(ValidateCIS, s->handle, &buf.cisinfo); + break; + case DS_SUSPEND_CARD: + ret = CardServices(SuspendCard, s->handle, NULL); + break; + case DS_RESUME_CARD: + ret = CardServices(ResumeCard, s->handle, NULL); + break; + case DS_EJECT_CARD: + ret = CardServices(EjectCard, s->handle, NULL); + break; + case DS_INSERT_CARD: + ret = CardServices(InsertCard, s->handle, NULL); + break; + case DS_ACCESS_CONFIGURATION_REGISTER: + if ((buf.conf_reg.Action == CS_WRITE) && !suser()) + return -EPERM; + ret = CardServices(AccessConfigurationRegister, s->handle, + &buf.conf_reg); + break; + case DS_GET_FIRST_REGION: + ret = CardServices(GetFirstRegion, s->handle, &buf.region); + break; + case DS_GET_NEXT_REGION: + ret = CardServices(GetNextRegion, s->handle, &buf.region); + break; + case DS_GET_FIRST_WINDOW: + buf.win_info.handle = (window_handle_t)s->handle; + ret = CardServices(GetFirstWindow, &buf.win_info.handle, + &buf.win_info.window); + break; + case DS_GET_NEXT_WINDOW: + ret = CardServices(GetNextWindow, &buf.win_info.handle, + &buf.win_info.window); + break; + case DS_GET_MEM_PAGE: + ret = CardServices(GetMemPage, buf.win_info.handle, + &buf.win_info.map); + break; + case DS_REPLACE_CIS: + ret = CardServices(ReplaceCIS, s->handle, &buf.cisdump); + break; + case DS_BIND_REQUEST: + if (!suser()) return -EPERM; + err = bind_request(i, &buf.bind_info); + break; + case DS_GET_DEVICE_INFO: + err = get_device_info(i, &buf.bind_info, 1); + break; + case DS_GET_NEXT_DEVICE: + err = get_device_info(i, &buf.bind_info, 0); + break; + case DS_UNBIND_REQUEST: + err = unbind_request(i, &buf.bind_info); + break; + case DS_BIND_MTD: + if (!suser()) return -EPERM; + err = bind_mtd(i, &buf.mtd_info); + break; + default: + err = -EINVAL; + } + + if ((err == 0) && (ret != CS_SUCCESS)) { + DEBUG(2, "ds_ioctl: ret = %d\n", ret); + switch (ret) { + case CS_BAD_SOCKET: case CS_NO_CARD: + err = -ENODEV; break; + case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ: + case CS_BAD_TUPLE: + err = -EINVAL; break; + case CS_IN_USE: + err = -EBUSY; break; + case CS_OUT_OF_RESOURCE: + err = -ENOSPC; break; + case CS_NO_MORE_ITEMS: + err = -ENODATA; break; + case CS_UNSUPPORTED_FUNCTION: + err = -ENOSYS; break; + default: + err = -EIO; break; + } + } + + if (cmd & IOC_OUT) copy_to_user((char *)arg, (char *)&buf, size); + + return err; +} /* ds_ioctl */ + +/*====================================================================*/ + +static struct file_operations ds_fops = { + NULL, /* lseek */ + ds_read, /* read */ + ds_write, /* write */ + NULL, /* readdir */ + ds_poll, /* poll */ + ds_ioctl, /* ioctl */ + NULL, /* mmap */ + ds_open, /* open */ + NULL, /* flush */ + ds_release, /* release */ + NULL /* fsync */ +}; + +EXPORT_SYMBOL(register_pccard_driver); +EXPORT_SYMBOL(unregister_pccard_driver); + +/*====================================================================*/ + +int pcmcia_ds_init(void) +{ + client_reg_t client_reg; + servinfo_t serv; + bind_req_t bind; + socket_info_t *s; + int i, ret; + + DEBUG(0, "%s\n", version); + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "ds: Card Services release does not match!\n"); + return -1; + } + if (serv.Count == 0) { + printk(KERN_NOTICE "ds: no socket drivers loaded!\n"); + return -1; + } + + sockets = serv.Count; + socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL); + for (i = 0, s = socket_table; i < sockets; i++, s++) { + s->state = 0; + s->user = NULL; + s->req_pending = 0; + init_waitqueue_head(&s->queue); + init_waitqueue_head(&s->request); + s->handle = NULL; + s->removal.prev = s->removal.next = NULL; + s->removal.data = i; + s->removal.function = &handle_removal; + s->bind = NULL; + } + + /* Set up hotline to Card Services */ + client_reg.dev_info = bind.dev_info = &dev_info; + client_reg.Attributes = INFO_MASTER_CLIENT; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &ds_event; + client_reg.Version = 0x0210; + for (i = 0; i < sockets; i++) { + bind.Socket = i; + bind.Function = BIND_FN_ALL; + ret = CardServices(BindDevice, &bind); + if (ret != CS_SUCCESS) { + cs_error(NULL, BindDevice, ret); + break; + } + client_reg.event_callback_args.client_data = &socket_table[i]; + ret = CardServices(RegisterClient, &socket_table[i].handle, + &client_reg); + if (ret != CS_SUCCESS) { + cs_error(NULL, RegisterClient, ret); + break; + } + } + + /* Set up character device for user mode clients */ + i = register_chrdev(0, "pcmcia", &ds_fops); + if (i == -EBUSY) + printk(KERN_NOTICE "unable to find a free device # for " + "Driver Services\n"); + else + major_dev = i; + + return 0; +} + +#ifdef MODULE + +static int init_module(void) +{ + return pcmcia_ds_init(); +} + +void cleanup_module(void) +{ + int i; + if (major_dev != -1) + unregister_chrdev(major_dev, "pcmcia"); + for (i = 0; i < sockets; i++) + CardServices(DeregisterClient, socket_table[i].handle); + sockets = 0; + kfree(socket_table); +} + +#endif diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c --- v2.3.16/linux/drivers/pcmcia/i82365.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/i82365.c Tue Sep 7 11:50:40 1999 @@ -0,0 +1,2819 @@ +/*====================================================================== + + Device driver for Intel 82365 and compatible PC Card controllers, + and Yenta-compatible PCI-to-CardBus controllers. + + i82365.c 1.251 1999/09/07 15:19:23 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* ISA-bus controllers */ +#include "i82365.h" +#include "cirrus.h" +#include "vg468.h" +#include "ricoh.h" +#include "o2micro.h" + +/* PCI-bus controllers */ +#include "yenta.h" +#include "ti113x.h" +#include "smc34c90.h" +#include "topic.h" + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) do { if (pc_debug>(n)) printk(KERN_DEBUG args); } while (0) +static const char *version = +"i82365.c $Revision: 1.249 $ $Date: 1999/08/28 04:01:46 $ (David Hinds)"; +#else +#define DEBUG(n, args...) do { } while (0) +#endif + +static void irq_count(int, void *, struct pt_regs *); +static inline int _check_irq(int irq, int flags) +{ + if (request_irq(irq, irq_count, flags, "x", NULL) == 0) { + free_irq(irq, NULL); + return 0; + } + return -1; +} + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +#ifdef CONFIG_ISA +/* Default base address for i82365sl and other ISA chips */ +static int i365_base = 0x3e0; +/* Should we probe at 0x3e2 for an extra ISA controller? */ +static int extra_sockets = 0; +/* Specify a socket number to ignore */ +static int ignore = -1; +/* Bit map or list of interrupts to choose from */ +static u_int irq_mask = 0xffff; +static int irq_list[16] = { -1 }; +/* The card status change interrupt -- 0 means autoselect */ +static int cs_irq = 0; +#endif + +/* Probe for safe interrupts? */ +static int do_scan = 1; +/* Poll status interval -- 0 means default to interrupt */ +static int poll_interval = 0; +/* External clock time, in nanoseconds. 120 ns = 8.33 MHz */ +static int cycle_time = 120; + +/* Cirrus options */ +static int has_dma = -1; +static int has_led = -1; +static int has_ring = -1; +static int dynamic_mode = 0; +static int freq_bypass = -1; +static int setup_time = -1; +static int cmd_time = -1; +static int recov_time = -1; + +#ifdef CONFIG_ISA +/* Vadem options */ +static int async_clock = -1; +static int cable_mode = -1; +static int wakeup = 0; +#endif + +#ifdef CONFIG_ISA +MODULE_PARM(i365_base, "i"); +MODULE_PARM(ignore, "i"); +MODULE_PARM(extra_sockets, "i"); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-16i"); +MODULE_PARM(cs_irq, "i"); +MODULE_PARM(async_clock, "i"); +MODULE_PARM(cable_mode, "i"); +MODULE_PARM(wakeup, "i"); +#endif + +MODULE_PARM(do_scan, "i"); +MODULE_PARM(poll_interval, "i"); +MODULE_PARM(cycle_time, "i"); +MODULE_PARM(has_dma, "i"); +MODULE_PARM(has_led, "i"); +MODULE_PARM(has_ring, "i"); +MODULE_PARM(dynamic_mode, "i"); +MODULE_PARM(freq_bypass, "i"); +MODULE_PARM(setup_time, "i"); +MODULE_PARM(cmd_time, "i"); +MODULE_PARM(recov_time, "i"); + +#ifdef CONFIG_PCI +/* Scan PCI bus? */ +static int do_pci_probe = 1; +/* Default memory base address for CardBus controllers */ +static u_int cb_mem_base[] = { 0x68000000, 0xf8000000 }; +static int fast_pci = -1; +static int hold_time = -1; +/* Override BIOS interrupt routing mode? */ +static int irq_mode = -1; +static int has_clkrun = -1; +static int clkrun_sel = -1; +static int pci_latency = -1; +static int cb_latency = -1; +static int cb_bus_base = 0; +static int cb_bus_step = 2; +static int cb_write_post = -1; +MODULE_PARM(do_pci_probe, "i"); +MODULE_PARM(cb_mem_base, "i"); +MODULE_PARM(fast_pci, "i"); +MODULE_PARM(hold_time, "i"); +MODULE_PARM(irq_mode, "i"); +MODULE_PARM(has_clkrun, "i"); +MODULE_PARM(clkrun_sel, "i"); +MODULE_PARM(pci_latency, "i"); +MODULE_PARM(cb_latency, "i"); +MODULE_PARM(cb_bus_base, "i"); +MODULE_PARM(cb_bus_step, "i"); +MODULE_PARM(cb_write_post, "i"); +#endif + +#ifdef CONFIG_ISA +#ifdef CONFIG_PCI +/* PCI card status change interrupts? */ +static int pci_csc = 0; +/* PCI IO card functional interrupts? */ +static int pci_int = 0; +MODULE_PARM(pci_csc, "i"); +MODULE_PARM(pci_int, "i"); +#else /* no PCI */ +#define pci_csc 0 +#define pci_int 0 +#endif +#else /* no ISA */ +#ifdef CONFIG_PCI +#define pci_csc 0 +#define pci_int 1 +#else +#error "No bus architectures defined!" +#endif +#endif + +/*====================================================================*/ + +typedef struct cirrus_state_t { + u_char misc1, misc2; + u_char timer[6]; +} cirrus_state_t; + +typedef struct vg46x_state_t { + u_char ctl, ema; +} vg46x_state_t; + +typedef struct ti113x_state_t { + u_int sysctl; + u_char cardctl, devctl, diag; +} ti113x_state_t; + +typedef struct rl5c4xx_state_t { + u_short misc, ctl, io, mem; +} rl5c4xx_state_t; + +typedef struct o2micro_state_t { + u_char mode_a, mode_b, mode_c, mode_d; + u_char mhpg, fifo, mode_e; +} o2micro_state_t; + +typedef struct topic_state_t { + u_char slot, ccr, cdr; + u_int rcr; +} topic_state_t; + +typedef struct socket_info_t { + u_short type, flags; + socket_cap_t cap; + u_short ioaddr; + u_short psock; + u_char cs_irq, intr; + void (*handler)(void *info, u_int events); + void *info; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc; +#endif +#ifdef CONFIG_PCI + u_short vendor, device; + u_char revision, bus, devfn; + u_short bcr; + u_char pci_lat, cb_lat, sub_bus; + u_char cache, pmcs; + u_int cb_phys; + char *cb_virt; +#endif + union { + cirrus_state_t cirrus; + vg46x_state_t vg46x; +#ifdef CONFIG_PCI + o2micro_state_t o2micro; + ti113x_state_t ti113x; + rl5c4xx_state_t rl5c4xx; + topic_state_t topic; +#endif + } state; +} socket_info_t; + +/* Where we keep track of our sockets... */ +static int sockets = 0; +static socket_info_t socket[8] = { + { 0, }, /* ... */ +}; + +/* Default ISA interrupt mask */ +#define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */ + +static void pcic_interrupt_wrapper(u_long); +static void pcic_interrupt(int irq, void *dev, + struct pt_regs *regs); +static int pcic_service(u_int sock, u_int cmd, void *arg); +#ifdef CONFIG_PROC_FS +static void pcic_proc_remove(u_short sock); +#endif + +#ifdef CONFIG_ISA +static int grab_irq; +static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED; +#endif +static struct timer_list poll_timer; + +/*====================================================================*/ + +#ifdef CONFIG_PCI + +#ifndef PCI_VENDOR_ID_INTEL +#define PCI_VENDOR_ID_INTEL 0x8086 +#endif +#ifndef PCI_VENDOR_ID_OMEGA +#define PCI_VENDOR_ID_OMEGA 0x119b +#endif +#ifndef PCI_DEVICE_ID_OMEGA_PCMCIA +#define PCI_DEVICE_ID_OMEGA_PCMCIA 0x1221 +#endif + +/* Default settings for PCI command configuration register */ +#define CMD_DFLT (PCI_COMMAND_IO|PCI_COMMAND_MEMORY| \ + PCI_COMMAND_MASTER|PCI_COMMAND_WAIT) + +#endif + +/* These definitions must match the pcic table! */ +typedef enum pcic_id { +#ifdef CONFIG_ISA + IS_I82365A, IS_I82365B, IS_I82365DF, + IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469, + IS_PD6710, IS_PD672X, IS_VT83C469, +#endif +#ifdef CONFIG_PCI + IS_PD6729, IS_PD6730, IS_OZ6729, IS_OZ6730, + IS_I82092AA, IS_OM82C092G, + IS_PD6832, IS_OZ6832, IS_OZ6836, + IS_RL5C465, IS_RL5C466, IS_RL5C475, IS_RL5C476, IS_RL5C478, + IS_SMC34C90, + IS_TI1130, IS_TI1131, IS_TI1250A, IS_TI1220, IS_TI1221, IS_TI1210, + IS_TI1251A, IS_TI1251B, IS_TI1450, IS_TI1225, IS_TI1211, IS_TI1420, + IS_TOPIC95_A, IS_TOPIC95_B, IS_TOPIC97, + IS_UNK_PCI, IS_UNK_CARDBUS +#endif +} pcic_id; + +/* Flags for classifying groups of controllers */ +#define IS_VADEM 0x0001 +#define IS_CIRRUS 0x0002 +#define IS_TI 0x0004 +#define IS_O2MICRO 0x0008 +#define IS_VIA 0x0010 +#define IS_TOPIC 0x0020 +#define IS_RICOH 0x0040 +#define IS_UNKNOWN 0x0400 +#define IS_VG_PWR 0x0800 +#define IS_DF_PWR 0x1000 +#define IS_PCI 0x2000 +#define IS_CARDBUS 0x4000 +#define IS_ALIVE 0x8000 + +typedef struct pcic_t { + char *name; + u_short flags; +#ifdef CONFIG_PCI + u_short vendor, device; +#endif +} pcic_t; + +static pcic_t pcic[] = { +#ifdef CONFIG_ISA + { "Intel i82365sl A step", 0 }, + { "Intel i82365sl B step", 0 }, + { "Intel i82365sl DF", IS_DF_PWR }, + { "IBM Clone", 0 }, + { "Ricoh RF5C296/396", 0 }, + { "VLSI 82C146", 0 }, + { "Vadem VG-468", IS_VADEM }, + { "Vadem VG-469", IS_VADEM|IS_VG_PWR }, + { "Cirrus PD6710", IS_CIRRUS }, + { "Cirrus PD672x", IS_CIRRUS }, + { "VIA VT83C469", IS_CIRRUS|IS_VIA }, +#endif +#ifdef CONFIG_PCI + { "Cirrus PD6729", IS_CIRRUS|IS_PCI, + PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729 }, + { "Cirrus PD6730", IS_CIRRUS|IS_PCI, + PCI_VENDOR_ID_CIRRUS, 0xffff }, + { "O2Micro OZ6729", IS_O2MICRO|IS_PCI|IS_VG_PWR, + PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6729 }, + { "O2Micro OZ6730", IS_O2MICRO|IS_PCI|IS_VG_PWR, + PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6730 }, + { "Intel 82092AA", IS_PCI, + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_OMEGA_PCMCIA }, + { "Omega Micro 82C092G", IS_PCI, + PCI_VENDOR_ID_OMEGA, PCI_DEVICE_ID_OMEGA_PCMCIA }, + { "Cirrus PD6832", IS_CIRRUS|IS_CARDBUS, + PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832 }, + { "O2Micro OZ6832/OZ6833", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR, + PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6832 }, + { "O2Micro OZ6836/OZ6860", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR, + PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6836 }, + { "Ricoh RL5C465", IS_RICOH|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465 }, + { "Ricoh RL5C466", IS_RICOH|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466 }, + { "Ricoh RL5C475", IS_RICOH|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475 }, + { "Ricoh RL5C476", IS_RICOH|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476 }, + { "Ricoh RL5C478", IS_RICOH|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478 }, + { "SMC 34C90", IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_34C90 }, + { "TI 1130", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130 }, + { "TI 1131", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131 }, + { "TI 1250A", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250A }, + { "TI 1220", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1220 }, + { "TI 1221", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221 }, + { "TI 1210", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210 }, + { "TI 1251A", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A }, + { "TI 1251B", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B }, + { "TI 1450", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450 }, + { "TI 1225", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225 }, + { "TI 1211", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211 }, + { "TI 1420", IS_TI|IS_CARDBUS|IS_DF_PWR, + PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420 }, + { "Toshiba ToPIC95-A", IS_CARDBUS|IS_TOPIC|IS_DF_PWR, + PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_A }, + { "Toshiba ToPIC95-B", IS_CARDBUS|IS_TOPIC|IS_DF_PWR, + PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_B }, + { "Toshiba ToPIC97", IS_CARDBUS|IS_TOPIC|IS_DF_PWR, + PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97 }, + { "Unknown", IS_PCI|IS_UNKNOWN, 0, 0 }, + { "Unknown", IS_CARDBUS|IS_DF_PWR|IS_UNKNOWN, 0, 0 } +#endif +}; + +#define PCIC_COUNT (sizeof(pcic)/sizeof(pcic_t)) + +/*====================================================================*/ + +/* Some PCI shortcuts */ + +#ifdef CONFIG_PCI + +#define pci_readb pcibios_read_config_byte +#define pci_writeb pcibios_write_config_byte +#define pci_readw pcibios_read_config_word +#define pci_writew pcibios_write_config_word +#define pci_readl pcibios_read_config_dword +#define pci_writel pcibios_write_config_dword + +#define cb_readb(s, r) readb(socket[s].cb_virt + (r)) +#define cb_readl(s, r) readl(socket[s].cb_virt + (r)) +#define cb_writeb(s, r, v) writeb(v, socket[s].cb_virt + (r)) +#define cb_writel(s, r, v) writel(v, socket[s].cb_virt + (r)) + +static void cb_get_power(u_short sock, socket_state_t *state); +static void cb_set_power(u_short sock, socket_state_t *state); +#endif + +/*====================================================================*/ + +static u_char i365_get(u_short sock, u_short reg) +{ +#ifdef CONFIG_PCI + if (socket[sock].cb_virt) + return cb_readb(sock, 0x0800 + reg); + else +#endif + { + u_short port = socket[sock].ioaddr; + u_char val; + reg = I365_REG(socket[sock].psock, reg); + outb(reg, port); val = inb(port+1); + return val; + } +} + +static void i365_set(u_short sock, u_short reg, u_char data) +{ +#ifdef CONFIG_PCI + if (socket[sock].cb_virt) + cb_writeb(sock, 0x0800 + reg, data); + else +#endif + { + u_short port = socket[sock].ioaddr; + u_char val = I365_REG(socket[sock].psock, reg); + outb(val, port); outb(data, port+1); + } +} + +static void i365_bset(u_short sock, u_short reg, u_char mask) +{ + u_char d = i365_get(sock, reg); + d |= mask; + i365_set(sock, reg, d); +} + +static void i365_bclr(u_short sock, u_short reg, u_char mask) +{ + u_char d = i365_get(sock, reg); + d &= ~mask; + i365_set(sock, reg, d); +} + +static void i365_bflip(u_short sock, u_short reg, u_char mask, int b) +{ + u_char d = i365_get(sock, reg); + if (b) + d |= mask; + else + d &= ~mask; + i365_set(sock, reg, d); +} + +static u_short i365_get_pair(u_short sock, u_short reg) +{ + u_short a, b; + a = i365_get(sock, reg); + b = i365_get(sock, reg+1); + return (a + (b<<8)); +} + +static void i365_set_pair(u_short sock, u_short reg, u_short data) +{ + i365_set(sock, reg, data & 0xff); + i365_set(sock, reg+1, data >> 8); +} + +/*====================================================================== + + Code to save and restore global state information for Cirrus + PD67xx controllers, and to set and report global configuration + options. + + The VIA controllers also use these routines, as they are mostly + Cirrus lookalikes, without the timing registers. + +======================================================================*/ + +#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b)))) + +static void cirrus_get_state(u_short s) +{ + int i; + cirrus_state_t *p = &socket[s].state.cirrus; + p->misc1 = i365_get(s, PD67_MISC_CTL_1); + p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA); + p->misc2 = i365_get(s, PD67_MISC_CTL_2); + for (i = 0; i < 6; i++) + p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i); +} + +static void cirrus_set_state(u_short s) +{ + int i; + u_char misc; + cirrus_state_t *p = &socket[s].state.cirrus; + + misc = i365_get(s, PD67_MISC_CTL_2); + i365_set(s, PD67_MISC_CTL_2, p->misc2); + if (misc & PD67_MC2_SUSPEND) mdelay(50); + misc = i365_get(s, PD67_MISC_CTL_1); + misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA); + i365_set(s, PD67_MISC_CTL_1, misc | p->misc1); + for (i = 0; i < 6; i++) + i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]); +} + +#ifdef CONFIG_PCI +static int cirrus_set_irq_mode(u_short s, int pcsc, int pint) +{ + flip(socket[s].bcr, PD6832_BCR_MGMT_IRQ_ENA, !pcsc); + return 0; +} +#endif /* CONFIG_PCI */ + +static u_int cirrus_set_opts(u_short s, char *buf) +{ + socket_info_t *t = &socket[s]; + cirrus_state_t *p = &socket[s].state.cirrus; + u_int mask = 0xffff; + + if (has_ring == -1) has_ring = 1; + flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring); + flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode); + if (p->misc2 & PD67_MC2_IRQ15_RI) + strcat(buf, " [ring]"); + if (p->misc2 & PD67_MC2_DYNAMIC_MODE) + strcat(buf, " [dyn mode]"); + if (p->misc1 & PD67_MC1_INPACK_ENA) + strcat(buf, " [inpack]"); + if (!(t->flags & (IS_PCI | IS_CARDBUS))) { + if (p->misc2 & PD67_MC2_IRQ15_RI) + mask &= ~0x8000; + if (has_led > 0) { + strcat(buf, " [led]"); + mask &= ~0x1000; + } + if (has_dma > 0) { + strcat(buf, " [dma]"); + mask &= ~0x0600; + flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass); + if (p->misc2 & PD67_MC2_FREQ_BYPASS) + strcat(buf, " [freq bypass]"); + } +#ifdef CONFIG_PCI + } else { + p->misc1 &= ~PD67_MC1_MEDIA_ENA; + flip(p->misc2, PD67_MC2_FAST_PCI, fast_pci); + if (p->misc2 & PD67_MC2_IRQ15_RI) + mask &= (socket[s].type == IS_PD6730) ? ~0x0400 : ~0x8000; +#endif + } + if (!(t->flags & IS_VIA)) { + if (setup_time >= 0) + p->timer[0] = p->timer[3] = setup_time; + if (cmd_time > 0) { + p->timer[1] = cmd_time; + p->timer[4] = cmd_time*2+4; + } + if (p->timer[1] == 0) { + p->timer[1] = 6; p->timer[4] = 16; + if (p->timer[0] == 0) + p->timer[0] = p->timer[3] = 1; + } + if (recov_time >= 0) + p->timer[2] = p->timer[5] = recov_time; + buf += strlen(buf); + sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1], + p->timer[2], p->timer[3], p->timer[4], p->timer[5]); + } + return mask; +} + +/*====================================================================== + + Code to save and restore global state information for Vadem VG468 + and VG469 controllers, and to set and report global configuration + options. + +======================================================================*/ + +#ifdef CONFIG_ISA + +static void vg46x_get_state(u_short s) +{ + vg46x_state_t *p = &socket[s].state.vg46x; + p->ctl = i365_get(s, VG468_CTL); + if (socket[s].type == IS_VG469) + p->ema = i365_get(s, VG469_EXT_MODE); +} + +static void vg46x_set_state(u_short s) +{ + vg46x_state_t *p = &socket[s].state.vg46x; + i365_set(s, VG468_CTL, p->ctl); + if (socket[s].type == IS_VG469) + i365_set(s, VG469_EXT_MODE, p->ema); +} + +static u_int vg46x_set_opts(u_short s, char *buf) +{ + vg46x_state_t *p = &socket[s].state.vg46x; + + flip(p->ctl, VG468_CTL_ASYNC, async_clock); + flip(p->ema, VG469_MODE_CABLE, cable_mode); + if (p->ctl & VG468_CTL_ASYNC) + strcat(buf, " [async]"); + if (p->ctl & VG468_CTL_INPACK) + strcat(buf, " [inpack]"); + if (socket[s].type == IS_VG469) { + u_char vsel = i365_get(s, VG469_VSELECT); + if (vsel & VG469_VSEL_EXT_STAT) { + strcat(buf, " [ext mode]"); + if (vsel & VG469_VSEL_EXT_BUS) + strcat(buf, " [isa buf]"); + } + if (p->ema & VG469_MODE_CABLE) + strcat(buf, " [cable]"); + if (p->ema & VG469_MODE_COMPAT) + strcat(buf, " [c step]"); + } + return 0xffff; +} + +#endif + +/*====================================================================== + + Code to save and restore global state information for TI 1130 and + TI 1131 controllers, and to set and report global configuration + options. + +======================================================================*/ + +#ifdef CONFIG_PCI + +static void ti113x_get_state(u_short s) +{ + socket_info_t *t = &socket[s]; + ti113x_state_t *p = &socket[s].state.ti113x; + pci_readl(t->bus, t->devfn, TI113X_SYSTEM_CONTROL, &p->sysctl); + pci_readb(t->bus, t->devfn, TI113X_CARD_CONTROL, &p->cardctl); + pci_readb(t->bus, t->devfn, TI113X_DEVICE_CONTROL, &p->devctl); + pci_readb(t->bus, t->devfn, TI1250_DIAGNOSTIC, &p->diag); +} + +static void ti113x_set_state(u_short s) +{ + socket_info_t *t = &socket[s]; + ti113x_state_t *p = &socket[s].state.ti113x; + pci_writel(t->bus, t->devfn, TI113X_SYSTEM_CONTROL, p->sysctl); + pci_writeb(t->bus, t->devfn, TI113X_CARD_CONTROL, p->cardctl); + pci_writeb(t->bus, t->devfn, TI113X_DEVICE_CONTROL, p->devctl); + pci_writeb(t->bus, t->devfn, TI1250_MULTIMEDIA_CTL, 0); + pci_writeb(t->bus, t->devfn, TI1250_DIAGNOSTIC, p->diag); + i365_set_pair(s, TI113X_IO_OFFSET(0), 0); + i365_set_pair(s, TI113X_IO_OFFSET(1), 0); +} + +static int ti113x_set_irq_mode(u_short s, int pcsc, int pint) +{ + socket_info_t *t = &socket[s]; + ti113x_state_t *p = &t->state.ti113x; + t->intr = (pcsc) ? I365_INTR_ENA : 0; + if (t->type <= IS_TI1131) { + p->cardctl &= ~(TI113X_CCR_PCI_IRQ_ENA | + TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC); + if (pcsc) + p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC; + if (pint) + p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ; + } else if (t->type == IS_TI1250A) { + p->diag &= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ; + if (pcsc) + p->diag |= TI1250_DIAG_PCI_CSC; + if (pint) + p->diag |= TI1250_DIAG_PCI_IREQ; + } + return 0; +} + +static u_int ti113x_set_opts(u_short s, char *buf) +{ + socket_info_t *t = &socket[s]; + ti113x_state_t *p = &t->state.ti113x; + u_int mask = 0xffff; + int old = (t->type <= IS_TI1131); + + flip(p->sysctl, TI113X_SCR_CLKRUN_ENA, has_clkrun); + flip(p->sysctl, TI113X_SCR_CLKRUN_SEL, clkrun_sel); + flip(p->cardctl, TI113X_CCR_RIENB, has_ring); + p->cardctl &= ~TI113X_CCR_ZVENABLE; + switch (irq_mode) { + case 1: + p->devctl &= ~TI113X_DCR_IMODE_MASK; + p->devctl |= TI113X_DCR_IMODE_ISA; + break; + case 2: + p->devctl &= ~TI113X_DCR_IMODE_MASK; + p->devctl |= TI113X_DCR_IMODE_SERIAL; + break; + case 3: + p->devctl &= ~TI113X_DCR_IMODE_MASK; + p->devctl |= TI12XX_DCR_IMODE_ALL_SERIAL; + break; + default: + if ((p->devctl & TI113X_DCR_IMODE_MASK) == 0) + p->devctl |= TI113X_DCR_IMODE_ISA; + } + if (p->cardctl & TI113X_CCR_RIENB) { + strcat(buf, " [ring]"); + if (old) mask &= ~0x8000; + } + if (old && (p->sysctl & TI113X_SCR_CLKRUN_ENA)) { + if (p->sysctl & TI113X_SCR_CLKRUN_SEL) { + strcat(buf, " [clkrun irq 12]"); + mask &= ~0x1000; + } else { + strcat(buf, " [clkrun irq 10]"); + mask &= ~0x0400; + } + } + if (p->sysctl & TI113X_SCR_PWRSAVINGS) + strcat(buf, " [pwr save]"); + switch (p->devctl & TI113X_DCR_IMODE_MASK) { + case TI12XX_DCR_IMODE_PCI_ONLY: + strcat(buf, " [pci only]"); + mask = 0; + break; + case TI113X_DCR_IMODE_ISA: + strcat(buf, " [isa irq]"); + if (old) mask &= ~0x0018; + break; + case TI113X_DCR_IMODE_SERIAL: + strcat(buf, " [pci + serial irq]"); + mask = 0xffff; + break; + case TI12XX_DCR_IMODE_ALL_SERIAL: + strcat(buf, " [serial pci & irq]"); + mask = 0xffff; + break; + } + return mask; +} + +#endif + +/*====================================================================== + + Code to save and restore global state information for the Ricoh + RL5C4XX controllers, and to set and report global configuration + options. + +======================================================================*/ + +#ifdef CONFIG_PCI + +static void rl5c4xx_get_state(u_short s) +{ + socket_info_t *t = &socket[s]; + rl5c4xx_state_t *p = &socket[s].state.rl5c4xx; + pci_readw(t->bus, t->devfn, RL5C4XX_MISC, &p->misc); + pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_CTL, &p->ctl); + pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_IO_0, &p->io); + pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_MEM_0, &p->mem); +} + +static void rl5c4xx_set_state(u_short s) +{ + socket_info_t *t = &socket[s]; + rl5c4xx_state_t *p = &socket[s].state.rl5c4xx; + pci_writew(t->bus, t->devfn, RL5C4XX_MISC, p->misc); + pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_CTL, p->ctl); + pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_IO_0, p->io); + pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_MEM_0, p->mem); +} + +static u_int rl5c4xx_set_opts(u_short s, char *buf) +{ + rl5c4xx_state_t *p = &socket[s].state.rl5c4xx; + u_int mask = 0xffff; + int old = (socket[s].type < IS_RL5C475); + + p->ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; + if (old) p->ctl |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2; + + if (setup_time >= 0) { + p->io = (p->io & ~RL5C4XX_SETUP_MASK) + + ((setup_time+1) << RL5C4XX_SETUP_SHIFT); + p->mem = (p->mem & ~RL5C4XX_SETUP_MASK) + + (setup_time << RL5C4XX_SETUP_SHIFT); + } + if (cmd_time >= 0) { + p->io = (p->io & ~RL5C4XX_CMD_MASK) + + (cmd_time << RL5C4XX_CMD_SHIFT); + p->mem = (p->mem & ~RL5C4XX_CMD_MASK) + + (cmd_time << RL5C4XX_CMD_SHIFT); + } + if (hold_time >= 0) { + p->io = (p->io & ~RL5C4XX_HOLD_MASK) + + (hold_time << RL5C4XX_HOLD_SHIFT); + p->mem = (p->mem & ~RL5C4XX_HOLD_MASK) + + (hold_time << RL5C4XX_HOLD_SHIFT); + } + if (!old) { + switch (irq_mode) { + case 1: + p->misc &= ~RL5C47X_MISC_SRIRQ_ENA; break; + case 2: + p->misc |= RL5C47X_MISC_SRIRQ_ENA; break; + } + if (p->misc & RL5C47X_MISC_SRIRQ_ENA) + sprintf(buf, " [serial irq]"); + else + sprintf(buf, " [isa irq]"); + buf += strlen(buf); + } + sprintf(buf, " [io %d/%d/%d] [mem %d/%d/%d]", + (p->io & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT, + (p->io & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT, + (p->io & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT, + (p->mem & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT, + (p->mem & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT, + (p->mem & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT); + return mask; +} + +#endif + +/*====================================================================== + + Code to save and restore global state information for O2Micro + controllers, and to set and report global configuration options. + +======================================================================*/ + +#ifdef CONFIG_PCI + +static void o2micro_get_state(u_short s) +{ + socket_info_t *t = &socket[s]; + o2micro_state_t *p = &socket[s].state.o2micro; + if ((t->revision == 0x34) || (t->revision == 0x62)) { + p->mode_a = i365_get(s, O2_MODE_A_2); + p->mode_b = i365_get(s, O2_MODE_B_2); + } else { + p->mode_a = i365_get(s, O2_MODE_A); + p->mode_b = i365_get(s, O2_MODE_B); + } + p->mode_c = i365_get(s, O2_MODE_C); + p->mode_d = i365_get(s, O2_MODE_D); + if (t->flags & IS_CARDBUS) { + p->mhpg = i365_get(s, O2_MHPG_DMA); + p->fifo = i365_get(s, O2_FIFO_ENA); + p->mode_e = i365_get(s, O2_MODE_E); + } +} + +static void o2micro_set_state(u_short s) +{ + socket_info_t *t = &socket[s]; + o2micro_state_t *p = &socket[s].state.o2micro; + if ((t->revision == 0x34) || (t->revision == 0x62)) { + i365_set(s, O2_MODE_A_2, p->mode_a); + i365_set(s, O2_MODE_B_2, p->mode_b); + } else { + i365_set(s, O2_MODE_A, p->mode_a); + i365_set(s, O2_MODE_B, p->mode_b); + } + i365_set(s, O2_MODE_C, p->mode_c); + i365_set(s, O2_MODE_D, p->mode_d); + if (t->flags & IS_CARDBUS) { + i365_set(s, O2_MHPG_DMA, p->mhpg); + i365_set(s, O2_FIFO_ENA, p->fifo); + i365_set(s, O2_MODE_E, p->mode_e); + } +} + +static u_int o2micro_set_opts(u_short s, char *buf) +{ + socket_info_t *t = &socket[s]; + o2micro_state_t *p = &socket[s].state.o2micro; + u_int mask = 0xffff; + + p->mode_b = (p->mode_b & ~O2_MODE_B_IDENT) | O2_MODE_B_ID_CSTEP; + flip(p->mode_b, O2_MODE_B_IRQ15_RI, has_ring); + p->mode_c &= ~(O2_MODE_C_ZVIDEO | O2_MODE_C_DREQ_MASK); + if (t->flags & IS_CARDBUS) { + p->mode_d &= ~O2_MODE_D_W97_IRQ; + p->mode_e &= ~O2_MODE_E_MHPG_DMA; + p->mhpg |= O2_MHPG_CINT_ENA | O2_MHPG_CSC_ENA; + p->mhpg &= ~O2_MHPG_CHANNEL; + } else { + if (p->mode_b & O2_MODE_B_IRQ15_RI) mask &= ~0x8000; + } + sprintf(buf, " [a %02x] [b %02x] [c %02x] [d %02x]", + p->mode_a, p->mode_b, p->mode_c, p->mode_d); + if (t->flags & IS_CARDBUS) { + buf += strlen(buf); + sprintf(buf, " [mhpg %02x] [fifo %02x] [e %02x]", + p->mhpg, p->fifo, p->mode_e); + } + return mask; +} + +#endif + +/*====================================================================== + + Code to save and restore global state information for the Toshiba + ToPIC 95 and 97 controllers, and to set and report global + configuration options. + +======================================================================*/ + +#ifdef CONFIG_PCI + +static void topic_get_state(u_short s) +{ + socket_info_t *t = &socket[s]; + topic_state_t *p = &socket[s].state.topic; + pci_readb(t->bus, t->devfn, TOPIC_SLOT_CONTROL, &p->slot); + pci_readb(t->bus, t->devfn, TOPIC_CARD_CONTROL, &p->ccr); + pci_readb(t->bus, t->devfn, TOPIC_CARD_DETECT, &p->cdr); + pci_readl(t->bus, t->devfn, TOPIC_REGISTER_CONTROL, &p->rcr); +} + +static void topic_set_state(u_short s) +{ + socket_info_t *t = &socket[s]; + topic_state_t *p = &socket[s].state.topic; + pci_writeb(t->bus, t->devfn, TOPIC_SLOT_CONTROL, p->slot); + pci_writeb(t->bus, t->devfn, TOPIC_CARD_CONTROL, p->ccr); + pci_writeb(t->bus, t->devfn, TOPIC_CARD_DETECT, p->cdr); + pci_writel(t->bus, t->devfn, TOPIC_REGISTER_CONTROL, p->rcr); +} + +static int topic_set_irq_mode(u_short s, int pcsc, int pint) +{ + if (socket[s].type == IS_TOPIC97) { + topic_state_t *p = &socket[s].state.topic; + flip(p->ccr, TOPIC97_ICR_IRQSEL, pcsc); + return 0; + } else { + return !pcsc; + } +} + +static u_int topic_set_opts(u_short s, char *buf) +{ + topic_state_t *p = &socket[s].state.topic; + + p->slot |= TOPIC_SLOT_SLOTON|TOPIC_SLOT_SLOTEN|TOPIC_SLOT_ID_LOCK; + p->cdr |= TOPIC_CDR_MODE_PC32; + p->cdr &= ~(TOPIC_CDR_SW_DETECT); + sprintf(buf, " [slot 0x%02x] [ccr 0x%02x] [cdr 0x%02x] [rcr 0x%02x]", + p->slot, p->ccr, p->cdr, p->rcr); + return 0xffff; +} + +#endif + +/*====================================================================== + + Routines to handle common CardBus options + +======================================================================*/ + +#ifdef CONFIG_PCI + +static void cb_get_state(u_short s) +{ + socket_info_t *t = &socket[s]; + + pci_readb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, &t->cache); + pci_readb(t->bus, t->devfn, PCI_LATENCY_TIMER, &t->pci_lat); + pci_readb(t->bus, t->devfn, CB_LATENCY_TIMER, &t->cb_lat); + pci_readb(t->bus, t->devfn, CB_CARDBUS_BUS, &t->cap.cardbus); + pci_readb(t->bus, t->devfn, CB_SUBORD_BUS, &t->sub_bus); + pci_readw(t->bus, t->devfn, CB_BRIDGE_CONTROL, &t->bcr); + { + struct pci_dev *pdev = pci_find_slot(t->bus, t->devfn); + t->cap.pci_irq = (pdev) ? pdev->irq : 0; + } + if (t->cap.pci_irq >= NR_IRQS) t->cap.pci_irq = 0; +} + +static void cb_set_state(u_short s) +{ + socket_info_t *t = &socket[s]; + if (t->pmcs) + pci_writew(t->bus, t->devfn, t->pmcs, PCI_PMCS_PWR_STATE_D0); + pci_writel(t->bus, t->devfn, CB_LEGACY_MODE_BASE, 0); + pci_writel(t->bus, t->devfn, PCI_BASE_ADDRESS_0, t->cb_phys); + pci_writew(t->bus, t->devfn, PCI_COMMAND, CMD_DFLT); + pci_writeb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, t->cache); + pci_writeb(t->bus, t->devfn, PCI_LATENCY_TIMER, t->pci_lat); + pci_writeb(t->bus, t->devfn, CB_LATENCY_TIMER, t->cb_lat); + pci_writeb(t->bus, t->devfn, CB_CARDBUS_BUS, t->cap.cardbus); + pci_writeb(t->bus, t->devfn, CB_SUBORD_BUS, t->sub_bus); + pci_writew(t->bus, t->devfn, CB_BRIDGE_CONTROL, t->bcr); +} + +static int cb_get_irq_mode(u_short s) +{ + return (!(socket[s].bcr & CB_BCR_ISA_IRQ)); +} + +static int cb_set_irq_mode(u_short s, int pcsc, int pint) +{ + socket_info_t *t = &socket[s]; + flip(t->bcr, CB_BCR_ISA_IRQ, !(pint)); + if (t->flags & IS_CIRRUS) + return cirrus_set_irq_mode(s, pcsc, pint); + else if (t->flags & IS_TI) + return ti113x_set_irq_mode(s, pcsc, pint); + else if (t->flags & IS_TOPIC) + return topic_set_irq_mode(s, pcsc, pint); + return 0; +} + +static void pci_scan(u_short sock); + +static void cb_set_opts(u_short s, char *buf) +{ + socket_info_t *t = &socket[s]; + t->bcr |= CB_BCR_WRITE_POST; + /* some TI1130's seem to exhibit problems with write posting */ + if (((t->type == IS_TI1130) && (t->revision == 4) && + (cb_write_post < 0)) || (cb_write_post == 0)) + t->bcr &= ~CB_BCR_WRITE_POST; + if (t->cache == 0) t->cache = 8; + if (pci_latency >= 0) t->pci_lat = pci_latency; + if (t->pci_lat == 0) t->pci_lat = 0xa8; + if (cb_latency >= 0) t->cb_lat = cb_latency; + if (t->cb_lat == 0) t->cb_lat = 0xb0; + if ((t->cap.pci_irq == 0) && (pci_csc || pci_int) && do_scan) + pci_scan(s); + if (t->cap.pci_irq == 0) + strcat(buf, " [no pci irq]"); + else + sprintf(buf, " [pci irq %d]", t->cap.pci_irq); + buf += strlen(buf); + if ((cb_bus_base > 0) || (t->cap.cardbus == 0)) { + if (cb_bus_base <= 0) cb_bus_base = 0x20; + t->cap.cardbus = cb_bus_base; + t->sub_bus = cb_bus_base+cb_bus_step; + cb_bus_base += cb_bus_step+1; + } + if (!(t->flags & IS_TOPIC)) + t->cap.features |= SS_CAP_PAGE_REGS; + sprintf(buf, " [lat %d/%d] [bus %d/%d]", + t->pci_lat, t->cb_lat, t->cap.cardbus, t->sub_bus); +} + +#endif + +/*====================================================================== + + Generic routines to get and set controller options + +======================================================================*/ + +static void get_host_state(u_short s) +{ + socket_info_t *t = &socket[s]; + if (t->flags & IS_CIRRUS) + cirrus_get_state(s); +#ifdef CONFIG_ISA + else if (t->flags & IS_VADEM) + vg46x_get_state(s); +#endif +#ifdef CONFIG_PCI + else if (t->flags & IS_O2MICRO) + o2micro_get_state(s); + else if (t->flags & IS_TI) + ti113x_get_state(s); + else if (t->flags & IS_RICOH) + rl5c4xx_get_state(s); + else if (t->flags & IS_TOPIC) + topic_get_state(s); + if (t->flags & IS_CARDBUS) + cb_get_state(s); +#endif +} + +static void set_host_state(u_short s) +{ + socket_info_t *t = &socket[s]; +#ifdef CONFIG_PCI + if (t->flags & IS_CARDBUS) + cb_set_state(s); +#endif + if (t->flags & IS_CIRRUS) + cirrus_set_state(s); + else { + i365_set(s, I365_GBLCTL, 0x00); + i365_set(s, I365_GENCTL, 0x00); + } + i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr); +#ifdef CONFIG_ISA + if (t->flags & IS_VADEM) + vg46x_set_state(s); +#endif +#ifdef CONFIG_PCI + if (t->flags & IS_O2MICRO) + o2micro_set_state(s); + else if (t->flags & IS_TI) + ti113x_set_state(s); + else if (t->flags & IS_RICOH) + rl5c4xx_set_state(s); + else if (t->flags & IS_TOPIC) + topic_set_state(s); +#endif +} + +static u_int set_host_opts(u_short s, u_short ns) +{ + u_short i; + u_int m = 0xffff; + char buf[128]; + + for (i = s; i < s+ns; i++) { + if (socket[i].flags & IS_ALIVE) { + printk(KERN_INFO " host opts [%d]: already alive!\n", i); + continue; + } + buf[0] = '\0'; + get_host_state(i); + if (socket[i].flags & IS_CIRRUS) + m = cirrus_set_opts(i, buf); +#ifdef CONFIG_ISA + else if (socket[i].flags & IS_VADEM) + m = vg46x_set_opts(i, buf); +#endif +#ifdef CONFIG_PCI + else if (socket[i].flags & IS_O2MICRO) + m = o2micro_set_opts(i, buf); + else if (socket[i].flags & IS_TI) + m = ti113x_set_opts(i, buf); + else if (socket[i].flags & IS_RICOH) + m = rl5c4xx_set_opts(i, buf); + else if (socket[i].flags & IS_TOPIC) + m = topic_set_opts(i, buf); + if (socket[i].flags & IS_CARDBUS) + cb_set_opts(i, buf+strlen(buf)); +#endif + set_host_state(i); + printk(KERN_INFO " host opts [%d]:%s\n", i, + (*buf) ? buf : " none"); + } +#ifdef CONFIG_PCI + /* Mask out all PCI interrupts */ + for (i = 0; i < sockets; i++) + m &= ~(1<next) + m &= ~(1<irq); + } +#endif + return m; +} + +/*====================================================================== + + Interrupt testing code, for ISA and PCI interrupts + +======================================================================*/ + +static volatile u_int irq_hits; +static u_short irq_sock; + +static void irq_count(int irq, void *dev, struct pt_regs *regs) +{ +#ifdef CONFIG_PCI + if (socket[irq_sock].flags & IS_CARDBUS) { + cb_writel(irq_sock, CB_SOCKET_EVENT, -1); + } else +#endif + i365_get(irq_sock, I365_CSC); + irq_hits++; + DEBUG(2, ("-> hit on irq %d\n", irq)); +} + +static u_int test_irq(u_short sock, int irq, int pci) +{ + u_char csc = (pci) ? 0 : irq; + DEBUG(2, " testing %s irq %d\n", pci ? "PCI" : "ISA", irq); + + if (request_irq(irq, irq_count, (pci?SA_SHIRQ:0), "scan", NULL) != 0) + return 1; + irq_hits = 0; irq_sock = sock; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/100); + if (irq_hits) { + free_irq(irq, NULL); + DEBUG(2, (" spurious hit!\n")); + return 1; + } + + /* Generate one interrupt */ +#ifdef CONFIG_PCI + if (socket[sock].flags & IS_CARDBUS) { + cb_writel(sock, CB_SOCKET_EVENT, -1); + i365_set(sock, I365_CSCINT, I365_CSC_STSCHG | (csc << 4)); + cb_writel(sock, CB_SOCKET_EVENT, -1); + cb_writel(sock, CB_SOCKET_MASK, CB_SM_CSTSCHG); + cb_writel(sock, CB_SOCKET_FORCE, CB_SE_CSTSCHG); + udelay(1000); + cb_writel(sock, CB_SOCKET_EVENT, -1); + cb_writel(sock, CB_SOCKET_MASK, 0); + } else +#endif + { + i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (csc << 4)); + i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ); + udelay(1000); + } + + free_irq(irq, NULL); + + /* mask all interrupts */ + i365_set(sock, I365_CSCINT, 0); + DEBUG(2, " hits = %d\n", irq_hits); + + return (irq_hits != 1); +} + +#ifdef CONFIG_ISA + +static u_int isa_scan(u_short sock, u_int mask0) +{ + u_int mask1 = 0; + int i; + +#ifdef __alpha__ +#define PIC 0x4d0 + /* Don't probe level-triggered interrupts -- reserved for PCI */ + mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8)); +#endif + +#ifdef CONFIG_PCI + /* Only scan if we can select ISA csc irq's */ + if (!(socket[sock].flags & IS_CARDBUS) || + (cb_set_irq_mode(sock, 0, 0) == 0)) +#endif + if (do_scan) { + set_host_state(sock); + i365_set(sock, I365_CSCINT, 0); + for (i = 0; i < 16; i++) + if ((mask0 & (1 << i)) && (test_irq(sock, i, 0) == 0)) + mask1 |= (1 << i); + for (i = 0; i < 16; i++) + if ((mask1 & (1 << i)) && (test_irq(sock, i, 0) != 0)) + mask1 ^= (1 << i); + } + + printk(KERN_INFO " ISA irqs ("); + if (mask1) { + printk("scanned"); + } else { + /* Fallback: just find interrupts that aren't in use */ + for (i = 0; i < 16; i++) + if ((mask0 & (1 << i)) && (_check_irq(i, 0) == 0)) + mask1 |= (1 << i); + printk("default"); + /* If scan failed, default to polled status */ + if (!cs_irq && (poll_interval == 0)) poll_interval = HZ; + } + printk(") = "); + + for (i = 0; i < 16; i++) + if (mask1 & (1<= 4) ? IS_VG469 : IS_VG468; + } + + /* Check for Ricoh chips */ + val = i365_get(sockets, RF5C_CHIP_ID); + if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396)) + type = IS_RF5Cx96; + + /* Check for Cirrus CL-PD67xx chips */ + i365_set(sockets, PD67_CHIP_INFO, 0); + val = i365_get(sockets, PD67_CHIP_INFO); + if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) { + val = i365_get(sockets, PD67_CHIP_INFO); + if ((val & PD67_INFO_CHIP_ID) == 0) { + type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710; + i365_set(sockets, PD67_EXT_INDEX, 0xe5); + if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5) + type = IS_VT83C469; + } + } + return type; +} /* identify */ + +#endif + +/*====================================================================== + + See if a card is present, powered up, in IO mode, and already + bound to a (non PC Card) Linux driver. We leave these alone. + + We make an exception for cards that seem to be serial devices. + +======================================================================*/ + +static int is_alive(u_short sock) +{ + u_char stat; + u_short start, stop; + + stat = i365_get(sock, I365_STATUS); + start = i365_get_pair(sock, I365_IO(0)+I365_W_START); + stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP); + if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) && + (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) && + (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) && + (check_region(start, stop-start+1) != 0) && + ((start & 0xfeef) != 0x02e8)) + return 1; + else + return 0; +} + +/*====================================================================*/ + +static void add_socket(u_short port, int psock, int type) +{ + socket[sockets].ioaddr = port; + socket[sockets].psock = psock; + socket[sockets].type = type; + socket[sockets].flags = pcic[type].flags; + if (is_alive(sockets)) + socket[sockets].flags |= IS_ALIVE; + sockets++; +} + +static void add_pcic(int ns, int type) +{ + u_int mask = 0, i, base; + int use_pci = 0, isa_irq = 0; + socket_info_t *t = &socket[sockets-ns]; + + base = sockets-ns; + if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365"); + + if (base == 0) printk("\n"); + printk(KERN_INFO " %s", pcic[type].name); +#ifdef CONFIG_PCI + if (t->flags & IS_UNKNOWN) + printk(" [0x%04x 0x%04x]", t->vendor, t->device); + if (t->flags & IS_CARDBUS) + printk(" PCI-to-CardBus at bus %d slot %d, mem 0x%08x", + t->bus, PCI_SLOT(t->devfn), t->cb_phys); + else if (t->flags & IS_PCI) + printk(" PCI-to-PCMCIA at bus %d slot %d, port %#x", + t->bus, PCI_SLOT(t->devfn), t->ioaddr); + else +#endif + printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x", + t->ioaddr, t->psock*0x40); + printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : "")); + +#ifdef CONFIG_ISA + /* Set host options, build basic interrupt mask */ + if (irq_list[0] == -1) + mask = irq_mask; + else + for (i = mask = 0; i < 16; i++) + mask |= (1<cap.pci_irq) { + for (i = 0; i < ns; i++) + if (_check_irq(t[i].cap.pci_irq, SA_SHIRQ)) break; + if (i == ns) { + use_pci = 1; + printk(" PCI status changes\n"); + } + } +#endif + +#ifdef CONFIG_ISA + /* Poll if only two interrupts available */ + if (!use_pci && !poll_interval) { + u_int tmp = (mask & (mask-1)); + if ((tmp & (tmp-1)) == 0) + poll_interval = HZ; + } + /* Only try an ISA cs_irq if this is the first controller */ + if (!use_pci && !grab_irq && (cs_irq || !poll_interval)) { + /* Avoid irq 12 unless it is explicitly requested */ + u_int cs_mask = mask & ((cs_irq) ? (1< 0; cs_irq--) + if ((cs_mask & (1 << cs_irq)) && + (_check_irq(cs_irq, 0) == 0)) + break; + if (cs_irq) { + grab_irq = 1; + isa_irq = cs_irq; + printk(" status change on irq %d\n", cs_irq); + } + } +#endif + + if (!use_pci && !isa_irq) { + if (poll_interval == 0) + poll_interval = HZ; + printk(" polling interval = %d ms\n", + poll_interval * 1000 / HZ); + + } + + /* Update socket interrupt information, capabilities */ + for (i = 0; i < ns; i++) { + t[i].cap.features |= SS_CAP_PCCARD; + t[i].cap.map_size = 0x1000; + t[i].cap.irq_mask = mask; + if (pci_int && t[i].cap.pci_irq) + t[i].cap.irq_mask |= (1 << t[i].cap.pci_irq); + t[i].cs_irq = isa_irq; +#ifdef CONFIG_PCI + if (t[i].flags & IS_CARDBUS) { + t[i].cap.features |= SS_CAP_CARDBUS; + cb_set_irq_mode(i, pci_csc && t[i].cap.pci_irq, + pci_int && t[i].cap.pci_irq); + } +#endif + } + +} /* add_pcic */ + +/*====================================================================*/ + +#ifdef CONFIG_PCI + +typedef struct pci_dev *pci_id_t; +static int pci_lookup(u_int class, pci_id_t *id, + u_char *bus, u_char *devfn) +{ + if ((*id = pci_find_class(class<<8, *id)) != NULL) { + *bus = (*id)->bus->number; + *devfn = (*id)->devfn; + return 0; + } else return -1; +} + +static void add_pci_bridge(int type, u_char bus, u_char devfn, + u_short v, u_short d) +{ + socket_info_t *s = &socket[sockets]; + u_short i, ns; + u_int addr; + + if (type == PCIC_COUNT) type = IS_UNK_PCI; + pci_readl(bus, devfn, PCI_BASE_ADDRESS_0, &addr); + addr &= ~0x1; + pci_writew(bus, devfn, PCI_COMMAND, CMD_DFLT); + for (i = ns = 0; i < ((type == IS_I82092AA) ? 4 : 2); i++) { + s->bus = bus; s->devfn = devfn; + s->vendor = v; s->device = d; + add_socket(addr, i, type); + ns++; s++; + } + add_pcic(ns, type); +} + +static void add_cb_bridge(int type, u_char bus, u_char devfn, + u_short v, u_short d0) +{ + socket_info_t *s = &socket[sockets]; + u_short d, ns; + u_char a, b, r, max; + + /* PCI bus enumeration is broken on some systems */ + for (ns = 0; ns < sockets; ns++) + if ((socket[ns].bus == bus) && (socket[ns].devfn == devfn)) + return; + + if (type == PCIC_COUNT) type = IS_UNK_CARDBUS; + pci_readb(bus, devfn, PCI_HEADER_TYPE, &a); + pci_readb(bus, devfn, PCI_CLASS_REVISION, &r); + max = (a & 0x80) ? 8 : 1; + for (ns = 0; ns < max; ns++, s++, devfn++) { + if (pci_readw(bus, devfn, PCI_DEVICE_ID, &d) || (d != d0)) + break; + s->bus = bus; s->devfn = devfn; + s->vendor = v; s->device = d; s->revision = r; + + /* Check for power management capabilities */ + pci_readb(bus, devfn, PCI_STATUS, &a); + if (a & PCI_STATUS_CAPLIST) { + pci_readb(bus, devfn, PCI_CB_CAPABILITY_POINTER, &b); + while (b != 0) { + pci_readb(bus, devfn, b+PCI_CAPABILITY_ID, &a); + if (a == PCI_CAPABILITY_PM) { + s->pmcs = b + PCI_PM_CONTROL_STATUS; + break; + } + pci_readb(bus, devfn, b+PCI_NEXT_CAPABILITY, &b); + } + } + /* If capability exists, make sure we're in D0 state */ + if (s->pmcs) + pci_writew(bus, devfn, s->pmcs, PCI_PMCS_PWR_STATE_D0); + + /* Map CardBus registers if they are not already mapped */ + pci_writel(bus, devfn, CB_LEGACY_MODE_BASE, 0); + pci_readl(bus, devfn, PCI_BASE_ADDRESS_0, &s->cb_phys); + if (s->cb_phys == 0) { + int i; + pci_writew(bus, devfn, PCI_COMMAND, CMD_DFLT); + for (i = 0; i < sizeof(cb_mem_base)/sizeof(u_int); i++) { + s->cb_phys = cb_mem_base[i]; + s->cb_virt = ioremap(s->cb_phys, 0x1000); + pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, s->cb_phys); + /* Simple sanity checks */ + if (((readb(s->cb_virt+0x800+I365_IDENT) & 0xf0) + == 0x80) && + !(readb(s->cb_virt+0x800+I365_CSC) && + readb(s->cb_virt+0x800+I365_CSC) && + readb(s->cb_virt+0x800+I365_CSC))) + break; + iounmap(s->cb_virt); + } + if (i == sizeof(cb_mem_base)/sizeof(u_int)) { + pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, 0); + s->cb_phys = 0; s->cb_virt = NULL; + printk("\n"); + printk(KERN_NOTICE " Bridge register mapping failed:" + " check cb_mem_base setting\n"); + break; + } + cb_mem_base[0] = cb_mem_base[i] + PAGE_SIZE; + } else { + s->cb_virt = ioremap(s->cb_phys, 0x1000); + } + + request_mem_region(s->cb_phys, 0x1000, "i82365"); + add_socket(0, 0, type); + } + if (ns == 0) return; + + s -= ns; + if (ns == 2) { + /* Nasty special check for bad bus mapping */ + pci_readb(bus, s[0].devfn, CB_CARDBUS_BUS, &a); + pci_readb(bus, s[1].devfn, CB_CARDBUS_BUS, &b); + if (a == b) { + pci_writeb(bus, s[0].devfn, CB_CARDBUS_BUS, 0); + pci_writeb(bus, s[1].devfn, CB_CARDBUS_BUS, 0); + } + } + add_pcic(ns, type); + + /* Re-do card type & voltage detection */ + cb_writel(sockets-ns, CB_SOCKET_FORCE, CB_SF_CVSTEST); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/5); + + /* Set up PCI bus bridge structures if needed */ + for (a = 0; a < ns; a++) { + struct pci_dev *self = pci_find_slot(bus, s[a].devfn); + struct pci_bus *child, *parent = self->bus; + for (child = parent->children; child; child = child->next) + if (child->number == s[a].cap.cardbus) break; + if (!child) { + child = kmalloc(sizeof(struct pci_bus), GFP_KERNEL); + memset(child, 0, sizeof(struct pci_bus)); + child->self = self; + child->primary = bus; + child->number = child->secondary = s[a].cap.cardbus; + child->subordinate = s[a].sub_bus; + child->parent = parent; + child->ops = parent->ops; + child->next = parent->children; + } + s[a].cap.cb_bus = parent->children = child; + } +} + +static void pci_probe(u_int class, void (add_fn)(int, u_char, u_char, + u_short, u_short)) +{ + u_short i, v, d; + u_char bus, devfn; + pci_id_t id; + + id = 0; + while (pci_lookup(class, &id, &bus, &devfn) == 0) { + if (PCI_FUNC(devfn) != 0) continue; + pci_readw(bus, devfn, PCI_VENDOR_ID, &v); + pci_readw(bus, devfn, PCI_DEVICE_ID, &d); + for (i = 0; i < PCIC_COUNT; i++) + if ((pcic[i].vendor == v) && (pcic[i].device == d)) break; + add_fn(i, bus, devfn, v, d); + } +} + +#endif /* CONFIG_PCI */ + +/*====================================================================*/ + +#ifdef CONFIG_ISA + +static void isa_probe(void) +{ + int i, j, sock, k; + int ns, id; + u_short port; + + if (check_region(i365_base, 2) != 0) { + if (sockets == 0) + printk("port conflict at %#x\n", i365_base); + return; + } + + id = identify(i365_base, 0); + if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) { + for (i = 0; i < 4; i++) { + if (i == ignore) continue; + port = i365_base + ((i & 1) << 2) + ((i & 2) << 1); + sock = (i & 1) << 1; + if (identify(port, sock) == IS_I82365DF) { + add_socket(port, sock, IS_VLSI); + add_pcic(1, IS_VLSI); + } + } + } else { + for (i = 0; i < (extra_sockets ? 8 : 4); i += 2) { + port = i365_base + 2*(i>>2); + sock = (i & 3); + id = identify(port, sock); + if (id < 0) continue; + + for (j = ns = 0; j < 2; j++) { + /* Does the socket exist? */ + if ((ignore == i+j) || (identify(port, sock+j) < 0)) + continue; + /* Check for bad socket decode */ + for (k = 0; k <= sockets; k++) + i365_set(k, I365_MEM(0)+I365_W_OFF, k); + for (k = 0; k <= sockets; k++) + if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k) + break; + if (k <= sockets) break; + add_socket(port, sock+j, id); ns++; + } + if (ns != 0) add_pcic(ns, id); + } + } +} + +#endif + +/*====================================================================*/ + +static int pcic_init(void) +{ + DEBUG(0, "%s\n", version); + printk(KERN_INFO "Intel PCIC probe: "); + sockets = 0; + +#ifdef CONFIG_PCI + if (do_pci_probe && pcibios_present()) { + pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge); + pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge); + } +#endif + +#ifdef CONFIG_ISA + isa_probe(); +#endif + + if (sockets == 0) { + printk("not found.\n"); + return -ENODEV; + } + + /* Set up interrupt handler, and/or polling */ +#ifdef CONFIG_ISA + if (grab_irq != 0) + request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL); +#endif +#ifdef CONFIG_PCI + if (pci_csc) { + u_int i, irq, mask = 0; + for (i = 0; i < sockets; i++) { + irq = socket[i].cap.pci_irq; + if (irq && !(mask & (1<handler; + socket[sock].info = call->info; + } + return 0; +} /* pcic_register_callback */ + +/*====================================================================*/ + +static int pcic_inquire_socket(u_short sock, socket_cap_t *cap) +{ + *cap = socket[sock].cap; + return 0; +} /* pcic_inquire_socket */ + +/*====================================================================*/ + +static int i365_get_status(u_short sock, u_int *value) +{ + u_int status; + + status = i365_get(sock, I365_STATUS); + *value = ((status & I365_CS_DETECT) == I365_CS_DETECT) + ? SS_DETECT : 0; + if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) + *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; + else { + *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD; + *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN; + } + *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0; + *value |= (status & I365_CS_READY) ? SS_READY : 0; + *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0; + +#ifdef CONFIG_PCI + if (socket[sock].flags & IS_CARDBUS) { + status = cb_readl(sock, CB_SOCKET_STATE); +#ifndef CONFIG_CARDBUS + *value |= (status & CB_SS_32BIT) ? SS_CARDBUS : 0; +#endif + *value |= (status & CB_SS_3VCARD) ? SS_3VCARD : 0; + *value |= (status & CB_SS_XVCARD) ? SS_XVCARD : 0; + } else if (socket[sock].flags & IS_O2MICRO) { + status = i365_get(sock, O2_MODE_B); + *value |= (status & O2_MODE_B_VS1) ? 0 : SS_3VCARD; + *value |= (status & O2_MODE_B_VS2) ? 0 : SS_XVCARD; + } +#endif +#ifdef CONFIG_ISA + if (socket[sock].type == IS_VG469) { + status = i365_get(sock, VG469_VSENSE); + if (socket[sock].psock & 1) { + *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD; + *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD; + } else { + *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD; + *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD; + } + } +#endif + + DEBUG(1, "i82365: GetStatus(%d) = %#4.4x\n", sock, *value); + return 0; +} /* i365_get_status */ + +/*====================================================================*/ + +static int i365_get_socket(u_short sock, socket_state_t *state) +{ + socket_info_t *t = &socket[sock]; + u_char reg, vcc, vpp; + + reg = i365_get(sock, I365_POWER); + state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; + state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; + vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; + state->Vcc = state->Vpp = 0; +#ifdef CONFIG_PCI + if (t->flags & IS_CARDBUS) { + cb_get_power(sock, state); + } else +#endif + if (t->flags & IS_CIRRUS) { + if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_VCC_3V) { + if (reg & I365_VCC_5V) state->Vcc = 33; + if (vpp == I365_VPP1_5V) state->Vpp = 33; + } else { + if (reg & I365_VCC_5V) state->Vcc = 50; + if (vpp == I365_VPP1_5V) state->Vpp = 50; + } + if (vpp == I365_VPP1_12V) state->Vpp = 120; + } else if (t->flags & IS_VG_PWR) { + if (i365_get(sock, VG469_VSELECT) & VG469_VSEL_VCC) { + if (reg & I365_VCC_5V) state->Vcc = 33; + if (vpp == I365_VPP1_5V) state->Vpp = 33; + } else { + if (reg & I365_VCC_5V) state->Vcc = 50; + if (vpp == I365_VPP1_5V) state->Vpp = 50; + } + if (vpp == I365_VPP1_12V) state->Vpp = 120; + } else if (t->flags & IS_DF_PWR) { + if (vcc == I365_VCC_3V) state->Vcc = 33; + if (vcc == I365_VCC_5V) state->Vcc = 50; + if (vpp == I365_VPP1_5V) state->Vpp = 50; + if (vpp == I365_VPP1_12V) state->Vpp = 120; + } else { + if (reg & I365_VCC_5V) { + state->Vcc = 50; + if (vpp == I365_VPP1_5V) state->Vpp = 50; + if (vpp == I365_VPP1_12V) state->Vpp = 120; + } + } + + /* IO card, RESET flags, IO interrupt */ + reg = i365_get(sock, I365_INTCTL); + state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; + if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD; +#ifdef CONFIG_PCI + if (cb_get_irq_mode(sock) != 0) + state->io_irq = t->cap.pci_irq; + else +#endif + state->io_irq = reg & I365_IRQ_MASK; + + /* speaker control */ + if (t->flags & IS_CIRRUS) { + if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_SPKR_ENA) + state->flags |= SS_SPKR_ENA; + } + + /* Card status change mask */ + reg = i365_get(sock, I365_CSCINT); + state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0; + if (state->flags & SS_IOCARD) + state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0; + else { + state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0; + state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0; + state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0; + } + + DEBUG(1, "i82365: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + return 0; +} /* i365_get_socket */ + +/*====================================================================*/ + +static int i365_set_socket(u_short sock, socket_state_t *state) +{ + socket_info_t *t = &socket[sock]; + u_char reg; + + DEBUG(1, "i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + + /* First set global controller options */ +#ifdef CONFIG_PCI + if ((t->flags & IS_CARDBUS) && t->cap.pci_irq) + cb_set_irq_mode(sock, pci_csc, + (t->cap.pci_irq == state->io_irq)); + t->bcr &= ~CB_BCR_CB_RESET; +#endif + set_host_state(sock); + + /* IO card, RESET flag, IO interrupt */ + reg = t->intr; + if (state->io_irq != t->cap.pci_irq) reg |= state->io_irq; + reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; + reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; + i365_set(sock, I365_INTCTL, reg); + + reg = I365_PWR_NORESET; + if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; + if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; + +#ifdef CONFIG_PCI + if (t->flags & IS_CARDBUS) { + cb_set_power(sock, state); + reg |= i365_get(sock, I365_POWER) & + (I365_VCC_MASK|I365_VPP1_MASK); + } else +#endif + if (t->flags & IS_CIRRUS) { + if (state->Vpp != 0) { + if (state->Vpp == 120) + reg |= I365_VPP1_12V; + else if (state->Vpp == state->Vcc) + reg |= I365_VPP1_5V; + else return -EINVAL; + } + if (state->Vcc != 0) { + reg |= I365_VCC_5V; + if (state->Vcc == 33) + i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); + else if (state->Vcc == 50) + i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); + else return -EINVAL; + } + } else if (t->flags & IS_VG_PWR) { + if (state->Vpp != 0) { + if (state->Vpp == 120) + reg |= I365_VPP1_12V; + else if (state->Vpp == state->Vcc) + reg |= I365_VPP1_5V; + else return -EINVAL; + } + if (state->Vcc != 0) { + reg |= I365_VCC_5V; + if (state->Vcc == 33) + i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC); + else if (state->Vcc == 50) + i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC); + else return -EINVAL; + } + } else if (t->flags & IS_DF_PWR) { + switch (state->Vcc) { + case 0: break; + case 33: reg |= I365_VCC_3V; break; + case 50: reg |= I365_VCC_5V; break; + default: return -EINVAL; + } + switch (state->Vpp) { + case 0: break; + case 50: reg |= I365_VPP1_5V; break; + case 120: reg |= I365_VPP1_12V; break; + default: return -EINVAL; + } + } else { + switch (state->Vcc) { + case 0: break; + case 50: reg |= I365_VCC_5V; break; + default: return -EINVAL; + } + switch (state->Vpp) { + case 0: break; + case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break; + case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break; + default: return -EINVAL; + } + } + + if (reg != i365_get(sock, I365_POWER)) + i365_set(sock, I365_POWER, reg); + + /* Chipset-specific functions */ + if (t->flags & IS_CIRRUS) { + /* Speaker control */ + i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA, + state->flags & SS_SPKR_ENA); + } + + /* Card status change interrupt mask */ + reg = t->cs_irq << 4; + if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; + if (state->flags & SS_IOCARD) { + if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG; + } else { + if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1; + if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2; + if (state->csc_mask & SS_READY) reg |= I365_CSC_READY; + } + i365_set(sock, I365_CSCINT, reg); + i365_get(sock, I365_CSC); + + return 0; +} /* i365_set_socket */ + +/*====================================================================*/ + +static int i365_get_io_map(u_short sock, struct pccard_io_map *io) +{ + u_char map, ioctl, addr; + + map = io->map; + if (map > 1) return -EINVAL; + io->start = i365_get_pair(sock, I365_IO(map)+I365_W_START); + io->stop = i365_get_pair(sock, I365_IO(map)+I365_W_STOP); + ioctl = i365_get(sock, I365_IOCTL); + addr = i365_get(sock, I365_ADDRWIN); + io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0; + io->flags = (addr & I365_ENA_IO(map)) ? MAP_ACTIVE : 0; + io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0; + io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0; + io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0; + DEBUG(1, "i82365: GetIOMap(%d, %d) = %#2.2x, %d ns, " + "%#4.4x-%#4.4x\n", sock, map, io->flags, io->speed, + io->start, io->stop); + return 0; +} /* i365_get_io_map */ + +/*====================================================================*/ + +static int i365_set_io_map(u_short sock, struct pccard_io_map *io) +{ + u_char map, ioctl; + + DEBUG(1, "i82365: SetIOMap(%d, %d, %#2.2x, %d ns, " + "%#4.4x-%#4.4x)\n", sock, io->map, io->flags, + io->speed, io->start, io->stop); + map = io->map; + if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) || + (io->stop < io->start)) return -EINVAL; + /* Turn off the window before changing anything */ + if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map)) + i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map)); + i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start); + i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop); + ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map); + if (io->speed) ioctl |= I365_IOCTL_WAIT(map); + if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); + if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); + if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); + i365_set(sock, I365_IOCTL, ioctl); + /* Turn on the window if necessary */ + if (io->flags & MAP_ACTIVE) + i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map)); + return 0; +} /* i365_set_io_map */ + +/*====================================================================*/ + +static int i365_get_mem_map(u_short sock, struct pccard_mem_map *mem) +{ + u_short base, i; + u_char map, addr; + + map = mem->map; + if (map > 4) return -EINVAL; + addr = i365_get(sock, I365_ADDRWIN); + mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0; + base = I365_MEM(map); + + i = i365_get_pair(sock, base+I365_W_START); + mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0; + mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0; + mem->sys_start += ((u_long)(i & 0x0fff) << 12); + + i = i365_get_pair(sock, base+I365_W_STOP); + mem->speed = (i & I365_MEM_WS0) ? 1 : 0; + mem->speed += (i & I365_MEM_WS1) ? 2 : 0; + mem->speed = to_ns(mem->speed); + mem->sys_stop = ((u_long)(i & 0x0fff) << 12) + 0x0fff; + + i = i365_get_pair(sock, base+I365_W_OFF); + mem->flags |= (i & I365_MEM_WRPROT) ? MAP_WRPROT : 0; + mem->flags |= (i & I365_MEM_REG) ? MAP_ATTRIB : 0; + mem->card_start = ((u_int)(i & 0x3fff) << 12) + mem->sys_start; + mem->card_start &= 0x3ffffff; + +#ifdef CONFIG_PCI + /* Take care of high byte, for PCI controllers */ + if (socket[sock].type == IS_PD6729) { + i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); + addr = i365_get(sock, PD67_EXT_DATA) << 24; + } else if (socket[sock].flags & IS_CARDBUS) { + addr = i365_get(sock, CB_MEM_PAGE(map)) << 24; + mem->sys_stop += addr; mem->sys_start += addr; + } +#endif + + DEBUG(1, "i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5." + "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed, + mem->sys_start, mem->sys_stop, mem->card_start); + return 0; +} /* i365_get_mem_map */ + +/*====================================================================*/ + +static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem) +{ + u_short base, i; + u_char map; + + DEBUG(1, "i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5" + "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed, + mem->sys_start, mem->sys_stop, mem->card_start); + + map = mem->map; + if ((map > 4) || (mem->card_start > 0x3ffffff) || + (mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) + return -EINVAL; + if (!(socket[sock].flags & (IS_PCI | IS_CARDBUS)) && + ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff))) + return -EINVAL; + + /* Turn off the window before changing anything */ + if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map)) + i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map)); + +#ifdef CONFIG_PCI + /* Take care of high byte, for PCI controllers */ + if (socket[sock].type == IS_PD6729) { + i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); + i365_set(sock, PD67_EXT_DATA, (mem->sys_start >> 24)); + } else if (socket[sock].flags & IS_CARDBUS) + i365_set(sock, CB_MEM_PAGE(map), mem->sys_start >> 24); +#endif + + base = I365_MEM(map); + i = (mem->sys_start >> 12) & 0x0fff; + if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT; + if (mem->flags & MAP_0WS) i |= I365_MEM_0WS; + i365_set_pair(sock, base+I365_W_START, i); + + i = (mem->sys_stop >> 12) & 0x0fff; + switch (to_cycles(mem->speed)) { + case 0: break; + case 1: i |= I365_MEM_WS0; break; + case 2: i |= I365_MEM_WS1; break; + default: i |= I365_MEM_WS1 | I365_MEM_WS0; break; + } + i365_set_pair(sock, base+I365_W_STOP, i); + + i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff; + if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT; + if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG; + i365_set_pair(sock, base+I365_W_OFF, i); + + /* Turn on the window if necessary */ + if (mem->flags & MAP_ACTIVE) + i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map)); + return 0; +} /* i365_set_mem_map */ + +/*====================================================================== + + Power control for Cardbus controllers: used both for 16-bit and + Cardbus cards. + +======================================================================*/ + +#ifdef CONFIG_PCI + +static void cb_get_power(u_short sock, socket_state_t *state) +{ + u_int reg = cb_readl(sock, CB_SOCKET_CONTROL); + state->Vcc = state->Vpp = 0; + switch (reg & CB_SC_VCC_MASK) { + case CB_SC_VCC_3V: state->Vcc = 33; break; + case CB_SC_VCC_5V: state->Vcc = 50; break; + } + switch (reg & CB_SC_VCC_MASK) { + case CB_SC_VPP_3V: state->Vpp = 33; break; + case CB_SC_VPP_5V: state->Vpp = 50; break; + case CB_SC_VPP_12V: state->Vpp = 120; break; + } +} + +static void cb_set_power(u_short sock, socket_state_t *state) +{ + u_int reg = 0; + switch (state->Vcc) { + case 33: reg = CB_SC_VCC_3V; break; + case 50: reg = CB_SC_VCC_5V; break; + default: reg = 0; break; + } + switch (state->Vpp) { + case 33: reg |= CB_SC_VPP_3V; break; + case 50: reg |= CB_SC_VPP_5V; break; + case 120: reg |= CB_SC_VPP_12V; break; + } + if (reg != cb_readl(sock, CB_SOCKET_CONTROL)) + cb_writel(sock, CB_SOCKET_CONTROL, reg); +} + +#endif + +/*====================================================================== + + All the stuff that is strictly for Cardbus cards goes here. + +======================================================================*/ + +#ifdef CONFIG_CARDBUS + +static int cb_get_status(u_short sock, u_int *value) +{ + u_int s; + s = cb_readl(sock, CB_SOCKET_STATE); + *value = ((s & CB_SS_32BIT) ? SS_CARDBUS : 0); + *value |= ((s & CB_SS_CCD1) || (s & CB_SS_CCD2)) ? 0 : SS_DETECT; + *value |= (s & CB_SS_CSTSCHG) ? SS_STSCHG : 0; + *value |= (s & CB_SS_PWRCYCLE) ? (SS_POWERON|SS_READY) : 0; + *value |= (s & CB_SS_3VCARD) ? SS_3VCARD : 0; + *value |= (s & CB_SS_XVCARD) ? SS_XVCARD : 0; + DEBUG(1, "yenta: GetStatus(%d) = %#4.4x\n", sock, *value); + return 0; +} /* cb_get_status */ + +static int cb_get_socket(u_short sock, socket_state_t *state) +{ + socket_info_t *s = &socket[sock]; + u_short bcr; + + cb_get_power(sock, state); + pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr); + state->flags |= (bcr & CB_BCR_CB_RESET) ? SS_RESET : 0; + if (cb_get_irq_mode(sock) != 0) + state->io_irq = s->cap.pci_irq; + else + state->io_irq = i365_get(sock, I365_INTCTL) & I365_IRQ_MASK; + DEBUG(1, "yenta: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + return 0; +} /* cb_get_socket */ + +static int cb_set_socket(u_short sock, socket_state_t *state) +{ + socket_info_t *s = &socket[sock]; + u_int reg; + + DEBUG(1, "yenta: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + + /* First set global controller options */ + if (s->cap.pci_irq) + cb_set_irq_mode(sock, pci_csc, + (s->cap.pci_irq == state->io_irq)); + s->bcr &= ~CB_BCR_CB_RESET; + s->bcr |= (state->flags & SS_RESET) ? CB_BCR_CB_RESET : 0; + set_host_state(sock); + + cb_set_power(sock, state); + + /* Handle IO interrupt using ISA routing */ + reg = i365_get(sock, I365_INTCTL) & ~I365_IRQ_MASK; + if (state->io_irq != s->cap.pci_irq) reg |= state->io_irq; + i365_set(sock, I365_INTCTL, reg); + + /* Handle CSC mask */ + reg = (socket[sock].cs_irq << 4); + if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; + i365_set(sock, I365_CSCINT, reg); + i365_get(sock, I365_CSC); + + return 0; +} /* cb_set_socket */ + +static int cb_get_bridge(u_short sock, struct cb_bridge_map *m) +{ + socket_info_t *s = &socket[sock]; + u_char map; + + map = m->map; + if (map > 1) return -EINVAL; + m->flags &= MAP_IOSPACE; + map += (m->flags & MAP_IOSPACE) ? 2 : 0; + pci_readl(s->bus, s->devfn, CB_MEM_BASE(map), &m->start); + pci_readl(s->bus, s->devfn, CB_MEM_LIMIT(map), &m->stop); + if (m->start || m->stop) { + m->flags |= MAP_ACTIVE; + m->stop |= (map > 1) ? 3 : 0x0fff; + } + if (map > 1) { + u_short bcr; + pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr); + m->flags |= (bcr & CB_BCR_PREFETCH(map)) ? MAP_PREFETCH : 0; + } + DEBUG(1, "yenta: GetBridge(%d, %d) = %#2.2x, %#4.4x-%#4.4x\n", + sock, map, m->flags, m->start, m->stop); + return 0; +} + +static int cb_set_bridge(u_short sock, struct cb_bridge_map *m) +{ + socket_info_t *s = &socket[sock]; + u_char map; + + DEBUG(1, "yenta: SetBridge(%d, %d, %#2.2x, %#4.4x-%#4.4x)\n", + sock, m->map, m->flags, m->start, m->stop); + map = m->map; + if (!(s->flags & IS_CARDBUS) || (map > 1) || (m->stop < m->start)) + return -EINVAL; + if (m->flags & MAP_IOSPACE) { + if ((m->stop > 0xffff) || (m->start & 3) || + ((m->stop & 3) != 3)) + return -EINVAL; + map += 2; + } else { + u_short bcr; + if ((m->start & 0x0fff) || ((m->stop & 0x0fff) != 0x0fff)) + return -EINVAL; + pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr); + bcr &= ~CB_BCR_PREFETCH(map); + bcr |= (m->flags & MAP_PREFETCH) ? CB_BCR_PREFETCH(map) : 0; + pci_writew(s->bus, s->devfn, CB_BRIDGE_CONTROL, bcr); + } + if (m->flags & MAP_ACTIVE) { + pci_writel(s->bus, s->devfn, CB_MEM_BASE(map), m->start); + pci_writel(s->bus, s->devfn, CB_MEM_LIMIT(map), m->stop); + } else { + pci_writel(s->bus, s->devfn, CB_IO_BASE(map), 0); + pci_writel(s->bus, s->devfn, CB_IO_LIMIT(map), 0); + } + return 0; +} + +#endif /* CONFIG_CARDBUS */ + +/*====================================================================== + + Routines for accessing socket information and register dumps via + /proc/bus/pccard/... + +======================================================================*/ + +#ifdef CONFIG_PROC_FS + +static int proc_read_info(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + socket_info_t *s = data; + char *p = buf; + p += sprintf(p, "type: %s\npsock: %d\n", + pcic[s->type].name, s->psock); +#ifdef CONFIG_PCI + if (s->flags & (IS_PCI|IS_CARDBUS)) + p += sprintf(p, "bus: %02x\ndevfn: %02x.%1x\n", + s->bus, PCI_SLOT(s->devfn), PCI_FUNC(s->devfn)); + if (s->flags & IS_CARDBUS) + p += sprintf(p, "cardbus: %02x\n", s->cap.cardbus); +#endif + return (p - buf); +} + +static int proc_read_exca(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + u_short sock = (socket_info_t *)data - socket; + char *p = buf; + int i, top; + +#ifdef CONFIG_ISA + u_long flags = 0; + if (!(socket[sock].flags & IS_CARDBUS)) + spin_lock_irqsave(&isa_lock, flags); +#endif + top = 0x40; + if (socket[sock].flags & IS_CARDBUS) + top = (socket[sock].flags & IS_CIRRUS) ? 0x140 : 0x50; + for (i = 0; i < top; i += 4) { + if (i == 0x50) { + p += sprintf(p, "\n"); + i = 0x100; + } + p += sprintf(p, "%02x %02x %02x %02x%s", + i365_get(sock,i), i365_get(sock,i+1), + i365_get(sock,i+2), i365_get(sock,i+3), + ((i % 16) == 12) ? "\n" : " "); + } +#ifdef CONFIG_ISA + if (!(socket[sock].flags & IS_CARDBUS)) + spin_unlock_irqrestore(&isa_lock, flags); +#endif + return (p - buf); +} + + +#ifdef CONFIG_PCI +static int proc_read_pci(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + socket_info_t *s = data; + u_char bus = s->bus, devfn = s->devfn; + char *p = buf; + u_int a, b, c, d; + int i; + + for (i = 0; i < 0xc0; i += 0x10) { + pci_readl(bus, devfn, i, &a); + pci_readl(bus, devfn, i+4, &b); + pci_readl(bus, devfn, i+8, &c); + pci_readl(bus, devfn, i+12, &d); + p += sprintf(p, "%08x %08x %08x %08x\n", a, b, c, d); + } + return (p - buf); +} +#endif + +#ifdef CONFIG_CARDBUS +static int proc_read_cardbus(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + u_short sock = (socket_info_t *)data - socket; + int len; + + len = sprintf(buf, "%08x %08x %08x %08x %08x %08x\n", + cb_readl(sock,0), cb_readl(sock,4), + cb_readl(sock,8), cb_readl(sock,12), + cb_readl(sock,16), cb_readl(sock,32)); + return len; +} +#endif + +static void pcic_proc_setup(u_short sock, struct proc_dir_entry *base) +{ + socket_info_t *s = &socket[sock]; + struct proc_dir_entry *ent; + ent = create_proc_entry("info", 0, base); + ent->read_proc = proc_read_info; + ent->data = s; + ent = create_proc_entry("exca", 0, base); + ent->read_proc = proc_read_exca; + ent->data = s; +#ifdef CONFIG_PCI + if (s->flags & (IS_PCI|IS_CARDBUS)) { + ent = create_proc_entry("pci", 0, base); + ent->read_proc = proc_read_pci; + ent->data = s; + } +#endif +#ifdef CONFIG_CARDBUS + if (s->flags & IS_CARDBUS) { + ent = create_proc_entry("cardbus", 0, base); + ent->read_proc = proc_read_cardbus; + ent->data = s; + } +#endif + s->proc = base; +} + +static void pcic_proc_remove(u_short sock) +{ + struct proc_dir_entry *base = socket[sock].proc; + if (base == NULL) return; + remove_proc_entry("info", base); + remove_proc_entry("exca", base); +#ifdef CONFIG_PCI + if (socket[sock].flags & (IS_PCI|IS_CARDBUS)) + remove_proc_entry("pci", base); +#endif +#ifdef CONFIG_CARDBUS + if (socket[sock].flags & IS_CARDBUS) + remove_proc_entry("cardbus", base); +#endif +} + +#endif /* CONFIG_PROC_FS */ + +/*====================================================================*/ + +typedef int (*subfn_t)(u_short, void *); + +static subfn_t pcic_service_table[] = { + (subfn_t)&pcic_register_callback, + (subfn_t)&pcic_inquire_socket, + (subfn_t)&i365_get_status, + (subfn_t)&i365_get_socket, + (subfn_t)&i365_set_socket, + (subfn_t)&i365_get_io_map, + (subfn_t)&i365_set_io_map, + (subfn_t)&i365_get_mem_map, + (subfn_t)&i365_set_mem_map, +#ifdef CONFIG_CARDBUS + (subfn_t)&cb_get_bridge, + (subfn_t)&cb_set_bridge, +#else + NULL, NULL, +#endif +#ifdef CONFIG_PROC_FS + (subfn_t)&pcic_proc_setup +#endif +}; + +#define NFUNC (sizeof(pcic_service_table)/sizeof(subfn_t)) + +static int pcic_service(u_int sock, u_int cmd, void *arg) +{ + subfn_t fn; + + DEBUG(2, "pcic_ioctl(%d, %d, 0x%p)\n", sock, cmd, arg); + + if (cmd >= NFUNC) + return -EINVAL; + + if (socket[sock].flags & IS_ALIVE) { + if (cmd == SS_GetStatus) + *(u_int *)arg = 0; + return -EINVAL; + } + + fn = pcic_service_table[cmd]; +#ifdef CONFIG_CARDBUS + if ((socket[sock].flags & IS_CARDBUS) && + (cb_readl(sock, CB_SOCKET_STATE) & CB_SS_32BIT)) { + if (cmd == SS_GetStatus) + fn = (subfn_t)&cb_get_status; + else if (cmd == SS_GetSocket) + fn = (subfn_t)&cb_get_socket; + else if (cmd == SS_SetSocket) + fn = (subfn_t)&cb_set_socket; + } +#endif + +#ifdef CONFIG_ISA + if (!(socket[sock].flags & IS_CARDBUS)) { + int ret; + u_long flags; + spin_lock_irqsave(&isa_lock, flags); + ret = (fn == NULL) ? -EINVAL : fn(sock, arg); + spin_unlock_irqrestore(&isa_lock, flags); + return ret; + } +#endif + return (fn == NULL) ? -EINVAL : fn(sock, arg); +} /* pcic_service */ + +/*====================================================================*/ + +int pcmcia_i82365_init(void) +{ + servinfo_t serv; + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "i82365: Card Services release " + "does not match!\n"); + return -1; + } + return pcic_init(); +} + +#ifdef MODULE + +int init_module(void) +{ + return pcmcia_i82365_init(); +} + +void cleanup_module(void) +{ + pcic_finish(); +} + +#endif + +/*====================================================================*/ + diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/i82365.h linux/drivers/pcmcia/i82365.h --- v2.3.16/linux/drivers/pcmcia/i82365.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/i82365.h Fri Sep 3 12:27:58 1999 @@ -0,0 +1,135 @@ +/* + * i82365.h 1.14 1999/08/28 04:01:47 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_I82365_H +#define _LINUX_I82365_H + +/* register definitions for the Intel 82365SL PCMCIA controller */ + +/* Offsets for PCIC registers */ +#define I365_IDENT 0x00 /* Identification and revision */ +#define I365_STATUS 0x01 /* Interface status */ +#define I365_POWER 0x02 /* Power and RESETDRV control */ +#define I365_INTCTL 0x03 /* Interrupt and general control */ +#define I365_CSC 0x04 /* Card status change */ +#define I365_CSCINT 0x05 /* Card status change interrupt control */ +#define I365_ADDRWIN 0x06 /* Address window enable */ +#define I365_IOCTL 0x07 /* I/O control */ +#define I365_GENCTL 0x16 /* Card detect and general control */ +#define I365_GBLCTL 0x1E /* Global control register */ + +/* Offsets for I/O and memory window registers */ +#define I365_IO(map) (0x08+((map)<<2)) +#define I365_MEM(map) (0x10+((map)<<3)) +#define I365_W_START 0 +#define I365_W_STOP 2 +#define I365_W_OFF 4 + +/* Flags for I365_STATUS */ +#define I365_CS_BVD1 0x01 +#define I365_CS_STSCHG 0x01 +#define I365_CS_BVD2 0x02 +#define I365_CS_SPKR 0x02 +#define I365_CS_DETECT 0x0C +#define I365_CS_WRPROT 0x10 +#define I365_CS_READY 0x20 /* Inverted */ +#define I365_CS_POWERON 0x40 +#define I365_CS_GPI 0x80 + +/* Flags for I365_POWER */ +#define I365_PWR_OFF 0x00 /* Turn off the socket */ +#define I365_PWR_OUT 0x80 /* Output enable */ +#define I365_PWR_NORESET 0x40 /* Disable RESETDRV on resume */ +#define I365_PWR_AUTO 0x20 /* Auto pwr switch enable */ +#define I365_VCC_MASK 0x18 /* Mask for turning off Vcc */ +/* There are different layouts for B-step and DF-step chips: the B + step has independent Vpp1/Vpp2 control, and the DF step has only + Vpp1 control, plus 3V control */ +#define I365_VCC_5V 0x10 /* Vcc = 5.0v */ +#define I365_VCC_3V 0x18 /* Vcc = 3.3v */ +#define I365_VPP2_MASK 0x0c /* Mask for turning off Vpp2 */ +#define I365_VPP2_5V 0x04 /* Vpp2 = 5.0v */ +#define I365_VPP2_12V 0x08 /* Vpp2 = 12.0v */ +#define I365_VPP1_MASK 0x03 /* Mask for turning off Vpp1 */ +#define I365_VPP1_5V 0x01 /* Vpp2 = 5.0v */ +#define I365_VPP1_12V 0x02 /* Vpp2 = 12.0v */ + +/* Flags for I365_INTCTL */ +#define I365_RING_ENA 0x80 +#define I365_PC_RESET 0x40 +#define I365_PC_IOCARD 0x20 +#define I365_INTR_ENA 0x10 +#define I365_IRQ_MASK 0x0F + +/* Flags for I365_CSC and I365_CSCINT*/ +#define I365_CSC_BVD1 0x01 +#define I365_CSC_STSCHG 0x01 +#define I365_CSC_BVD2 0x02 +#define I365_CSC_READY 0x04 +#define I365_CSC_DETECT 0x08 +#define I365_CSC_ANY 0x0F +#define I365_CSC_GPI 0x10 + +/* Flags for I365_ADDRWIN */ +#define I365_ENA_IO(map) (0x40 << (map)) +#define I365_ENA_MEM(map) (0x01 << (map)) + +/* Flags for I365_IOCTL */ +#define I365_IOCTL_MASK(map) (0x0F << (map<<2)) +#define I365_IOCTL_WAIT(map) (0x08 << (map<<2)) +#define I365_IOCTL_0WS(map) (0x04 << (map<<2)) +#define I365_IOCTL_IOCS16(map) (0x02 << (map<<2)) +#define I365_IOCTL_16BIT(map) (0x01 << (map<<2)) + +/* Flags for I365_GENCTL */ +#define I365_CTL_16DELAY 0x01 +#define I365_CTL_RESET 0x02 +#define I365_CTL_GPI_ENA 0x04 +#define I365_CTL_GPI_CTL 0x08 +#define I365_CTL_RESUME 0x10 +#define I365_CTL_SW_IRQ 0x20 + +/* Flags for I365_GBLCTL */ +#define I365_GBL_PWRDOWN 0x01 +#define I365_GBL_CSC_LEV 0x02 +#define I365_GBL_WRBACK 0x04 +#define I365_GBL_IRQ_0_LEV 0x08 +#define I365_GBL_IRQ_1_LEV 0x10 + +/* Flags for memory window registers */ +#define I365_MEM_16BIT 0x8000 /* In memory start high byte */ +#define I365_MEM_0WS 0x4000 +#define I365_MEM_WS1 0x8000 /* In memory stop high byte */ +#define I365_MEM_WS0 0x4000 +#define I365_MEM_WRPROT 0x8000 /* In offset high byte */ +#define I365_MEM_REG 0x4000 + +#define I365_REG(slot, reg) (((slot) << 6) + reg) + +#endif /* _LINUX_I82365_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/o2micro.h linux/drivers/pcmcia/o2micro.h --- v2.3.16/linux/drivers/pcmcia/o2micro.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/o2micro.h Tue Sep 7 11:03:10 1999 @@ -0,0 +1,98 @@ +/* + * o2micro.h 1.10 1999/09/03 16:43:35 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_O2MICRO_H +#define _LINUX_O2MICRO_H + +#ifndef PCI_VENDOR_ID_O2 +#define PCI_VENDOR_ID_O2 0x1217 +#endif +#ifndef PCI_DEVICE_ID_O2_6729 +#define PCI_DEVICE_ID_O2_6729 0x6729 +#endif +#ifndef PCI_DEVICE_ID_O2_6730 +#define PCI_DEVICE_ID_O2_6730 0x673a +#endif +#ifndef PCI_DEVICE_ID_O2_6832 +#define PCI_DEVICE_ID_O2_6832 0x6832 +#endif +#ifndef PCI_DEVICE_ID_O2_6836 +#define PCI_DEVICE_ID_O2_6836 0x6836 +#endif + +#define O2_MODE_A 0x38 +#define O2_MODE_A_2 0x26 /* For 6833B, 6860C */ +#define O2_MODE_A_CD_PULSE 0x04 +#define O2_MODE_A_SUSP_EDGE 0x08 +#define O2_MODE_A_HOST_SUSP 0x10 +#define O2_MODE_A_PWRCHIP 0x60 +#define O2_MODE_A_QUIET 0x80 + +#define O2_MODE_B 0x39 +#define O2_MODE_B_2 0x2e /* For 6833B, 6860C */ +#define O2_MODE_B_IDENT 0x03 +#define O2_MODE_B_ID_BSTEP 0x00 +#define O2_MODE_B_ID_CSTEP 0x01 +#define O2_MODE_B_ID_O2 0x02 +#define O2_MODE_B_VS1 0x04 +#define O2_MODE_B_VS2 0x08 +#define O2_MODE_B_IRQ15_RI 0x80 + +#define O2_MODE_C 0x3a +#define O2_MODE_C_DREQ_MASK 0x03 +#define O2_MODE_C_DREQ_INPACK 0x01 +#define O2_MODE_C_DREQ_WP 0x02 +#define O2_MODE_C_DREQ_BVD2 0x03 +#define O2_MODE_C_ZVIDEO 0x08 + +#define O2_MODE_D 0x3b +#define O2_MODE_D_IRQ_MODE 0x03 +#define O2_MODE_D_SKT_ACTV 0x20 +#define O2_MODE_D_PCI_FIFO 0x40 /* for OZ6729, OZ6730 */ +#define O2_MODE_D_W97_IRQ 0x40 /* for OZ6832 */ +#define O2_MODE_D_ISA_IRQ 0x80 + +#define O2_MHPG_DMA 0x3c +#define O2_MHPG_CHANNEL 0x07 +#define O2_MHPG_CINT_ENA 0x08 +#define O2_MHPG_CSC_ENA 0x10 + +#define O2_FIFO_ENA 0x3d +#define O2_FIFO_ZVIDEO_3 0x08 +#define O2_FIFO_PCI_FIFO 0x10 +#define O2_FIFO_POSTWR 0x40 +#define O2_FIFO_BUFFER 0x80 + +#define O2_MODE_E 0x3e +#define O2_MODE_E_MHPG_DMA 0x01 +#define O2_MODE_E_SPKR_OUT 0x02 +#define O2_MODE_E_LED_OUT 0x08 +#define O2_MODE_E_SKTA_ACTV 0x10 + +#endif /* _LINUX_O2MICRO_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/ricoh.h linux/drivers/pcmcia/ricoh.h --- v2.3.16/linux/drivers/pcmcia/ricoh.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/ricoh.h Fri Sep 3 12:27:58 1999 @@ -0,0 +1,132 @@ +/* + * ricoh.h 1.8 1999/08/28 04:01:47 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_RICOH_H +#define _LINUX_RICOH_H + +#define RF5C_MODE_CTL 0x1f /* Mode control */ +#define RF5C_PWR_CTL 0x2f /* Mixed voltage control */ +#define RF5C_CHIP_ID 0x3a /* Chip identification */ +#define RF5C_MODE_CTL_3 0x3b /* Mode control 3 */ + +/* I/O window address offset */ +#define RF5C_IO_OFF(w) (0x36+((w)<<1)) + +/* Flags for RF5C_MODE_CTL */ +#define RF5C_MODE_ATA 0x01 /* ATA mode */ +#define RF5C_MODE_LED_ENA 0x02 /* IRQ 12 is LED */ +#define RF5C_MODE_CA21 0x04 +#define RF5C_MODE_CA22 0x08 +#define RF5C_MODE_CA23 0x10 +#define RF5C_MODE_CA24 0x20 +#define RF5C_MODE_CA25 0x40 +#define RF5C_MODE_3STATE_BIT7 0x80 + +/* Flags for RF5C_PWR_CTL */ +#define RF5C_PWR_VCC_3V 0x01 +#define RF5C_PWR_IREQ_HIGH 0x02 +#define RF5C_PWR_INPACK_ENA 0x04 +#define RF5C_PWR_5V_DET 0x08 +#define RF5C_PWR_TC_SEL 0x10 /* Terminal Count: irq 11 or 15 */ +#define RF5C_PWR_DREQ_LOW 0x20 +#define RF5C_PWR_DREQ_OFF 0x00 /* DREQ steering control */ +#define RF5C_PWR_DREQ_INPACK 0x40 +#define RF5C_PWR_DREQ_SPKR 0x80 +#define RF5C_PWR_DREQ_IOIS16 0xc0 + +/* Values for RF5C_CHIP_ID */ +#define RF5C_CHIP_RF5C296 0x32 +#define RF5C_CHIP_RF5C396 0xb2 + +/* Flags for RF5C_MODE_CTL_3 */ +#define RF5C_MCTL3_DISABLE 0x01 /* Disable PCMCIA interface */ +#define RF5C_MCTL3_DMA_ENA 0x02 + +/* Register definitions for Ricoh PCI-to-CardBus bridges */ + +#ifndef PCI_VENDOR_ID_RICOH +#define PCI_VENDOR_ID_RICOH 0x1180 +#endif +#ifndef PCI_DEVICE_ID_RICOH_RL5C465 +#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465 +#endif +#ifndef PCI_DEVICE_ID_RICOH_RL5C466 +#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466 +#endif +#ifndef PCI_DEVICE_ID_RICOH_RL5C475 +#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475 +#endif +#ifndef PCI_DEVICE_ID_RICOH_RL5C476 +#define PCI_DEVICE_ID_RICOH_RL5C476 0x0476 +#endif +#ifndef PCI_DEVICE_ID_RICOH_RL5C478 +#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478 +#endif + +/* Extra bits in CB_BRIDGE_CONTROL */ +#define RL5C46X_BCR_3E0_ENA 0x0800 +#define RL5C46X_BCR_3E2_ENA 0x1000 + +/* Misc Control Register */ +#define RL5C4XX_MISC 0x0082 /* 16 bit */ +#define RL5C4XX_MISC_HW_SUSPEND_ENA 0x0002 +#define RL5C4XX_MISC_VCCEN_POL 0x0100 +#define RL5C4XX_MISC_VPPEN_POL 0x0200 +#define RL5C46X_MISC_SUSPEND 0x0001 +#define RL5C46X_MISC_PWR_SAVE_2 0x0004 +#define RL5C46X_MISC_IFACE_BUSY 0x0008 +#define RL5C46X_MISC_B_LOCK 0x0010 +#define RL5C46X_MISC_A_LOCK 0x0020 +#define RL5C46X_MISC_PCI_LOCK 0x0040 +#define RL5C47X_MISC_IFACE_BUSY 0x0004 +#define RL5C47X_MISC_PCI_INT_MASK 0x0018 +#define RL5C47X_MISC_PCI_INT_DIS 0x0020 +#define RL5C47X_MISC_SUBSYS_WR 0x0040 +#define RL5C47X_MISC_SRIRQ_ENA 0x0080 +#define RL5C47X_MISC_5V_DISABLE 0x0400 +#define RL5C47X_MISC_LED_POL 0x0800 + +/* 16-bit Interface Control Register */ +#define RL5C4XX_16BIT_CTL 0x0084 /* 16 bit */ +#define RL5C4XX_16CTL_IO_TIMING 0x0100 +#define RL5C4XX_16CTL_MEM_TIMING 0x0200 +#define RL5C46X_16CTL_LEVEL_1 0x0010 +#define RL5C46X_16CTL_LEVEL_2 0x0020 + +/* 16-bit IO and memory timing registers */ +#define RL5C4XX_16BIT_IO_0 0x0088 /* 16 bit */ +#define RL5C4XX_16BIT_MEM_0 0x0088 /* 16 bit */ +#define RL5C4XX_SETUP_MASK 0x0007 +#define RL5C4XX_SETUP_SHIFT 0 +#define RL5C4XX_CMD_MASK 0x01f0 +#define RL5C4XX_CMD_SHIFT 4 +#define RL5C4XX_HOLD_MASK 0x1c00 +#define RL5C4XX_HOLD_SHIFT 10 + +#endif /* _LINUX_RICOH_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c --- v2.3.16/linux/drivers/pcmcia/rsrc_mgr.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/rsrc_mgr.c Tue Sep 7 11:03:10 1999 @@ -0,0 +1,802 @@ +/*====================================================================== + + Resource management routines + + rsrc_mgr.c 1.70 1999/09/07 15:19:32 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#define __NO_VERSION__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "cs_internal.h" +#include "rsrc_mgr.h" + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Should we probe resources for conflicts? */ +static int probe_mem = 1; +MODULE_PARM(probe_mem, "i"); +#ifdef CONFIG_ISA +static int probe_io = 1; +static int mem_limit = 0x10000; +MODULE_PARM(probe_io, "i"); +MODULE_PARM(mem_limit, "i"); +#endif + +/*====================================================================== + + The resource_map_t structures are used to track what resources are + available for allocation for PC Card devices. + +======================================================================*/ + +typedef struct resource_map_t { + u_long base, num; + struct resource_map_t *next; +} resource_map_t; + +/* Memory resource database */ +static resource_map_t mem_db = { 0, 0, &mem_db }; + +/* IO port resource database */ +static resource_map_t io_db = { 0, 0, &io_db }; + +#ifdef CONFIG_ISA + +typedef struct irq_info_t { + u_int Attributes; + int time_share, dyn_share; + struct socket_info_t *Socket; +} irq_info_t; + +/* Table of IRQ assignments */ +static irq_info_t irq_table[NR_IRQS] = { { 0, 0, 0 }, /* etc */ }; + +#endif + +static spinlock_t rsrc_lock = SPIN_LOCK_UNLOCKED; + +/*====================================================================== + + Linux resource management extensions + +======================================================================*/ + +typedef struct resource_entry_t { + u_long base, num; + char *name; + struct resource_entry_t *next; +} resource_entry_t; + +/* Ordered linked lists of allocated IO and memory blocks */ +static resource_entry_t io_list = { 0, 0, NULL, NULL }; +#ifndef HAVE_MEMRESERVE +static resource_entry_t mem_list = { 0, 0, NULL, NULL }; +#endif + +static resource_entry_t *find_gap(resource_entry_t *root, + resource_entry_t *entry) +{ + resource_entry_t *p; + + if (entry->base > entry->base+entry->num-1) + return NULL; + for (p = root; ; p = p->next) { + if ((p != root) && (p->base+p->num-1 >= entry->base)) { + p = NULL; + break; + } + if ((p->next == NULL) || + (p->next->base > entry->base+entry->num-1)) + break; + } + return p; +} + +static int register_my_resource(resource_entry_t *list, + u_long base, u_long num, char *name) +{ + u_long flags; + resource_entry_t *p, *entry; + + entry = kmalloc(sizeof(resource_entry_t), GFP_ATOMIC); + entry->base = base; + entry->num = num; + entry->name = name; + + spin_lock_irqsave(&rsrc_lock, flags); + p = find_gap(list, entry); + if (p == NULL) { + spin_unlock_irqrestore(&rsrc_lock, flags); + kfree(entry); + return -EBUSY; + } + entry->next = p->next; + p->next = entry; + spin_unlock_irqrestore(&rsrc_lock, flags); + return 0; +} + +static void release_my_resource(resource_entry_t *list, + u_long base, u_long num) +{ + u_long flags; + resource_entry_t *p, *q; + + spin_lock_irqsave(&rsrc_lock, flags); + for (p = list; ; p = q) { + q = p->next; + if (q == NULL) break; + if ((q->base == base) && (q->num == num)) { + p->next = q->next; + kfree(q); + spin_unlock_irqrestore(&rsrc_lock, flags); + return; + } + } + spin_unlock_irqrestore(&rsrc_lock, flags); + return; +} + +static int check_my_resource(resource_entry_t *list, + u_long base, u_long num) +{ + if (register_my_resource(list, base, num, NULL) != 0) + return -EBUSY; + release_my_resource(list, base, num); + return 0; +} + +int check_io_region(u_long base, u_long num) +{ + return check_my_resource(&io_list, base, num); +} +void request_io_region(u_long base, u_long num, char *name) +{ + register_my_resource(&io_list, base, num, name); +} +void release_io_region(u_long base, u_long num) +{ + release_my_resource(&io_list, base, num); +} +#ifdef CONFIG_PROC_FS +int proc_read_io(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + resource_entry_t *r; + u_long flags; + char *p = buf; + + spin_lock_irqsave(&rsrc_lock, flags); + for (r = io_list.next; r; r = r->next) + p += sprintf(p, "%04lx-%04lx : %s\n", r->base, + r->base+r->num-1, r->name); + spin_unlock_irqrestore(&rsrc_lock, flags); + return (p - buf); +} +#endif + + +/*====================================================================== + + These manage the internal databases of available resources. + +======================================================================*/ + +static int add_interval(resource_map_t *map, u_long base, u_long num) +{ + resource_map_t *p, *q; + + for (p = map; ; p = p->next) { + if ((p != map) && (p->base+p->num-1 >= base)) + return -1; + if ((p->next == map) || (p->next->base > base+num-1)) + break; + } + q = kmalloc(sizeof(resource_map_t), GFP_KERNEL); + q->base = base; q->num = num; + q->next = p->next; p->next = q; + return 0; +} /* add_interval */ + +/*====================================================================*/ + +static int sub_interval(resource_map_t *map, u_long base, u_long num) +{ + resource_map_t *p, *q; + + for (p = map; ; p = q) { + q = p->next; + if (q == map) + break; + if ((q->base+q->num > base) && (base+num > q->base)) { + if (q->base >= base) { + if (q->base+q->num <= base+num) { + /* Delete whole block */ + p->next = q->next; + kfree(q); + /* don't advance the pointer yet */ + q = p; + } else { + /* Cut off bit from the front */ + q->num = q->base + q->num - base - num; + q->base = base + num; + } + } else if (q->base+q->num <= base+num) { + /* Cut off bit from the end */ + q->num = base - q->base; + } else { + /* Split the block into two pieces */ + p = kmalloc(sizeof(resource_map_t), GFP_KERNEL); + p->base = base+num; + p->num = q->base+q->num - p->base; + q->num = base - q->base; + p->next = q->next ; q->next = p; + } + } + } + return 0; +} /* sub_interval */ + +/*====================================================================== + + These routines examine a region of IO or memory addresses to + determine what ranges might be genuinely available. + +======================================================================*/ + +#ifdef CONFIG_ISA +static void do_io_probe(ioaddr_t base, ioaddr_t num) +{ + + ioaddr_t i, j, bad, any; + u_char *b, hole, most; + + printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:", + base, base+num-1); + + /* First, what does a floating port look like? */ + b = kmalloc(256, GFP_KERNEL); + memset(b, 0, 256); + for (i = base, most = 0; i < base+num; i += 8) { + if (check_region(i, 8) || check_io_region(i, 8)) + continue; + hole = inb(i); + for (j = 1; j < 8; j++) + if (inb(i+j) != hole) break; + if ((j == 8) && (++b[hole] > b[most])) + most = hole; + if (b[most] == 127) break; + } + kfree(b); + + bad = any = 0; + for (i = base; i < base+num; i += 8) { + if (check_region(i, 8) || check_io_region(i, 8)) + continue; + for (j = 0; j < 8; j++) + if (inb(i+j) != most) break; + if (j < 8) { + if (!any) + printk(" excluding"); + if (!bad) + bad = any = i; + } else { + if (bad) { + sub_interval(&io_db, bad, i-bad); + printk(" %#04x-%#04x", bad, i-1); + bad = 0; + } + } + } + if (bad) { + if ((num > 16) && (bad == base) && (i == base+num)) { + printk(" nothing: probe failed.\n"); + return; + } else { + sub_interval(&io_db, bad, i-bad); + printk(" %#04x-%#04x", bad, i-1); + } + } + + printk(any ? "\n" : " clean.\n"); +} +#endif + +/*====================================================================== + + The memory probe. If the memory list includes a 64K-aligned block + below 1MB, we probe in 64K chunks, and as soon as we accumulate at + least mem_limit free space, we quit. + +======================================================================*/ + +static int do_mem_probe(u_long base, u_long num, + int (*is_valid)(u_long), int (*do_cksum)(u_long)) +{ + u_long i, j, bad, fail, step; + + printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:", + base, base+num-1); + + bad = fail = 0; + step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); + for (i = base; i < base+num; i = j + step) { + if (!fail) { + for (j = i; j < base+num; j += step) + if ((check_mem_region(j, step) == 0) && is_valid(j)) + break; + fail = ((i == base) && (j == base+num)); + } + if (fail) { + for (j = i; j < base+num; j += 2*step) + if ((check_mem_region(j, 2*step) == 0) && + do_cksum(j) && do_cksum(j+step)) + break; + } + if (i != j) { + if (!bad) printk(" excluding"); + printk(" %#05lx-%#05lx", i, j-1); + sub_interval(&mem_db, i, j-i); + bad += j-i; + } + } + printk(bad ? "\n" : " clean.\n"); + + return (num - bad); +} + +#ifdef CONFIG_ISA + +static u_long inv_probe(int (*is_valid)(u_long), + int (*do_cksum)(u_long), + resource_map_t *m) +{ + u_long ok; + if (m == &mem_db) + return 0; + ok = inv_probe(is_valid, do_cksum, m->next); + if (ok) { + if (m->base >= 0x100000) + sub_interval(&mem_db, m->base, m->num); + return ok; + } + if (m->base < 0x100000) + return 0; + return do_mem_probe(m->base, m->num, is_valid, do_cksum); +} + +void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), + int force_low) +{ + resource_map_t *m, *n; + static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; + static int hi = 0, lo = 0; + u_long b, i, ok = 0; + + if (!probe_mem) return; + /* We do up to four passes through the list */ + if (!force_low) { + if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0)) + return; + printk(KERN_NOTICE "cs: warning: no high memory space " + "available!\n"); + } + if (lo++) return; + for (m = mem_db.next; m != &mem_db; m = n) { + n = m->next; + /* Only probe < 1 MB */ + if (m->base >= 0x100000) continue; + if ((m->base | m->num) & 0xffff) { + ok += do_mem_probe(m->base, m->num, is_valid, do_cksum); + continue; + } + /* Special probe for 64K-aligned block */ + for (i = 0; i < 4; i++) { + b = order[i] << 12; + if ((b >= m->base) && (b+0x10000 <= m->base+m->num)) { + if (ok >= mem_limit) + sub_interval(&mem_db, b, 0x10000); + else + ok += do_mem_probe(b, 0x10000, is_valid, do_cksum); + } + } + } +} + +#else /* CONFIG_ISA */ + +void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), + int force_low) +{ + resource_map_t *m; + static int done = 0; + + if (!probe_mem || done++) + return; + for (m = mem_db.next; m != &mem_db; m = m->next) + if (do_mem_probe(m->base, m->num, is_valid, do_cksum)) + return; +} + +#endif /* CONFIG_ISA */ + +/*====================================================================== + + These find ranges of I/O ports or memory addresses that are not + currently allocated by other devices. + +======================================================================*/ + +int find_io_region(ioaddr_t *base, ioaddr_t num, char *name) +{ + ioaddr_t align; + resource_map_t *m; + + if (*base != 0) { + for (m = io_db.next; m != &io_db; m = m->next) { + if ((*base >= m->base) && (*base+num <= m->base+m->num)) { + if (check_region(*base, num) || + check_io_region(*base, num)) { + return -1; + } else { + request_region(*base, num, name); + return 0; + } + } + } + return -1; + } + + for (align = 1; align < num; align *= 2) ; + + for (m = io_db.next; m != &io_db; m = m->next) { + for (*base = (m->base + align - 1) & (~(align-1)); + *base+align <= m->base + m->num; + *base += align) + if ((check_region(*base, num) == 0) && + (check_io_region(*base, num) == 0)) { + request_region(*base, num, name); + return 0; + } + } + return -1; +} /* find_io_region */ + +int find_mem_region(u_long *base, u_long num, char *name, + u_long align, int force_low) +{ + resource_map_t *m; + + if (*base != 0) { + for (m = mem_db.next; m != &mem_db; m = m->next) { + if ((*base >= m->base) && (*base+num <= m->base+m->num)) + if (check_mem_region(*base, num) == 0) { + request_mem_region(*base, num, name); + return 0; + } + } + return -1; + } + + while (1) { + for (m = mem_db.next; m != &mem_db; m = m->next) { + /* first pass >1MB, second pass <1MB */ + if ((force_low != 0) ^ (m->base < 0x100000)) continue; + for (*base = (m->base + align - 1) & (~(align-1)); + *base+num <= m->base+m->num; *base += align) + if (check_mem_region(*base, num) == 0) { + request_mem_region(*base, num, name); + return 0; + } + } + if (force_low) break; + force_low++; + } + return -1; +} /* find_mem_region */ + +/*====================================================================== + + This checks to see if an interrupt is available, with support + for interrupt sharing. We don't support reserving interrupts + yet. If the interrupt is available, we allocate it. + +======================================================================*/ + +#ifdef CONFIG_ISA + +static void fake_irq(int i, void *d, struct pt_regs *r) { } +static inline int check_irq(int irq) +{ + if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0) + return -1; + free_irq(irq, NULL); + return 0; +} + +int try_irq(u_int Attributes, int irq, int specific) +{ + irq_info_t *info = &irq_table[irq]; + if (info->Attributes & RES_ALLOCATED) { + switch (Attributes & IRQ_TYPE) { + case IRQ_TYPE_EXCLUSIVE: + return CS_IN_USE; + case IRQ_TYPE_TIME: + if ((info->Attributes & RES_IRQ_TYPE) + != RES_IRQ_TYPE_TIME) + return CS_IN_USE; + if (Attributes & IRQ_FIRST_SHARED) + return CS_BAD_ATTRIBUTE; + info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED; + info->time_share++; + break; + case IRQ_TYPE_DYNAMIC_SHARING: + if ((info->Attributes & RES_IRQ_TYPE) + != RES_IRQ_TYPE_DYNAMIC) + return CS_IN_USE; + if (Attributes & IRQ_FIRST_SHARED) + return CS_BAD_ATTRIBUTE; + info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED; + info->dyn_share++; + break; + } + } else { + if ((info->Attributes & RES_RESERVED) && !specific) + return CS_IN_USE; + if (check_irq(irq) != 0) + return CS_IN_USE; + switch (Attributes & IRQ_TYPE) { + case IRQ_TYPE_EXCLUSIVE: + info->Attributes |= RES_ALLOCATED; + break; + case IRQ_TYPE_TIME: + if (!(Attributes & IRQ_FIRST_SHARED)) + return CS_BAD_ATTRIBUTE; + info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED; + info->time_share = 1; + break; + case IRQ_TYPE_DYNAMIC_SHARING: + if (!(Attributes & IRQ_FIRST_SHARED)) + return CS_BAD_ATTRIBUTE; + info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED; + info->dyn_share = 1; + break; + } + } + return 0; +} /* try_irq */ + +#endif + +/*====================================================================*/ + +#ifdef CONFIG_ISA + +void undo_irq(u_int Attributes, int irq) +{ + irq_info_t *info; + + info = &irq_table[irq]; + switch (Attributes & IRQ_TYPE) { + case IRQ_TYPE_EXCLUSIVE: + info->Attributes &= RES_RESERVED; + break; + case IRQ_TYPE_TIME: + info->time_share--; + if (info->time_share == 0) + info->Attributes &= RES_RESERVED; + break; + case IRQ_TYPE_DYNAMIC_SHARING: + info->dyn_share--; + if (info->dyn_share == 0) + info->Attributes &= RES_RESERVED; + break; + } +} + +#endif + +/*====================================================================== + + The various adjust_* calls form the external interface to the + resource database. + +======================================================================*/ + +static int adjust_memory(adjust_t *adj) +{ + u_long base, num; + int i; + + base = adj->resource.memory.Base; + num = adj->resource.memory.Size; + if ((num == 0) || (base+num-1 < base)) + return CS_BAD_SIZE; + + switch (adj->Action) { + case ADD_MANAGED_RESOURCE: + if (add_interval(&mem_db, base, num) != 0) + return CS_IN_USE; + break; + case REMOVE_MANAGED_RESOURCE: + sub_interval(&mem_db, base, num); + for (i = 0; i < sockets; i++) { + release_cis_mem(socket_table[i]); +#ifdef CONFIG_CARDBUS + cb_release_cis_mem(socket_table[i]); +#endif + } + break; + default: + return CS_UNSUPPORTED_FUNCTION; + break; + } + + return CS_SUCCESS; +} /* adjust_mem */ + +/*====================================================================*/ + +static int adjust_io(adjust_t *adj) +{ + int base, num; + + base = adj->resource.io.BasePort; + num = adj->resource.io.NumPorts; + if ((base < 0) || (base > 0xffff)) + return CS_BAD_BASE; + if ((num <= 0) || (base+num > 0x10000) || (base+num <= base)) + return CS_BAD_SIZE; + + switch (adj->Action) { + case ADD_MANAGED_RESOURCE: + if (add_interval(&io_db, base, num) != 0) + return CS_IN_USE; +#ifdef CONFIG_ISA + if (probe_io) + do_io_probe(base, num); +#endif + break; + case REMOVE_MANAGED_RESOURCE: + sub_interval(&io_db, base, num); + break; + default: + return CS_UNSUPPORTED_FUNCTION; + break; + } + + return CS_SUCCESS; +} /* adjust_io */ + +/*====================================================================*/ + +static int adjust_irq(adjust_t *adj) +{ +#ifdef CONFIG_ISA + int irq; + irq_info_t *info; + + irq = adj->resource.irq.IRQ; + if ((irq < 0) || (irq > 15)) + return CS_BAD_IRQ; + info = &irq_table[irq]; + + switch (adj->Action) { + case ADD_MANAGED_RESOURCE: + if (info->Attributes & RES_REMOVED) + info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED); + else + if (adj->Attributes & RES_ALLOCATED) + return CS_IN_USE; + if (adj->Attributes & RES_RESERVED) + info->Attributes |= RES_RESERVED; + else + info->Attributes &= ~RES_RESERVED; + break; + case REMOVE_MANAGED_RESOURCE: + if (info->Attributes & RES_REMOVED) + return 0; + if (info->Attributes & RES_ALLOCATED) + return CS_IN_USE; + info->Attributes |= RES_ALLOCATED|RES_REMOVED; + info->Attributes &= ~RES_RESERVED; + break; + default: + return CS_UNSUPPORTED_FUNCTION; + break; + } +#endif + return CS_SUCCESS; +} /* adjust_irq */ + +/*====================================================================*/ + +int adjust_resource_info(client_handle_t handle, adjust_t *adj) +{ + if (CHECK_HANDLE(handle)) + return CS_BAD_HANDLE; + + switch (adj->Resource) { + case RES_MEMORY_RANGE: + return adjust_memory(adj); + break; + case RES_IO_RANGE: + return adjust_io(adj); + break; + case RES_IRQ: + return adjust_irq(adj); + break; + } + return CS_UNSUPPORTED_FUNCTION; +} /* adjust_resource_info */ + +/*====================================================================*/ + +void release_resource_db(void) +{ + resource_map_t *p, *q; + resource_entry_t *u, *v; + + for (p = mem_db.next; p != &mem_db; p = q) { + q = p->next; + kfree(p); + } + for (p = io_db.next; p != &io_db; p = q) { + q = p->next; + kfree(p); + } + for (u = io_list.next; u; u = v) { + v = u->next; + kfree(u); + } +#ifndef HAVE_MEMRESERVE + for (u = mem_list.next; u; u = v) { + v = u->next; + kfree(u); + } +#endif +} diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/rsrc_mgr.h linux/drivers/pcmcia/rsrc_mgr.h --- v2.3.16/linux/drivers/pcmcia/rsrc_mgr.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/rsrc_mgr.h Fri Sep 3 12:27:58 1999 @@ -0,0 +1,39 @@ +/* + * rsrc_mgr.h 1.18 1999/08/28 04:01:47 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _RSRC_MGR_H +#define _RSRC_MGR_H + +#ifdef __BEOS__ +int check_resource(int type, u_long base, u_long num); +int register_resource(int type, u_long base, u_long num); +int release_resource(int type, u_long base, u_long num); +#endif + +#endif /* _RSRC_MGR_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/smc34c90.h linux/drivers/pcmcia/smc34c90.h --- v2.3.16/linux/drivers/pcmcia/smc34c90.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/smc34c90.h Fri Sep 3 12:27:58 1999 @@ -0,0 +1,52 @@ +/* + * smc34c90.h 1.6 1999/08/28 04:01:47 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_SMC34C90_H +#define _LINUX_SMC34C90_H + +#ifndef PCI_VENDOR_ID_SMC +#define PCI_VENDOR_ID_SMC 0x10b3 +#endif + +#ifndef PCI_DEVICE_ID_SMC_34C90 +#define PCI_DEVICE_ID_SMC_34C90 0xb106 +#endif + +/* Register definitions for SMC 34C90 PCI-to-CardBus bridge */ + +/* EEPROM Information Register */ +#define SMC34C90_EEINFO 0x0088 +#define SMC34C90_EEINFO_ONE_SOCKET 0x0001 +#define SMC34C90_EEINFO_5V_ONLY 0x0002 +#define SMC34C90_EEINFO_ISA_IRQ 0x0004 +#define SMC34C90_EEINFO_ZV_PORT 0x0008 +#define SMC34C90_EEINFO_RING 0x0010 +#define SMC34C90_EEINFO_LED 0x0020 + +#endif /* _LINUX_SMC34C90_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/tcic.c linux/drivers/pcmcia/tcic.c --- v2.3.16/linux/drivers/pcmcia/tcic.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/tcic.c Tue Sep 7 11:03:10 1999 @@ -0,0 +1,979 @@ +/*====================================================================== + + Device driver for Databook TCIC-2 PCMCIA controller + + tcic.c 1.105 1999/09/06 06:55:14 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "tcic.h" + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +static const char *version = +"tcic.c 1.105 1999/09/06 06:55:14 (David Hinds)"; +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* The base port address of the TCIC-2 chip */ +static int tcic_base = TCIC_BASE; + +/* Specify a socket number to ignore */ +static int ignore = -1; + +/* Probe for safe interrupts? */ +static int do_scan = 1; + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xffff; +static int irq_list[16] = { -1 }; + +/* The card status change interrupt -- 0 means autoselect */ +static int cs_irq = 0; + +/* Poll status interval -- 0 means default to interrupt */ +static int poll_interval = 0; + +/* Delay for card status double-checking */ +static int poll_quick = HZ/20; + +/* CCLK external clock time, in nanoseconds. 70 ns = 14.31818 MHz */ +static int cycle_time = 70; + +MODULE_PARM(tcic_base, "i"); +MODULE_PARM(ignore, "i"); +MODULE_PARM(do_scan, "i"); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-16i"); +MODULE_PARM(cs_irq, "i"); +MODULE_PARM(poll_interval, "i"); +MODULE_PARM(poll_quick, "i"); +MODULE_PARM(cycle_time, "i"); + +/*====================================================================*/ + +static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs); +static void tcic_timer(u_long data); +static int tcic_service(u_int sock, u_int cmd, void *arg); + +typedef struct socket_info_t { + u_short psock; + void (*handler)(void *info, u_int events); + void *info; + u_char last_sstat; + u_char id; +} socket_info_t; + +static struct timer_list poll_timer; +static int tcic_timer_pending = 0; + +static int sockets; +static socket_info_t socket_table[2]; + +static socket_cap_t tcic_cap = { + /* only 16-bit cards, memory windows must be size-aligned */ + SS_CAP_PCCARD | SS_CAP_MEM_ALIGN, + 0x4cf8, /* irq 14, 11, 10, 7, 6, 5, 4, 3 */ + 0x1000, /* 4K minimum window size */ + 0, 0 /* No PCI or CardBus support */ +}; + +/*====================================================================*/ + +/* Trick when selecting interrupts: the TCIC sktirq pin is supposed + to map to irq 11, but is coded as 0 or 1 in the irq registers. */ +#define TCIC_IRQ(x) ((x) ? (((x) == 11) ? 1 : (x)) : 15) + +#ifdef PCMCIA_DEBUG_X +static u_char tcic_getb(u_char reg) +{ + u_char val = inb(tcic_base+reg); + printk(KERN_DEBUG "tcic_getb(%#x) = %#x\n", tcic_base+reg, val); + return val; +} + +static u_short tcic_getw(u_char reg) +{ + u_short val = inw(tcic_base+reg); + printk(KERN_DEBUG "tcic_getw(%#x) = %#x\n", tcic_base+reg, val); + return val; +} + +static void tcic_setb(u_char reg, u_char data) +{ + printk(KERN_DEBUG "tcic_setb(%#x, %#x)\n", tcic_base+reg, data); + outb(data, tcic_base+reg); +} + +static void tcic_setw(u_char reg, u_short data) +{ + printk(KERN_DEBUG "tcic_setw(%#x, %#x)\n", tcic_base+reg, data); + outw(data, tcic_base+reg); +} +#else +#define tcic_getb(reg) inb(tcic_base+reg) +#define tcic_getw(reg) inw(tcic_base+reg) +#define tcic_setb(reg, data) outb(data, tcic_base+reg) +#define tcic_setw(reg, data) outw(data, tcic_base+reg) +#endif + +static void tcic_setl(u_char reg, u_int data) +{ +#ifdef PCMCIA_DEBUG_X + printk(KERN_DEBUG "tcic_setl(%#x, %#lx)\n", tcic_base+reg, data); +#endif + outw(data & 0xffff, tcic_base+reg); + outw(data >> 16, tcic_base+reg+2); +} + +static u_char tcic_aux_getb(u_short reg) +{ + u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; + tcic_setb(TCIC_MODE, mode); + return tcic_getb(TCIC_AUX); +} + +static void tcic_aux_setb(u_short reg, u_char data) +{ + u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; + tcic_setb(TCIC_MODE, mode); + tcic_setb(TCIC_AUX, data); +} + +static u_short tcic_aux_getw(u_short reg) +{ + u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; + tcic_setb(TCIC_MODE, mode); + return tcic_getw(TCIC_AUX); +} + +static void tcic_aux_setw(u_short reg, u_short data) +{ + u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; + tcic_setb(TCIC_MODE, mode); + tcic_setw(TCIC_AUX, data); +} + +/*====================================================================*/ + +/* Time conversion functions */ + +static int to_cycles(int ns) +{ + if (ns < 14) + return 0; + else + return 2*(ns-14)/cycle_time; +} + +static int to_ns(int cycles) +{ + return (cycles*cycle_time)/2 + 14; +} + +/*====================================================================*/ + +static volatile u_int irq_hits; + +static void irq_count(int irq, void *dev, struct pt_regs *regs) +{ + irq_hits++; +} + +static u_int try_irq(int irq) +{ + u_short cfg; + + irq_hits = 0; + if (request_irq(irq, irq_count, 0, "irq scan", NULL) != 0) + return -1; + mdelay(10); + if (irq_hits) { + free_irq(irq, NULL); + return -1; + } + + /* Generate one interrupt */ + cfg = TCIC_SYSCFG_AUTOBUSY | 0x0a00; + tcic_aux_setw(TCIC_AUX_SYSCFG, cfg | TCIC_IRQ(irq)); + tcic_setb(TCIC_IENA, TCIC_IENA_ERR | TCIC_IENA_CFG_HIGH); + tcic_setb(TCIC_ICSR, TCIC_ICSR_ERR | TCIC_ICSR_JAM); + + udelay(1000); + free_irq(irq, NULL); + + /* Turn off interrupts */ + tcic_setb(TCIC_IENA, TCIC_IENA_CFG_OFF); + while (tcic_getb(TCIC_ICSR)) + tcic_setb(TCIC_ICSR, TCIC_ICSR_JAM); + tcic_aux_setw(TCIC_AUX_SYSCFG, cfg); + + return (irq_hits != 1); +} + +static u_int irq_scan(u_int mask0) +{ + u_int mask1; + int i; + +#ifdef __alpha__ +#define PIC 0x4d0 + /* Don't probe level-triggered interrupts -- reserved for PCI */ + int level_mask = inb_p(PIC) | (inb_p(PIC+1) << 8); + if (level_mask) + mask0 &= ~level_mask; +#endif + + mask1 = 0; + if (do_scan) { + for (i = 0; i < 16; i++) + if ((mask0 & (1 << i)) && (try_irq(i) == 0)) + mask1 |= (1 << i); + for (i = 0; i < 16; i++) + if ((mask1 & (1 << i)) && (try_irq(i) != 0)) { + mask1 ^= (1 << i); + } + } + + if (mask1) { + printk("scanned"); + } else { + /* Fallback: just find interrupts that aren't in use */ + for (i = 0; i < 16; i++) + if ((mask0 & (1 << i)) && + (request_irq(i, irq_count, 0, "x", NULL) == 0)) { + mask1 |= (1 << i); + free_irq(i, NULL); + } + printk("default"); + } + + printk(") = "); + for (i = 0; i < 16; i++) + if (mask1 & (1<> TCIC_ILOCKTEST_ID_SH; + tcic_aux_setw(TCIC_AUX_TEST, 0); + return id; +} + +/*====================================================================*/ + +int tcic_init(void) +{ + int i, sock; + u_int mask, scan; + + DEBUG(0, "%s\n", version); + + printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: "); + sock = 0; + + if (check_region(tcic_base, 16) == 0) { + tcic_setw(TCIC_ADDR, 0); + if (tcic_getw(TCIC_ADDR) == 0) { + tcic_setw(TCIC_ADDR, 0xc3a5); + if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2; + } + if (sock == 0) { + /* See if resetting the controller does any good */ + tcic_setb(TCIC_SCTRL, TCIC_SCTRL_RESET); + tcic_setb(TCIC_SCTRL, 0); + tcic_setw(TCIC_ADDR, 0); + if (tcic_getw(TCIC_ADDR) == 0) { + tcic_setw(TCIC_ADDR, 0xc3a5); + if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2; + } + } + } else + printk("could not allocate ports, "); + + if (sock == 0) { + printk("not found.\n"); + return -ENODEV; + } + + request_region(tcic_base, 16, "tcic-2"); + + sockets = 0; + for (i = 0; i < sock; i++) { + if ((i == ignore) || is_active(i)) continue; + socket_table[sockets].psock = i; + socket_table[sockets].handler = NULL; + socket_table[sockets].info = NULL; + socket_table[sockets].id = get_tcic_id(); + sockets++; + } + + switch (socket_table[0].id) { + case TCIC_ID_DB86082: + printk("DB86082"); break; + case TCIC_ID_DB86082A: + printk("DB86082A"); break; + case TCIC_ID_DB86084: + printk("DB86084"); break; + case TCIC_ID_DB86084A: + printk("DB86084A"); break; + case TCIC_ID_DB86072: + printk("DB86072"); break; + case TCIC_ID_DB86184: + printk("DB86184"); break; + case TCIC_ID_DB86082B: + printk("DB86082B"); break; + default: + printk("Unknown ID 0x%02x", socket_table[0].id); + } + + /* Set up polling */ + poll_timer.function = &tcic_timer; + poll_timer.data = 0; + poll_timer.prev = poll_timer.next = NULL; + + /* Build interrupt mask */ + printk(", %d sockets\n" KERN_INFO " irq list (", sockets); + if (irq_list[0] == -1) + mask = irq_mask; + else + for (i = mask = 0; i < 16; i++) + mask |= (1< 0; i--) + if ((cs_mask & (1 << i)) && + (request_irq(i, tcic_interrupt, 0, "tcic", NULL) == 0)) + break; + cs_irq = i; + if (cs_irq == 0) poll_interval = HZ; + } + + if (tcic_cap.irq_mask & (1 << 11)) + printk("sktirq is irq 11, "); + if (cs_irq != 0) + printk("status change on irq %d\n", cs_irq); + else + printk("polled status, interval = %d ms\n", + poll_interval * 1000 / HZ); + + for (i = 0; i < sockets; i++) { + tcic_setw(TCIC_ADDR+2, socket_table[i].psock << TCIC_SS_SHFT); + socket_table[i].last_sstat = tcic_getb(TCIC_SSTAT); + } + + /* jump start interrupt handler, if needed */ + tcic_interrupt(0, NULL, NULL); + + if (register_ss_entry(sockets, &tcic_service) != 0) { + printk(KERN_NOTICE "tcic: register_ss_entry() failed\n"); + release_region(tcic_base, 16); + if (cs_irq != 0) + free_irq(cs_irq, NULL); + return -ENODEV; + } + + return 0; + +} /* tcic_init */ + +/*====================================================================*/ + +static void tcic_finish(void) +{ + u_long flags; + unregister_ss_entry(&tcic_service); + save_flags(flags); + cli(); + if (cs_irq != 0) { + tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00); + free_irq(cs_irq, NULL); + } + if (tcic_timer_pending) + del_timer(&poll_timer); + restore_flags(flags); + release_region(tcic_base, 16); +} /* tcic_finish */ + +/*====================================================================*/ + +static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + int i, quick = 0; + u_char latch, sstat; + u_short psock; + u_int events; + static volatile int active = 0; + + if (active) { + printk(KERN_NOTICE "tcic: reentered interrupt handler!\n"); + return; + } else + active = 1; + + DEBUG(2, "tcic: tcic_interrupt()\n"); + + for (i = 0; i < sockets; i++) { + psock = socket_table[i].psock; + tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT) + | TCIC_ADDR_INDREG | TCIC_SCF1(psock)); + sstat = tcic_getb(TCIC_SSTAT); + latch = sstat ^ socket_table[psock].last_sstat; + socket_table[i].last_sstat = sstat; + if (tcic_getb(TCIC_ICSR) & TCIC_ICSR_CDCHG) { + tcic_setb(TCIC_ICSR, TCIC_ICSR_CLEAR); + quick = 1; + } + if ((latch == 0) || (socket_table[psock].handler == NULL)) + continue; + events = (latch & TCIC_SSTAT_CD) ? SS_DETECT : 0; + events |= (latch & TCIC_SSTAT_WP) ? SS_WRPROT : 0; + if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) { + events |= (latch & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0; + } else { + events |= (latch & TCIC_SSTAT_RDY) ? SS_READY : 0; + events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0; + events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0; + } + if (events) + socket_table[i].handler(socket_table[i].info, events); + } + + /* Schedule next poll, if needed */ + if (((cs_irq == 0) || quick) && (!tcic_timer_pending)) { + poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval); + add_timer(&poll_timer); + tcic_timer_pending = 1; + } + active = 0; + + DEBUG(2, "tcic: interrupt done\n"); + +} /* tcic_interrupt */ + +static void tcic_timer(u_long data) +{ + DEBUG(2, "tcic: tcic_timer()\n"); + tcic_timer_pending = 0; + tcic_interrupt(0, NULL, NULL); +} /* tcic_timer */ + +/*====================================================================*/ + +static int tcic_register_callback(u_short lsock, ss_callback_t *call) +{ + if (call == NULL) { + socket_table[lsock].handler = NULL; + MOD_DEC_USE_COUNT; + } else { + MOD_INC_USE_COUNT; + socket_table[lsock].handler = call->handler; + socket_table[lsock].info = call->info; + } + return 0; +} /* tcic_register_callback */ + +/*====================================================================*/ + +static int tcic_get_status(u_short lsock, u_int *value) +{ + u_short psock = socket_table[lsock].psock; + u_char reg; + + tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT) + | TCIC_ADDR_INDREG | TCIC_SCF1(psock)); + reg = tcic_getb(TCIC_SSTAT); + *value = (reg & TCIC_SSTAT_CD) ? SS_DETECT : 0; + *value |= (reg & TCIC_SSTAT_WP) ? SS_WRPROT : 0; + if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) { + *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0; + } else { + *value |= (reg & TCIC_SSTAT_RDY) ? SS_READY : 0; + *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0; + *value |= (reg & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0; + } + reg = tcic_getb(TCIC_PWR); + if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock))) + *value |= SS_POWERON; + DEBUG(1, "tcic: GetStatus(%d) = %#2.2x\n", lsock, *value); + return 0; +} /* tcic_get_status */ + +/*====================================================================*/ + +static int tcic_inquire_socket(u_short lsock, socket_cap_t *cap) +{ + *cap = tcic_cap; + return 0; +} /* tcic_inquire_socket */ + +/*====================================================================*/ + +static int tcic_get_socket(u_short lsock, socket_state_t *state) +{ + u_short psock = socket_table[lsock].psock; + u_char reg; + u_short scf1, scf2; + + tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT) + | TCIC_ADDR_INDREG | TCIC_SCF1(psock)); + scf1 = tcic_getw(TCIC_DATA); + state->flags = (scf1 & TCIC_SCF1_IOSTS) ? SS_IOCARD : 0; + state->flags |= (scf1 & TCIC_SCF1_DMA_MASK) ? SS_DMA_MODE : 0; + state->flags |= (scf1 & TCIC_SCF1_SPKR) ? SS_SPKR_ENA : 0; + if (tcic_getb(TCIC_SCTRL) & TCIC_SCTRL_ENA) + state->flags |= SS_OUTPUT_ENA; + state->io_irq = scf1 & TCIC_SCF1_IRQ_MASK; + if (state->io_irq == 1) state->io_irq = 11; + + reg = tcic_getb(TCIC_PWR); + state->Vcc = state->Vpp = 0; + if (reg & TCIC_PWR_VCC(psock)) { + if (reg & TCIC_PWR_VPP(psock)) + state->Vcc = 50; + else + state->Vcc = state->Vpp = 50; + } else { + if (reg & TCIC_PWR_VPP(psock)) { + state->Vcc = 50; + state->Vpp = 120; + } + } + reg = tcic_aux_getb(TCIC_AUX_ILOCK); + state->flags |= (reg & TCIC_ILOCK_CRESET) ? SS_RESET : 0; + + /* Card status change interrupt mask */ + tcic_setw(TCIC_ADDR, TCIC_SCF2(psock)); + scf2 = tcic_getw(TCIC_DATA); + state->csc_mask = (scf2 & TCIC_SCF2_MCD) ? 0 : SS_DETECT; + if (state->flags & SS_IOCARD) { + state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_STSCHG; + } else { + state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_BATDEAD; + state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT2) ? 0 : SS_BATWARN; + state->csc_mask |= (scf2 & TCIC_SCF2_MRDY) ? 0 : SS_READY; + } + + DEBUG(1, "tcic: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x\n", lsock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + return 0; +} /* tcic_get_socket */ + +/*====================================================================*/ + +static int tcic_set_socket(u_short lsock, socket_state_t *state) +{ + u_short psock = socket_table[lsock].psock; + u_char reg; + u_short scf1, scf2; + + DEBUG(1, "tcic: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags, + state->Vcc, state->Vpp, state->io_irq, state->csc_mask); + tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG); + + reg = tcic_getb(TCIC_PWR); + reg &= ~(TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock)); + + if (state->Vcc == 50) { + switch (state->Vpp) { + case 0: reg |= TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock); break; + case 50: reg |= TCIC_PWR_VCC(psock); break; + case 120: reg |= TCIC_PWR_VPP(psock); break; + default: return -EINVAL; + } + } else if (state->Vcc != 0) + return -EINVAL; + + if (reg != tcic_getb(TCIC_PWR)) + tcic_setb(TCIC_PWR, reg); + + reg = TCIC_ILOCK_HOLD_CCLK | TCIC_ILOCK_CWAIT; + if (state->flags & SS_OUTPUT_ENA) { + tcic_setb(TCIC_SCTRL, TCIC_SCTRL_ENA); + reg |= TCIC_ILOCK_CRESENA; + } else + tcic_setb(TCIC_SCTRL, 0); + if (state->flags & SS_RESET) + reg |= TCIC_ILOCK_CRESET; + tcic_aux_setb(TCIC_AUX_ILOCK, reg); + + tcic_setw(TCIC_ADDR, TCIC_SCF1(psock)); + scf1 = TCIC_SCF1_FINPACK; + scf1 |= TCIC_IRQ(state->io_irq); + if (state->flags & SS_IOCARD) { + scf1 |= TCIC_SCF1_IOSTS; + if (state->flags & SS_SPKR_ENA) + scf1 |= TCIC_SCF1_SPKR; + if (state->flags & SS_DMA_MODE) + scf1 |= TCIC_SCF1_DREQ2 << TCIC_SCF1_DMA_SHIFT; + } + tcic_setw(TCIC_DATA, scf1); + + /* Some general setup stuff, and configure status interrupt */ + reg = TCIC_WAIT_ASYNC | TCIC_WAIT_SENSE | to_cycles(250); + tcic_aux_setb(TCIC_AUX_WCTL, reg); + tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00| + TCIC_IRQ(cs_irq)); + + /* Card status change interrupt mask */ + tcic_setw(TCIC_ADDR, TCIC_SCF2(psock)); + scf2 = TCIC_SCF2_MALL; + if (state->csc_mask & SS_DETECT) scf2 &= ~TCIC_SCF2_MCD; + if (state->flags & SS_IOCARD) { + if (state->csc_mask & SS_STSCHG) reg &= ~TCIC_SCF2_MLBAT1; + } else { + if (state->csc_mask & SS_BATDEAD) reg &= ~TCIC_SCF2_MLBAT1; + if (state->csc_mask & SS_BATWARN) reg &= ~TCIC_SCF2_MLBAT2; + if (state->csc_mask & SS_READY) reg &= ~TCIC_SCF2_MRDY; + } + tcic_setw(TCIC_DATA, scf2); + /* For the ISA bus, the irq should be active-high totem-pole */ + tcic_setb(TCIC_IENA, TCIC_IENA_CDCHG | TCIC_IENA_CFG_HIGH); + + return 0; +} /* tcic_set_socket */ + +/*====================================================================*/ + +static int tcic_get_io_map(u_short lsock, struct pccard_io_map *io) +{ + u_short psock = socket_table[lsock].psock; + u_short base, ioctl; + u_int addr; + + if (io->map > 1) return -EINVAL; + tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); + addr = TCIC_IWIN(psock, io->map); + tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X); + base = tcic_getw(TCIC_DATA); + tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X); + ioctl = tcic_getw(TCIC_DATA); + + if (ioctl & TCIC_ICTL_TINY) + io->start = io->stop = base; + else { + io->start = base & (base-1); + io->stop = io->start + (base ^ (base-1)); + } + io->speed = to_ns(ioctl & TCIC_ICTL_WSCNT_MASK); + io->flags = (ioctl & TCIC_ICTL_ENA) ? MAP_ACTIVE : 0; + switch (ioctl & TCIC_ICTL_BW_MASK) { + case TCIC_ICTL_BW_DYN: + io->flags |= MAP_AUTOSZ; break; + case TCIC_ICTL_BW_16: + io->flags |= MAP_16BIT; break; + default: + break; + } + DEBUG(1, "tcic: GetIOMap(%d, %d) = %#2.2x, %d ns, " + "%#4.4x-%#4.4x\n", lsock, io->map, io->flags, + io->speed, io->start, io->stop); + return 0; +} /* tcic_get_io_map */ + +/*====================================================================*/ + +static int tcic_set_io_map(u_short lsock, struct pccard_io_map *io) +{ + u_short psock = socket_table[lsock].psock; + u_int addr; + u_short base, len, ioctl; + + DEBUG(1, "tcic: SetIOMap(%d, %d, %#2.2x, %d ns, " + "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags, + io->speed, io->start, io->stop); + if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) || + (io->stop < io->start)) return -EINVAL; + tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); + addr = TCIC_IWIN(psock, io->map); + + base = io->start; len = io->stop - io->start; + /* Check to see that len+1 is power of two, etc */ + if ((len & (len+1)) || (base & len)) return -EINVAL; + base |= (len+1)>>1; + tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X); + tcic_setw(TCIC_DATA, base); + + ioctl = (psock << TCIC_ICTL_SS_SHFT); + ioctl |= (len == 0) ? TCIC_ICTL_TINY : 0; + ioctl |= (io->flags & MAP_ACTIVE) ? TCIC_ICTL_ENA : 0; + ioctl |= to_cycles(io->speed) & TCIC_ICTL_WSCNT_MASK; + if (!(io->flags & MAP_AUTOSZ)) { + ioctl |= TCIC_ICTL_QUIET; + ioctl |= (io->flags & MAP_16BIT) ? TCIC_ICTL_BW_16 : TCIC_ICTL_BW_8; + } + tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X); + tcic_setw(TCIC_DATA, ioctl); + + return 0; +} /* tcic_set_io_map */ + +/*====================================================================*/ + +static int tcic_get_mem_map(u_short lsock, struct pccard_mem_map *mem) +{ + u_short psock = socket_table[lsock].psock; + u_short addr, ctl; + u_long base, mmap; + + if (mem->map > 3) return -EINVAL; + tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); + addr = TCIC_MWIN(psock, mem->map); + + tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X); + base = tcic_getw(TCIC_DATA); + if (base & TCIC_MBASE_4K_BIT) { + mem->sys_start = base & TCIC_MBASE_HA_MASK; + mem->sys_stop = mem->sys_start; + } else { + base &= TCIC_MBASE_HA_MASK; + mem->sys_start = (base & (base-1)); + mem->sys_stop = mem->sys_start + (base ^ (base-1)); + } + mem->sys_start = mem->sys_start << TCIC_MBASE_HA_SHFT; + mem->sys_stop = (mem->sys_stop << TCIC_MBASE_HA_SHFT) + 0x0fff; + + tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X); + mmap = tcic_getw(TCIC_DATA); + mem->flags = (mmap & TCIC_MMAP_REG) ? MAP_ATTRIB : 0; + mmap &= TCIC_MMAP_CA_MASK; + mem->card_start = mem->sys_start + (mmap << TCIC_MMAP_CA_SHFT); + mem->card_start &= 0x3ffffff; + + tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X); + ctl = tcic_getw(TCIC_DATA); + mem->flags |= (ctl & TCIC_MCTL_ENA) ? MAP_ACTIVE : 0; + mem->flags |= (ctl & TCIC_MCTL_B8) ? 0 : MAP_16BIT; + mem->flags |= (ctl & TCIC_MCTL_WP) ? MAP_WRPROT : 0; + mem->speed = to_ns(ctl & TCIC_MCTL_WSCNT_MASK); + + DEBUG(1, "tcic: GetMemMap(%d, %d) = %#2.2x, %d ns, " + "%#5.5lx-%#5.5lx, %#5.5x\n", lsock, mem->map, mem->flags, + mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); + return 0; +} /* tcic_get_mem_map */ + +/*====================================================================*/ + +static int tcic_set_mem_map(u_short lsock, struct pccard_mem_map *mem) +{ + u_short psock = socket_table[lsock].psock; + u_short addr, ctl; + u_long base, len, mmap; + + DEBUG(1, "tcic: SetMemMap(%d, %d, %#2.2x, %d ns, " + "%#5.5lx-%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, + mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); + if ((mem->map > 3) || (mem->card_start > 0x3ffffff) || + (mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff) || + (mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) + return -EINVAL; + tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); + addr = TCIC_MWIN(psock, mem->map); + + base = mem->sys_start; len = mem->sys_stop - mem->sys_start; + if ((len & (len+1)) || (base & len)) return -EINVAL; + if (len == 0x0fff) + base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT; + else + base = (base | (len+1)>>1) >> TCIC_MBASE_HA_SHFT; + tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X); + tcic_setw(TCIC_DATA, base); + + mmap = mem->card_start - mem->sys_start; + mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK; + if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG; + tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X); + tcic_setw(TCIC_DATA, mmap); + + ctl = TCIC_MCTL_QUIET | (psock << TCIC_MCTL_SS_SHFT); + ctl |= to_cycles(mem->speed) & TCIC_MCTL_WSCNT_MASK; + ctl |= (mem->flags & MAP_16BIT) ? 0 : TCIC_MCTL_B8; + ctl |= (mem->flags & MAP_WRPROT) ? TCIC_MCTL_WP : 0; + ctl |= (mem->flags & MAP_ACTIVE) ? TCIC_MCTL_ENA : 0; + tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X); + tcic_setw(TCIC_DATA, ctl); + + return 0; +} /* tcic_set_mem_map */ + +/*====================================================================*/ + +typedef int (*subfn_t)(u_short, void *); + +static subfn_t service_table[] = { + (subfn_t)&tcic_register_callback, + (subfn_t)&tcic_inquire_socket, + (subfn_t)&tcic_get_status, + (subfn_t)&tcic_get_socket, + (subfn_t)&tcic_set_socket, + (subfn_t)&tcic_get_io_map, + (subfn_t)&tcic_set_io_map, + (subfn_t)&tcic_get_mem_map, + (subfn_t)&tcic_set_mem_map, +}; + +#define NFUNC (sizeof(service_table)/sizeof(subfn_t)) + +static int tcic_service(u_int lsock, u_int cmd, void *arg) +{ + int err; + + DEBUG(2, "tcic_service(%d, %d, 0x%p)\n", lsock, cmd, arg); + + if (cmd < NFUNC) + err = service_table[cmd](lsock, arg); + else + err = -EINVAL; + + return err; +} /* tcic_service */ + +/*====================================================================*/ + +int pcmcia_tcic_init(void) +{ + servinfo_t serv; + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "tcic: Card Services release " + "does not match!\n"); + return -1; + } + return tcic_init(); +} + +#ifdef MODULE +int init_module(void) +{ + return pcmcia_tcic_init(); +} + +void cleanup_module(void) +{ + tcic_finish(); +} +#endif diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/tcic.h linux/drivers/pcmcia/tcic.h --- v2.3.16/linux/drivers/pcmcia/tcic.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/tcic.h Fri Sep 3 12:27:58 1999 @@ -0,0 +1,266 @@ +/* + * tcic.h 1.12 1999/08/28 04:01:47 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_TCIC_H +#define _LINUX_TCIC_H + +#define TCIC_BASE 0x240 + +/* offsets of registers from TCIC_BASE */ +#define TCIC_DATA 0x00 +#define TCIC_ADDR 0x02 +#define TCIC_SCTRL 0x06 +#define TCIC_SSTAT 0x07 +#define TCIC_MODE 0x08 +#define TCIC_PWR 0x09 +#define TCIC_EDC 0x0A +#define TCIC_ICSR 0x0C +#define TCIC_IENA 0x0D +#define TCIC_AUX 0x0E + +#define TCIC_SS_SHFT 12 +#define TCIC_SS_MASK 0x7000 + +/* Flags for TCIC_ADDR */ +#define TCIC_ADR2_REG 0x8000 +#define TCIC_ADR2_INDREG 0x0800 + +#define TCIC_ADDR_REG 0x80000000 +#define TCIC_ADDR_SS_SHFT (TCIC_SS_SHFT+16) +#define TCIC_ADDR_SS_MASK (TCIC_SS_MASK<<16) +#define TCIC_ADDR_INDREG 0x08000000 +#define TCIC_ADDR_IO 0x04000000 +#define TCIC_ADDR_MASK 0x03ffffff + +/* Flags for TCIC_SCTRL */ +#define TCIC_SCTRL_ENA 0x01 +#define TCIC_SCTRL_INCMODE 0x18 +#define TCIC_SCTRL_INCMODE_HOLD 0x00 +#define TCIC_SCTRL_INCMODE_WORD 0x08 +#define TCIC_SCTRL_INCMODE_REG 0x10 +#define TCIC_SCTRL_INCMODE_AUTO 0x18 +#define TCIC_SCTRL_EDCSUM 0x20 +#define TCIC_SCTRL_RESET 0x80 + +/* Flags for TCIC_SSTAT */ +#define TCIC_SSTAT_6US 0x01 +#define TCIC_SSTAT_10US 0x02 +#define TCIC_SSTAT_PROGTIME 0x04 +#define TCIC_SSTAT_LBAT1 0x08 +#define TCIC_SSTAT_LBAT2 0x10 +#define TCIC_SSTAT_RDY 0x20 /* Inverted */ +#define TCIC_SSTAT_WP 0x40 +#define TCIC_SSTAT_CD 0x80 /* Card detect */ + +/* Flags for TCIC_MODE */ +#define TCIC_MODE_PGMMASK 0x1f +#define TCIC_MODE_NORMAL 0x00 +#define TCIC_MODE_PGMWR 0x01 +#define TCIC_MODE_PGMRD 0x02 +#define TCIC_MODE_PGMCE 0x04 +#define TCIC_MODE_PGMDBW 0x08 +#define TCIC_MODE_PGMWORD 0x10 +#define TCIC_MODE_AUXSEL_MASK 0xe0 + +/* Registers accessed through TCIC_AUX, by setting TCIC_MODE */ +#define TCIC_AUX_TCTL (0<<5) +#define TCIC_AUX_PCTL (1<<5) +#define TCIC_AUX_WCTL (2<<5) +#define TCIC_AUX_EXTERN (3<<5) +#define TCIC_AUX_PDATA (4<<5) +#define TCIC_AUX_SYSCFG (5<<5) +#define TCIC_AUX_ILOCK (6<<5) +#define TCIC_AUX_TEST (7<<5) + +/* Flags for TCIC_PWR */ +#define TCIC_PWR_VCC(sock) (0x01<<(sock)) +#define TCIC_PWR_VCC_MASK 0x03 +#define TCIC_PWR_VPP(sock) (0x08<<(sock)) +#define TCIC_PWR_VPP_MASK 0x18 +#define TCIC_PWR_CLIMENA 0x40 +#define TCIC_PWR_CLIMSTAT 0x80 + +/* Flags for TCIC_ICSR */ +#define TCIC_ICSR_CLEAR 0x01 +#define TCIC_ICSR_SET 0x02 +#define TCIC_ICSR_JAM (TCIC_ICSR_CLEAR|TCIC_ICSR_SET) +#define TCIC_ICSR_STOPCPU 0x04 +#define TCIC_ICSR_ILOCK 0x08 +#define TCIC_ICSR_PROGTIME 0x10 +#define TCIC_ICSR_ERR 0x20 +#define TCIC_ICSR_CDCHG 0x40 +#define TCIC_ICSR_IOCHK 0x80 + +/* Flags for TCIC_IENA */ +#define TCIC_IENA_CFG_MASK 0x03 +#define TCIC_IENA_CFG_OFF 0x00 /* disabled */ +#define TCIC_IENA_CFG_OD 0x01 /* active low, open drain */ +#define TCIC_IENA_CFG_LOW 0x02 /* active low, totem pole */ +#define TCIC_IENA_CFG_HIGH 0x03 /* active high, totem pole */ +#define TCIC_IENA_ILOCK 0x08 +#define TCIC_IENA_PROGTIME 0x10 +#define TCIC_IENA_ERR 0x20 /* overcurrent or iochk */ +#define TCIC_IENA_CDCHG 0x40 + +/* Flags for TCIC_AUX_WCTL */ +#define TCIC_WAIT_COUNT_MASK 0x001f +#define TCIC_WAIT_ASYNC 0x0020 +#define TCIC_WAIT_SENSE 0x0040 +#define TCIC_WAIT_SRC 0x0080 +#define TCIC_WCTL_WR 0x0100 +#define TCIC_WCTL_RD 0x0200 +#define TCIC_WCTL_CE 0x0400 +#define TCIC_WCTL_LLBAT1 0x0800 +#define TCIC_WCTL_LLBAT2 0x1000 +#define TCIC_WCTL_LRDY 0x2000 +#define TCIC_WCTL_LWP 0x4000 +#define TCIC_WCTL_LCD 0x8000 + +/* Flags for TCIC_AUX_SYSCFG */ +#define TCIC_SYSCFG_IRQ_MASK 0x000f +#define TCIC_SYSCFG_MCSFULL 0x0010 +#define TCIC_SYSCFG_IO1723 0x0020 +#define TCIC_SYSCFG_MCSXB 0x0040 +#define TCIC_SYSCFG_ICSXB 0x0080 +#define TCIC_SYSCFG_NOPDN 0x0100 +#define TCIC_SYSCFG_MPSEL_SHFT 9 +#define TCIC_SYSCFG_MPSEL_MASK 0x0e00 +#define TCIC_SYSCFG_MPSENSE 0x2000 +#define TCIC_SYSCFG_AUTOBUSY 0x4000 +#define TCIC_SYSCFG_ACC 0x8000 + +#define TCIC_ILOCK_OUT 0x01 +#define TCIC_ILOCK_SENSE 0x02 +#define TCIC_ILOCK_CRESET 0x04 +#define TCIC_ILOCK_CRESENA 0x08 +#define TCIC_ILOCK_CWAIT 0x10 +#define TCIC_ILOCK_CWAITSNS 0x20 +#define TCIC_ILOCK_HOLD_MASK 0xc0 +#define TCIC_ILOCK_HOLD_CCLK 0xc0 + +#define TCIC_ILOCKTEST_ID_SH 8 +#define TCIC_ILOCKTEST_ID_MASK 0x7f00 +#define TCIC_ILOCKTEST_MCIC_1 0x8000 + +#define TCIC_ID_DB86082 0x02 +#define TCIC_ID_DB86082A 0x03 +#define TCIC_ID_DB86084 0x04 +#define TCIC_ID_DB86084A 0x08 +#define TCIC_ID_DB86072 0x15 +#define TCIC_ID_DB86184 0x14 +#define TCIC_ID_DB86082B 0x17 + +#define TCIC_TEST_DIAG 0x8000 + +/* + * Indirectly addressed registers + */ + +#define TCIC_SCF1(sock) ((sock)<<3) +#define TCIC_SCF2(sock) (((sock)<<3)+2) + +/* Flags for SCF1 */ +#define TCIC_SCF1_IRQ_MASK 0x000f +#define TCIC_SCF1_IRQ_OFF 0x0000 +#define TCIC_SCF1_IRQOC 0x0010 +#define TCIC_SCF1_PCVT 0x0020 +#define TCIC_SCF1_IRDY 0x0040 +#define TCIC_SCF1_ATA 0x0080 +#define TCIC_SCF1_DMA_SHIFT 8 +#define TCIC_SCF1_DMA_MASK 0x0700 +#define TCIC_SCF1_DMA_OFF 0 +#define TCIC_SCF1_DREQ2 2 +#define TCIC_SCF1_IOSTS 0x0800 +#define TCIC_SCF1_SPKR 0x1000 +#define TCIC_SCF1_FINPACK 0x2000 +#define TCIC_SCF1_DELWR 0x4000 +#define TCIC_SCF1_HD7IDE 0x8000 + +/* Flags for SCF2 */ +#define TCIC_SCF2_RI 0x0001 +#define TCIC_SCF2_IDBR 0x0002 +#define TCIC_SCF2_MDBR 0x0004 +#define TCIC_SCF2_MLBAT1 0x0008 +#define TCIC_SCF2_MLBAT2 0x0010 +#define TCIC_SCF2_MRDY 0x0020 +#define TCIC_SCF2_MWP 0x0040 +#define TCIC_SCF2_MCD 0x0080 +#define TCIC_SCF2_MALL 0x00f8 + +/* Indirect addresses for memory window registers */ +#define TCIC_MWIN(sock,map) (0x100+(((map)+((sock)<<2))<<3)) +#define TCIC_MBASE_X 2 +#define TCIC_MMAP_X 4 +#define TCIC_MCTL_X 6 + +#define TCIC_MBASE_4K_BIT 0x4000 +#define TCIC_MBASE_HA_SHFT 12 +#define TCIC_MBASE_HA_MASK 0x0fff + +#define TCIC_MMAP_REG 0x8000 +#define TCIC_MMAP_CA_SHFT 12 +#define TCIC_MMAP_CA_MASK 0x3fff + +#define TCIC_MCTL_WSCNT_MASK 0x001f +#define TCIC_MCTL_WCLK 0x0020 +#define TCIC_MCTL_WCLK_CCLK 0x0000 +#define TCIC_MCTL_WCLK_BCLK 0x0020 +#define TCIC_MCTL_QUIET 0x0040 +#define TCIC_MCTL_WP 0x0080 +#define TCIC_MCTL_ACC 0x0100 +#define TCIC_MCTL_KE 0x0200 +#define TCIC_MCTL_EDC 0x0400 +#define TCIC_MCTL_B8 0x0800 +#define TCIC_MCTL_SS_SHFT TCIC_SS_SHFT +#define TCIC_MCTL_SS_MASK TCIC_SS_MASK +#define TCIC_MCTL_ENA 0x8000 + +/* Indirect addresses for I/O window registers */ +#define TCIC_IWIN(sock,map) (0x200+(((map)+((sock)<<1))<<2)) +#define TCIC_IBASE_X 0 +#define TCIC_ICTL_X 2 + +#define TCIC_ICTL_WSCNT_MASK TCIC_MCTL_WSCNT_MASK +#define TCIC_ICTL_QUIET TCIC_MCTL_QUIET +#define TCIC_ICTL_1K 0x0080 +#define TCIC_ICTL_PASS16 0x0100 +#define TCIC_ICTL_ACC TCIC_MCTL_ACC +#define TCIC_ICTL_TINY 0x0200 +#define TCIC_ICTL_B16 0x0400 +#define TCIC_ICTL_B8 TCIC_MCTL_B8 +#define TCIC_ICTL_BW_MASK (TCIC_ICTL_B16|TCIC_ICTL_B8) +#define TCIC_ICTL_BW_DYN 0 +#define TCIC_ICTL_BW_8 TCIC_ICTL_B8 +#define TCIC_ICTL_BW_16 TCIC_ICTL_B16 +#define TCIC_ICTL_BW_ATA (TCIC_ICTL_B16|TCIC_ICTL_B8) +#define TCIC_ICTL_SS_SHFT TCIC_SS_SHFT +#define TCIC_ICTL_SS_MASK TCIC_SS_MASK +#define TCIC_ICTL_ENA TCIC_MCTL_ENA + +#endif /* _LINUX_TCIC_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/ti113x.h linux/drivers/pcmcia/ti113x.h --- v2.3.16/linux/drivers/pcmcia/ti113x.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/ti113x.h Tue Sep 7 11:03:10 1999 @@ -0,0 +1,180 @@ +/* + * ti113x.h 1.15 1999/09/03 16:43:35 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_TI113X_H +#define _LINUX_TI113X_H + +#ifndef PCI_VENDOR_ID_TI +#define PCI_VENDOR_ID_TI 0x104c +#endif + +#ifndef PCI_DEVICE_ID_TI_1130 +#define PCI_DEVICE_ID_TI_1130 0xac12 +#endif +#ifndef PCI_DEVICE_ID_TI_1131 +#define PCI_DEVICE_ID_TI_1131 0xac15 +#endif +#ifndef PCI_DEVICE_ID_TI_1031 +#define PCI_DEVICE_ID_TI_1031 0xac13 +#endif +#ifndef PCI_DEVICE_ID_TI_1250A +#define PCI_DEVICE_ID_TI_1250A 0xac16 +#endif +#ifndef PCI_DEVICE_ID_TI_1220 +#define PCI_DEVICE_ID_TI_1220 0xac17 +#endif +#ifndef PCI_DEVICE_ID_TI_1221 +#define PCI_DEVICE_ID_TI_1221 0xac19 +#endif +#ifndef PCI_DEVICE_ID_TI_1210 +#define PCI_DEVICE_ID_TI_1210 0xac1a +#endif +#ifndef PCI_DEVICE_ID_TI_1450 +#define PCI_DEVICE_ID_TI_1450 0xac1b +#endif +#ifndef PCI_DEVICE_ID_TI_1225 +#define PCI_DEVICE_ID_TI_1225 0xac1c +#endif +#ifndef PCI_DEVICE_ID_TI_1251A +#define PCI_DEVICE_ID_TI_1251A 0xac1d +#endif +#ifndef PCI_DEVICE_ID_TI_1211 +#define PCI_DEVICE_ID_TI_1211 0xac1e +#endif +#ifndef PCI_DEVICE_ID_TI_1251B +#define PCI_DEVICE_ID_TI_1251B 0xac1f +#endif +#ifndef PCI_DEVICE_ID_TI_1420 +#define PCI_DEVICE_ID_TI_1420 0xac51 +#endif + +/* Register definitions for TI 113X PCI-to-CardBus bridges */ + +/* System Control Register */ +#define TI113X_SYSTEM_CONTROL 0x0080 /* 32 bit */ +#define TI113X_SCR_SMIROUTE 0x04000000 +#define TI113X_SCR_SMISTATUS 0x02000000 +#define TI113X_SCR_SMIENB 0x01000000 +#define TI113X_SCR_VCCPROT 0x00200000 +#define TI113X_SCR_REDUCEZV 0x00100000 +#define TI113X_SCR_CDREQEN 0x00080000 +#define TI113X_SCR_CDMACHAN 0x00070000 +#define TI113X_SCR_SOCACTIVE 0x00002000 +#define TI113X_SCR_PWRSTREAM 0x00000800 +#define TI113X_SCR_DELAYUP 0x00000400 +#define TI113X_SCR_DELAYDOWN 0x00000200 +#define TI113X_SCR_INTERROGATE 0x00000100 +#define TI113X_SCR_CLKRUN_SEL 0x00000080 +#define TI113X_SCR_PWRSAVINGS 0x00000040 +#define TI113X_SCR_SUBSYSRW 0x00000020 +#define TI113X_SCR_CB_DPAR 0x00000010 +#define TI113X_SCR_CDMA_EN 0x00000008 +#define TI113X_SCR_ASYNC_IRQ 0x00000004 +#define TI113X_SCR_KEEPCLK 0x00000002 +#define TI113X_SCR_CLKRUN_ENA 0x00000001 + +#define TI122X_SCR_SER_STEP 0xc0000000 +#define TI122X_SCR_INTRTIE 0x20000000 +#define TI122X_SCR_CBRSVD 0x00400000 +#define TI122X_SCR_MRBURSTDN 0x00008000 +#define TI122X_SCR_MRBURSTUP 0x00004000 +#define TI122X_SCR_RIMUX 0x00000001 + +/* Multimedia Control Register */ +#define TI1250_MULTIMEDIA_CTL 0x0084 /* 8 bit */ +#define TI1250_MMC_ZVOUTEN 0x80 +#define TI1250_MMC_PORTSEL 0x40 +#define TI1250_MMC_ZVEN1 0x02 +#define TI1250_MMC_ZVEN0 0x01 + +#define TI1250_GENERAL_STATUS 0x0085 /* 8 bit */ +#define TI1250_GPIO0_CONTROL 0x0088 /* 8 bit */ +#define TI1250_GPIO1_CONTROL 0x0089 /* 8 bit */ +#define TI1250_GPIO2_CONTROL 0x008a /* 8 bit */ +#define TI1250_GPIO3_CONTROL 0x008b /* 8 bit */ +#define TI122X_IRQMUX 0x008c /* 32 bit */ + +/* Retry Status Register */ +#define TI113X_RETRY_STATUS 0x0090 /* 8 bit */ +#define TI113X_RSR_PCIRETRY 0x80 +#define TI113X_RSR_CBRETRY 0x40 +#define TI113X_RSR_TEXP_CBB 0x20 +#define TI113X_RSR_MEXP_CBB 0x10 +#define TI113X_RSR_TEXP_CBA 0x08 +#define TI113X_RSR_MEXP_CBA 0x04 +#define TI113X_RSR_TEXP_PCI 0x02 +#define TI113X_RSR_MEXP_PCI 0x01 + +/* Card Control Register */ +#define TI113X_CARD_CONTROL 0x0091 /* 8 bit */ +#define TI113X_CCR_RIENB 0x80 +#define TI113X_CCR_ZVENABLE 0x40 +#define TI113X_CCR_PCI_IRQ_ENA 0x20 +#define TI113X_CCR_PCI_IREQ 0x10 +#define TI113X_CCR_PCI_CSC 0x08 +#define TI113X_CCR_SPKROUTEN 0x02 +#define TI113X_CCR_IFG 0x01 + +#define TI1220_CCR_PORT_SEL 0x20 +#define TI122X_CCR_AUD2MUX 0x04 + +/* Device Control Register */ +#define TI113X_DEVICE_CONTROL 0x0092 /* 8 bit */ +#define TI113X_DCR_5V_FORCE 0x40 +#define TI113X_DCR_3V_FORCE 0x20 +#define TI113X_DCR_IMODE_MASK 0x06 +#define TI113X_DCR_IMODE_ISA 0x02 +#define TI113X_DCR_IMODE_SERIAL 0x04 + +#define TI12XX_DCR_IMODE_PCI_ONLY 0x00 +#define TI12XX_DCR_IMODE_ALL_SERIAL 0x06 + +/* Buffer Control Register */ +#define TI113X_BUFFER_CONTROL 0x0093 /* 8 bit */ +#define TI113X_BCR_CB_READ_DEPTH 0x08 +#define TI113X_BCR_CB_WRITE_DEPTH 0x04 +#define TI113X_BCR_PCI_READ_DEPTH 0x02 +#define TI113X_BCR_PCI_WRITE_DEPTH 0x01 + +/* Diagnostic Register */ +#define TI1250_DIAGNOSTIC 0x0093 /* 8 bit */ +#define TI1250_DIAG_TRUE_VALUE 0x80 +#define TI1250_DIAG_PCI_IREQ 0x40 +#define TI1250_DIAG_PCI_CSC 0x20 +#define TI1250_DIAG_ASYNC_CSC 0x01 + +/* DMA Registers */ +#define TI113X_DMA_0 0x0094 /* 32 bit */ +#define TI113X_DMA_1 0x0098 /* 32 bit */ + +/* ExCA IO offset registers */ +#define TI113X_IO_OFFSET(map) (0x36+((map)<<1)) + +#endif /* _LINUX_TI113X_H */ + diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/topic.h linux/drivers/pcmcia/topic.h --- v2.3.16/linux/drivers/pcmcia/topic.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/topic.h Fri Sep 3 12:27:58 1999 @@ -0,0 +1,96 @@ +/* + * topic.h 1.8 1999/08/28 04:01:47 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + * topic.h $Release$ 1999/08/28 04:01:47 + */ + +#ifndef _LINUX_TOPIC_H +#define _LINUX_TOPIC_H + +#ifndef PCI_VENDOR_ID_TOSHIBA +#define PCI_VENDOR_ID_TOSHIBA 0x1179 +#endif +#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC95_A +#define PCI_DEVICE_ID_TOSHIBA_TOPIC95_A 0x0603 +#endif +#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC95_B +#define PCI_DEVICE_ID_TOSHIBA_TOPIC95_B 0x060a +#endif +#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC97 +#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f +#endif + +/* Register definitions for Toshiba ToPIC95 controllers */ + +#define TOPIC_SOCKET_CONTROL 0x0090 /* 32 bit */ +#define TOPIC_SCR_IRQSEL 0x00000001 + +#define TOPIC_SLOT_CONTROL 0x00a0 /* 8 bit */ +#define TOPIC_SLOT_SLOTON 0x80 +#define TOPIC_SLOT_SLOTEN 0x40 +#define TOPIC_SLOT_ID_LOCK 0x20 +#define TOPIC_SLOT_ID_WP 0x10 +#define TOPIC_SLOT_PORT_MASK 0x0c +#define TOPIC_SLOT_PORT_SHIFT 2 +#define TOPIC_SLOT_OFS_MASK 0x03 + +#define TOPIC_CARD_CONTROL 0x00a1 /* 8 bit */ +#define TOPIC_CCR_INTB 0x20 +#define TOPIC_CCR_INTA 0x10 +#define TOPIC_CCR_CLOCK 0x0c +#define TOPIC_CCR_PCICLK 0x0c +#define TOPIC_CCR_PCICLK_2 0x08 +#define TOPIC_CCR_CCLK 0x04 + +#define TOPIC97_INT_CONTROL 0x00a1 /* 8 bit */ +#define TOPIC97_ICR_INTB 0x20 +#define TOPIC97_ICR_INTA 0x10 +#define TOPIC97_ICR_STSIRQNP 0x04 +#define TOPIC97_ICR_IRQNP 0x02 +#define TOPIC97_ICR_IRQSEL 0x01 + +#define TOPIC_CARD_DETECT 0x00a3 /* 8 bit */ +#define TOPIC_CDR_MODE_PC32 0x80 +#define TOPIC_CDR_VS1 0x04 +#define TOPIC_CDR_VS2 0x02 +#define TOPIC_CDR_SW_DETECT 0x01 + +#define TOPIC_REGISTER_CONTROL 0x00a4 /* 32 bit */ +#define TOPIC_RCR_RESUME_RESET 0x80000000 +#define TOPIC_RCR_REMOVE_RESET 0x40000000 +#define TOPIC97_RCR_CLKRUN_ENA 0x20000000 +#define TOPIC97_RCR_TESTMODE 0x10000000 +#define TOPIC97_RCR_IOPLUP 0x08000000 +#define TOPIC_RCR_BUFOFF_PWROFF 0x02000000 +#define TOPIC_RCR_BUFOFF_SIGOFF 0x01000000 +#define TOPIC97_RCR_CB_DEV_MASK 0x0000f800 +#define TOPIC97_RCR_CB_DEV_SHIFT 11 +#define TOPIC97_RCR_RI_DISABLE 0x00000004 +#define TOPIC97_RCR_CAUDIO_OFF 0x00000002 +#define TOPIC_RCR_CAUDIO_INVERT 0x00000001 + +#endif /* _LINUX_TOPIC_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/vg468.h linux/drivers/pcmcia/vg468.h --- v2.3.16/linux/drivers/pcmcia/vg468.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/vg468.h Fri Sep 3 12:27:58 1999 @@ -0,0 +1,106 @@ +/* + * vg468.h 1.10 1999/08/28 04:01:47 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_VG468_H +#define _LINUX_VG468_H + +/* Special bit in I365_IDENT used for Vadem chip detection */ +#define I365_IDENT_VADEM 0x08 + +/* Special definitions in I365_POWER */ +#define VG468_VPP2_MASK 0x0c +#define VG468_VPP2_5V 0x04 +#define VG468_VPP2_12V 0x08 + +/* Unique Vadem registers */ +#define VG469_VSENSE 0x1f /* Card voltage sense */ +#define VG469_VSELECT 0x2f /* Card voltage select */ +#define VG468_CTL 0x38 /* Control register */ +#define VG468_TIMER 0x39 /* Timer control */ +#define VG468_MISC 0x3a /* Miscellaneous */ +#define VG468_GPIO_CFG 0x3b /* GPIO configuration */ +#define VG469_EXT_MODE 0x3c /* Extended mode register */ +#define VG468_SELECT 0x3d /* Programmable chip select */ +#define VG468_SELECT_CFG 0x3e /* Chip select configuration */ +#define VG468_ATA 0x3f /* ATA control */ + +/* Flags for VG469_VSENSE */ +#define VG469_VSENSE_A_VS1 0x01 +#define VG469_VSENSE_A_VS2 0x02 +#define VG469_VSENSE_B_VS1 0x04 +#define VG469_VSENSE_B_VS2 0x08 + +/* Flags for VG469_VSELECT */ +#define VG469_VSEL_VCC 0x03 +#define VG469_VSEL_5V 0x00 +#define VG469_VSEL_3V 0x03 +#define VG469_VSEL_MAX 0x0c +#define VG469_VSEL_EXT_STAT 0x10 +#define VG469_VSEL_EXT_BUS 0x20 +#define VG469_VSEL_MIXED 0x40 +#define VG469_VSEL_ISA 0x80 + +/* Flags for VG468_CTL */ +#define VG468_CTL_SLOW 0x01 /* 600ns memory timing */ +#define VG468_CTL_ASYNC 0x02 /* Asynchronous bus clocking */ +#define VG468_CTL_TSSI 0x08 /* Tri-state some outputs */ +#define VG468_CTL_DELAY 0x10 /* Card detect debounce */ +#define VG468_CTL_INPACK 0x20 /* Obey INPACK signal? */ +#define VG468_CTL_POLARITY 0x40 /* VCCEN polarity */ +#define VG468_CTL_COMPAT 0x80 /* Compatibility stuff */ + +#define VG469_CTL_WS_COMPAT 0x04 /* Wait state compatibility */ +#define VG469_CTL_STRETCH 0x10 /* LED stretch */ + +/* Flags for VG468_TIMER */ +#define VG468_TIMER_ZEROPWR 0x10 /* Zero power control */ +#define VG468_TIMER_SIGEN 0x20 /* Power up */ +#define VG468_TIMER_STATUS 0x40 /* Activity timer status */ +#define VG468_TIMER_RES 0x80 /* Timer resolution */ +#define VG468_TIMER_MASK 0x0f /* Activity timer timeout */ + +/* Flags for VG468_MISC */ +#define VG468_MISC_GPIO 0x04 /* General-purpose IO */ +#define VG468_MISC_DMAWSB 0x08 /* DMA wait state control */ +#define VG469_MISC_LEDENA 0x10 /* LED enable */ +#define VG468_MISC_VADEMREV 0x40 /* Vadem revision control */ +#define VG468_MISC_UNLOCK 0x80 /* Unique register lock */ + +/* Flags for VG469_EXT_MODE_A */ +#define VG469_MODE_VPPST 0x03 /* Vpp steering control */ +#define VG469_MODE_INT_SENSE 0x04 /* Internal voltage sense */ +#define VG469_MODE_CABLE 0x08 +#define VG469_MODE_COMPAT 0x10 /* i82365sl B or DF step */ +#define VG469_MODE_TEST 0x20 +#define VG469_MODE_RIO 0x40 /* Steer RIO to INTR? */ + +/* Flags for VG469_EXT_MODE_B */ +#define VG469_MODE_B_3V 0x01 /* 3.3v for socket B */ + +#endif /* _LINUX_VG468_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/yenta.h linux/drivers/pcmcia/yenta.h --- v2.3.16/linux/drivers/pcmcia/yenta.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/pcmcia/yenta.h Fri Sep 3 12:27:58 1999 @@ -0,0 +1,153 @@ +/* + * yenta.h 1.15 1999/08/28 04:01:47 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_YENTA_H +#define _LINUX_YENTA_H + +/* PCI Configuration Registers */ + +#define PCI_STATUS_CAPLIST 0x10 +#define PCI_CB_CAPABILITY_POINTER 0x14 /* 8 bit */ +#define PCI_CAPABILITY_ID 0x00 /* 8 bit */ +#define PCI_CAPABILITY_PM 0x01 +#define PCI_NEXT_CAPABILITY 0x01 /* 8 bit */ +#define PCI_PM_CAPABILITIES 0x02 /* 16 bit */ +#define PCI_PMCAP_PME_D3COLD 0x8000 +#define PCI_PMCAP_PME_D3HOT 0x4000 +#define PCI_PMCAP_PME_D2 0x2000 +#define PCI_PMCAP_PME_D1 0x1000 +#define PCI_PMCAP_PME_D0 0x0800 +#define PCI_PMCAP_D2_CAP 0x0400 +#define PCI_PMCAP_D1_CAP 0x0200 +#define PCI_PMCAP_DYN_DATA 0x0100 +#define PCI_PMCAP_DSI 0x0020 +#define PCI_PMCAP_AUX_PWR 0x0010 +#define PCI_PMCAP_PMECLK 0x0008 +#define PCI_PMCAP_VERSION_MASK 0x0007 +#define PCI_PM_CONTROL_STATUS 0x04 /* 16 bit */ +#define PCI_PMCS_PME_STATUS 0x8000 +#define PCI_PMCS_DATASCALE_MASK 0x6000 +#define PCI_PMCS_DATASCALE_SHIFT 13 +#define PCI_PMCS_DATASEL_MASK 0x1e00 +#define PCI_PMCS_DATASEL_SHIFT 9 +#define PCI_PMCS_PME_ENABLE 0x0100 +#define PCI_PMCS_PWR_STATE_MASK 0x0003 +#define PCI_PMCS_PWR_STATE_D0 0x0000 +#define PCI_PMCS_PWR_STATE_D1 0x0001 +#define PCI_PMCS_PWR_STATE_D2 0x0002 +#define PCI_PMCS_PWR_STATE_D3 0x0003 +#define PCI_PM_BRIDGE_EXT 0x06 /* 8 bit */ +#define PCI_PM_DATA 0x07 /* 8 bit */ + +#define CB_PRIMARY_BUS 0x18 /* 8 bit */ +#define CB_CARDBUS_BUS 0x19 /* 8 bit */ +#define CB_SUBORD_BUS 0x1a /* 8 bit */ +#define CB_LATENCY_TIMER 0x1b /* 8 bit */ + +#define CB_MEM_BASE(m) (0x1c + 8*(m)) +#define CB_MEM_LIMIT(m) (0x20 + 8*(m)) +#define CB_IO_BASE(m) (0x2c + 8*(m)) +#define CB_IO_LIMIT(m) (0x30 + 8*(m)) + +#define CB_BRIDGE_CONTROL 0x3e /* 16 bit */ +#define CB_BCR_PARITY_ENA 0x0001 +#define CB_BCR_SERR_ENA 0x0002 +#define CB_BCR_ISA_ENA 0x0004 +#define CB_BCR_VGA_ENA 0x0008 +#define CB_BCR_MABORT 0x0020 +#define CB_BCR_CB_RESET 0x0040 +#define CB_BCR_ISA_IRQ 0x0080 +#define CB_BCR_PREFETCH(m) (0x0100 << (m)) +#define CB_BCR_WRITE_POST 0x0400 + +#define CB_LEGACY_MODE_BASE 0x44 + +/* Memory mapped registers */ + +#define CB_SOCKET_EVENT 0x0000 +#define CB_SE_CSTSCHG 0x00000001 +#define CB_SE_CCD1 0x00000002 +#define CB_SE_CCD2 0x00000004 +#define CB_SE_PWRCYCLE 0x00000008 + +#define CB_SOCKET_MASK 0x0004 +#define CB_SM_CSTSCHG 0x00000001 +#define CB_SM_CCD 0x00000006 +#define CB_SM_PWRCYCLE 0x00000008 + +#define CB_SOCKET_STATE 0x0008 +#define CB_SS_CSTSCHG 0x00000001 +#define CB_SS_CCD1 0x00000002 +#define CB_SS_CCD2 0x00000004 +#define CB_SS_PWRCYCLE 0x00000008 +#define CB_SS_16BIT 0x00000010 +#define CB_SS_32BIT 0x00000020 +#define CB_SS_CINT 0x00000040 +#define CB_SS_BADCARD 0x00000080 +#define CB_SS_DATALOST 0x00000100 +#define CB_SS_BADVCC 0x00000200 +#define CB_SS_5VCARD 0x00000400 +#define CB_SS_3VCARD 0x00000800 +#define CB_SS_XVCARD 0x00001000 +#define CB_SS_YVCARD 0x00002000 +#define CB_SS_5VSOCKET 0x10000000 +#define CB_SS_3VSOCKET 0x20000000 +#define CB_SS_XVSOCKET 0x40000000 +#define CB_SS_YVSOCKET 0x80000000 + +#define CB_SOCKET_FORCE 0x000c +#define CB_SF_CVSTEST 0x00004000 + +#define CB_SOCKET_CONTROL 0x0010 +#define CB_SC_VPP_MASK 0x00000007 +#define CB_SC_VPP_OFF 0x00000000 +#define CB_SC_VPP_12V 0x00000001 +#define CB_SC_VPP_5V 0x00000002 +#define CB_SC_VPP_3V 0x00000003 +#define CB_SC_VPP_XV 0x00000004 +#define CB_SC_VPP_YV 0x00000005 +#define CB_SC_VCC_MASK 0x00000070 +#define CB_SC_VCC_OFF 0x00000000 +#define CB_SC_VCC_5V 0x00000020 +#define CB_SC_VCC_3V 0x00000030 +#define CB_SC_VCC_XV 0x00000040 +#define CB_SC_VCC_YV 0x00000050 +#define CB_SC_CCLK_STOP 0x00000080 + +#define CB_SOCKET_POWER 0x0020 +#define CB_SP_CLK_CTRL 0x00000001 +#define CB_SP_CLK_CTRL_ENA 0x00010000 +#define CB_SP_CLK_MODE 0x01000000 +#define CB_SP_ACCESS 0x02000000 + +/* Address bits 31..24 for memory windows for 16-bit cards, + accessable only by memory mapping the 16-bit register set */ +#define CB_MEM_PAGE(map) (0x40 + (map)) + +#endif /* _LINUX_YENTA_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c --- v2.3.16/linux/drivers/pnp/isapnp.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/pnp/isapnp.c Tue Sep 7 10:14:37 1999 @@ -287,6 +287,14 @@ udelay(100); } +/* + * This code is badly broken. We cannot simply pick ports as the + * ISAPnP specification implies. We should try 4 or 5 safe ports + * then bale by default. + * + * This code touches NE2K cards or other devices and your box is + * history. + */ static int __init isapnp_isolate_rdp_select(void) { @@ -2102,6 +2110,13 @@ printk("isapnp: Write Data Register 0x%x already used\n", _PNPWRP); return -EBUSY; } + + /* + * Print a message. The existing ISAPnP code is hanging machines + * so let the user know where. + */ + + printk("isapnp: Scanning for Pnp cards...\n"); if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) { isapnp_rdp |= 3; isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read"); diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.3.16/linux/drivers/scsi/advansys.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/scsi/advansys.c Fri Sep 3 16:35:47 1999 @@ -1,10 +1,10 @@ -/* $Id: advansys.c,v 1.50 1998/05/08 23:39:15 bobf Exp bobf $ */ -#define ASC_VERSION "3.1E" /* AdvanSys Driver Version */ +/* $Id: advansys.c,v 1.58 1999/09/03 23:02:16 bobf Exp bobf $ */ +#define ASC_VERSION "3.2F" /* AdvanSys Driver Version */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters * - * Copyright (c) 1995-1998 Advanced System Products, Inc. + * Copyright (c) 1995-1999 Advanced System Products, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,19 +35,20 @@ G. Driver Compile Time Options and Debugging H. Driver LILO Option I. Release History - J. Known Problems or Issues + J. Known Problems/Fix List K. Credits L. AdvanSys Contact Information A. Linux Kernel Testing This driver has been tested in the following Linux kernels: v1.2.13, - v1.3.57, v2.0.33, v2.1.77. These kernel versions are major releases - of Linux or the latest Linux kernel versions available when this version - of the driver was released. The driver should also work in earlier - versions of the Linux kernel. Beginning with v1.3.58 the AdvanSys driver - is included with all Linux kernels. Please refer to sections C, D, and - E for instructions on adding or upgrading the AdvanSys driver. + v1.3.57, v2.0.38, v2.2.12, and v2.3.16. These kernel versions are major + releases of Linux or the latest Linux kernel versions available when + this version of the driver was released. The driver should also work + in earlier versions of the Linux kernel. Beginning with v1.3.58 the + AdvanSys driver is included with all Linux kernels. Please refer to + sections C, D, and E for instructions on adding or upgrading the + AdvanSys driver. B. Adapters Supported by this Driver @@ -65,15 +66,20 @@ lowered in the BIOS by changing the 'Host Queue Size' adapter setting. Connectivity Products: - ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1) - ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1, 3) - ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) (Footnote 4) + ABP510/5150 - Bus-Master ISA (240 CDB) + ABP5140 - Bus-Master ISA PnP (16 CDB) + ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) + ABP902/3902 - Bus-Master PCI (16 CDB) + ABP3905 - Bus-Master PCI (16 CDB) + ABP915 - Bus-Master PCI (16 CDB) ABP920 - Bus-Master PCI (16 CDB) - ABP930 - Bus-Master PCI (16 CDB) (Footnote 5) + ABP3922 - Bus-Master PCI (16 CDB) + ABP3925 - Bus-Master PCI (16 CDB) + ABP930 - Bus-Master PCI (16 CDB) ABP930U - Bus-Master PCI Ultra (16 CDB) ABP930UA - Bus-Master PCI Ultra (16 CDB) - ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2) - ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) (Footnote 2) + ABP960 - Bus-Master PCI MAC/PC (16 CDB) + ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) Single Channel Products: ABP542 - Bus-Master ISA with floppy (240 CDB) @@ -81,26 +87,23 @@ ABP842 - Bus-Master VL (240 CDB) ABP940 - Bus-Master PCI (240 CDB) ABP940U - Bus-Master PCI Ultra (240 CDB) + ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB) ABP970 - Bus-Master PCI MAC/PC (240 CDB) ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB) - ABP940UW - Bus-Master PCI Ultra-Wide (240 CDB) + ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB) + ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB) + ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB) + ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB) - Multi Channel Products: + Multi-Channel Products: ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel) ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel) + ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel) ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel) ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel) + ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.) - Footnotes: - 1. This board has been shipped by HP with the 4020i CD-R drive. - The board has no BIOS so it cannot control a boot device, but - it can control any secondary SCSI device. - 2. This board has been sold by Iomega as a Jaz Jet PCI adapter. - 3. This board has been sold by SIIG as the i540 SpeedMaster. - 4. This board has been sold by SIIG as the i542 SpeedMaster. - 5. This board has been sold by SIIG as the Fast SCSI Pro PCI. - C. Linux v1.2.X - Directions for Adding the AdvanSys Driver These directions apply to v1.2.13. For versions that follow v1.2.13. @@ -590,13 +593,63 @@ flag set to allow IRQ sharing with drivers that do not set the SA_INTERRUPT flag. Also display a more descriptive error message if request_irq() fails. - 5. Update to latest Asc and Adv Libraries. - - J. Known Problems or Issues + 6. Update to latest Asc and Adv Libraries. - 1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around - the queue depth flow control code when mid-level SCSI changes - are included in Linux. + 3.2A (7/22/99): + 1. Update Adv Library to 4.16 which includes support for + the ASC38C0800 (Ultra2/LVD) IC. + + 3.2B (8/23/99): + 1. Correct PCI compile time option for v2.1.93 and greater + kernels, advansys_info() string, and debug compile time + option. + 2. Correct DvcSleepMilliSecond() for v2.1.0 and greater + kernels. This caused an LVD detection/BIST problem problem + among other things. + 3. Sort PCI cards by PCI Bus, Slot, Function ascending order + to be consistent with the BIOS. + 4. Update to Asc Library S121 and Adv Library 5.2. + + 3.2C (8/24/99): + 1. Correct PCI card detection bug introduced in 3.2B that + prevented PCI cards from being detected in kernels older + than v2.1.93. + + 3.2D (8/26/99): + 1. Correct /proc device synchronous speed information display. + Also when re-negotiation is pending for a target device + note this condition with an * and footnote. + 2. Correct initialization problem with Ultra-Wide cards that + have a pre-3.2 BIOS. A microcode variable changed locations + in 3.2 and greater BIOSes which caused WDTR to be attempted + erroneously with drives that don't support WDTR. + + 3.2E (8/30/99): + 1. Fix compile error caused by v2.3.13 PCI structure change. + 2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM + checksum error for ISA cards. + 3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level + SCSI changes that it depended on were never included in Linux. + + 3.2F (9/3/99): + 1. Handle new initial function code added in v2.3.16 for all + driver versions. + + J. Known Problems/Fix List (XXX) + + 1. Need to add memory mapping workaround. Test the memory mapping. + If it doesn't work revert to I/O port access. Can a test be done + safely? + 2. Handle an interrupt not working. Keep an interrupt counter in + the interrupt handler. In the timeout function if the interrupt + has not occurred then print a message and run in polled mode. + 3. Allow bus type scanning order to be changed. + 4. Need to add support for target mode commands, cf. CAM XPT. + 5 Need to add support for new Linux SCSI error handling method. + 6. Need to fix sti/cli code in Asc Library. + 7. Need to fix abort code in Adv Library. + 8. Reduce io_request_lock hold time. + 9. Add big-endian support for Alpha. K. Credits @@ -617,17 +670,17 @@ Mark Moran has helped test Ultra-Wide support in the 3.1A driver. + Doug Gilbert has made changes and + suggestions to improve the driver and done testing. + L. AdvanSys Contact Information Mail: Advanced System Products, Inc. 1150 Ringwood Court San Jose, CA 95131 - Operator: 1-408-383-9400 + Operator/Sales: 1-408-383-9400 FAX: 1-408-383-9612 - Tech Support: 1-800-525-7440/1-408-467-2930 - BBS: 1-408-383-9540 (14400,N,8,1) - Interactive FAX: 1-408-383-9753 - Customer Direct Sales: 1-800-525-7443/1-408-383-5777 + Tech Support: 1-408-467-2930 Tech Support E-Mail: support@advansys.com FTP Site: ftp.advansys.com (login: anonymous) Web Site: http://www.advansys.com @@ -660,6 +713,9 @@ #include #include #include +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +#include +#endif /* verions < v2.1.0 */ #include #include #include @@ -745,8 +801,8 @@ */ #define ASC_LIB_VERSION_MAJOR 1 -#define ASC_LIB_VERSION_MINOR 22 -#define ASC_LIB_SERIAL_NUMBER 113 +#define ASC_LIB_VERSION_MINOR 24 +#define ASC_LIB_SERIAL_NUMBER 121 typedef unsigned char uchar; @@ -832,6 +888,15 @@ #define ASC_DVCLIB_CALL_FAILED (0) #define ASC_DVCLIB_CALL_ERROR (-1) +/* + * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists. + * The SRB structure will have to be changed and the ASC_SRB2SCSIQ() + * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the + * SRB structure. + */ +#define CC_VERY_LONG_SG_LIST 0 +#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr) + #define PortAddr unsigned short /* port address size */ #define Ptr2Func ulong #define inp(port) inb(port) @@ -976,6 +1041,9 @@ #define SCSI_TYPE_COMM 0x09 #define SCSI_TYPE_UNKNOWN 0x1F #define SCSI_TYPE_NO_DVC 0xFF +#define INQ_CLOCKING_ST_ONLY 0x0 +#define INQ_CLOCKING_DT_ONLY 0x1 +#define INQ_CLOCKING_ST_AND_DT 0x3 #define ASC_SCSIDIR_NOCHK 0x00 #define ASC_SCSIDIR_T2H 0x08 #define ASC_SCSIDIR_H2T 0x10 @@ -1194,9 +1262,10 @@ #define ASC_SCSIQ_CDB_BEG 36 #define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56 #define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60 +#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48 #define ASC_SCSIQ_B_SG_WK_QP 49 #define ASC_SCSIQ_B_SG_WK_IX 50 -#define ASC_SCSIQ_W_REQ_COUNT 52 +#define ASC_SCSIQ_W_ALT_DC1 52 #define ASC_SCSIQ_B_LIST_CNT 6 #define ASC_SCSIQ_B_CUR_LIST_CNT 7 #define ASC_SGQ_B_SG_CNTL 4 @@ -1307,6 +1376,8 @@ ASC_SCSIQ_2 q2; uchar *cdbptr; ASC_SG_HEAD *sg_head; + ushort remain_sg_entry_cnt; + ushort next_sg_index; } ASC_SCSI_Q; typedef struct asc_scsi_req_q { @@ -1781,6 +1852,7 @@ #define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300 #define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400 #define ASC_HALT_SDTR_REJECTED (ushort)0x4000 +#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000 #define ASC_MAX_QNO 0xF8 #define ASC_DATA_SEC_BEG (ushort)0x0080 #define ASC_DATA_SEC_END (ushort)0x0080 @@ -1876,10 +1948,10 @@ #define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B) #define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val) #define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val) -#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data)) ; -#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id)) ; -#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data) ; -#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id)) ; +#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data)); +#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id)); +#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data); +#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id)); #define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ]) #define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE) #define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD) @@ -2074,8 +2146,8 @@ * --- Adv Library Constants and Macros */ -#define ADV_LIB_VERSION_MAJOR 3 -#define ADV_LIB_VERSION_MINOR 45 +#define ADV_LIB_VERSION_MAJOR 5 +#define ADV_LIB_VERSION_MINOR 2 /* d_os_dep.h */ #define ADV_OS_LINUX @@ -2105,6 +2177,8 @@ #define iounmap vfree #endif /* version < v2.1.0 */ +#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15) + /* * Define total number of simultaneous maximum element scatter-gather * requests, i.e. ADV_TOT_SG_LIST * ADV_MAX_SG_LIST is the total number @@ -2117,18 +2191,9 @@ */ #define ADV_MAX_SG_LIST 64 -/* - * Scatter-Gather Definitions per request. - * - * Because SG block memory is allocated in virtual memory but is - * referenced by the microcode as physical memory, we need to do - * calculations to insure there will be enough physically contiguous - * memory to support ADV_MAX_SG_LIST SG entries. - */ - /* Number of SG blocks needed. */ #define ADV_NUM_SG_BLOCK \ - ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK) + ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK) /* Total contiguous memory needed for SG blocks. */ #define ADV_SG_TOTAL_MEM_SIZE \ @@ -2136,26 +2201,16 @@ #define ASC_PAGE_SIZE PAGE_SIZE -/* - * Number of page crossings possible for the total contiguous virtual memory - * needed for SG blocks. - * - * We need to allocate this many additional SG blocks in virtual memory to - * insure there will be space for ADV_NUM_SG_BLOCK physically contiguous - * scatter-gather blocks. - */ #define ADV_NUM_PAGE_CROSSING \ ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE) -/* - * Define Adv Library Assertion Macro. - */ - #define ADV_ASSERT(a) ASC_ASSERT(a) /* a_condor.h */ #define ADV_PCI_VENDOR_ID 0x10CD #define ADV_PCI_DEVICE_ID_REV_A 0x2300 +#define ADV_PCI_DEVID_38C0800_REV1 0x2500 +#define ADV_PCI_DEVID_38C1600_REV1 0x2700 #define ASC_EEP_DVC_CFG_BEGIN (0x00) #define ASC_EEP_DVC_CFG_END (0x15) @@ -2164,31 +2219,13 @@ #define ASC_EEP_DELAY_MS 100 -/* - * EEPROM bits reference by the RISC after initialization. - */ #define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */ #define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */ #define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */ +#define ADV_EEPROM_CIS_LD 0x1000 /* EEPROM Bit 12 */ -/* - * EEPROM configuration format - * - * Field naming convention: - * - * *_enable indicates the field enables or disables the feature. The - * value is never reset. - * - * *_able indicates both whether a feature should be enabled or disabled - * and whether a device isi capable of the feature. At initialization - * this field may be set, but later if a device is found to be incapable - * of the feature, the field is cleared. - * - * Default values are maintained in a_init.c in the structure - * Default_EEPROM_Config. - */ -typedef struct adveep_config -{ +typedef struct adveep_3550_config +{ /* Word Offset, Description */ ushort cfg_lsw; /* 00 power up initialization */ @@ -2255,7 +2292,109 @@ ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ ushort saved_adv_err_addr; /* 35 saved last uc error address */ ushort num_of_err; /* 36 number of error */ -} ADVEEP_CONFIG; +} ADVEEP_3550_CONFIG; + +typedef struct adveep_38C0800_config +{ + /* Word Offset, Description */ + + ushort cfg_lsw; /* 00 power up initialization */ + /* bit 12 set - CIS Load */ + /* bit 13 set - Term Polarity Control */ + /* bit 14 set - BIOS Enable */ + /* bit 15 set - Big Endian Mode */ + ushort cfg_msw; /* 01 unused */ + ushort disc_enable; /* 02 disconnect enable */ + ushort wdtr_able; /* 03 Wide DTR able */ + ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */ + ushort start_motor; /* 05 send start up motor */ + ushort tagqng_able; /* 06 tag queuing able */ + ushort bios_scan; /* 07 BIOS device control */ + ushort scam_tolerant; /* 08 no scam */ + + uchar adapter_scsi_id; /* 09 Host Adapter ID */ + uchar bios_boot_delay; /* power up wait */ + + uchar scsi_reset_delay; /* 10 reset delay */ + uchar bios_id_lun; /* first boot device scsi id & lun */ + /* high nibble is lun */ + /* low nibble is scsi id */ + + uchar termination_se; /* 11 0 - automatic */ + /* 1 - low off / high off */ + /* 2 - low off / high on */ + /* 3 - low on / high on */ + /* There is no low on / high off */ + + uchar termination_lvd; /* 11 0 - automatic */ + /* 1 - low off / high off */ + /* 2 - low off / high on */ + /* 3 - low on / high on */ + /* There is no low on / high off */ + + ushort bios_ctrl; /* 12 BIOS control bits */ + /* bit 0 set: BIOS don't act as initiator. */ + /* bit 1 set: BIOS > 1 GB support */ + /* bit 2 set: BIOS > 2 Disk Support */ + /* bit 3 set: BIOS don't support removables */ + /* bit 4 set: BIOS support bootable CD */ + /* bit 5 set: BIOS scan enabled */ + /* bit 6 set: BIOS support multiple LUNs */ + /* bit 7 set: BIOS display of message */ + /* bit 8 set: */ + /* bit 9 set: Reset SCSI bus during init. */ + /* bit 10 set: */ + /* bit 11 set: No verbose initialization. */ + /* bit 12 set: SCSI parity enabled */ + /* bit 13 set: */ + /* bit 14 set: */ + /* bit 15 set: */ + ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */ + ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */ + uchar max_host_qng; /* 15 maximum host queueing */ + uchar max_dvc_qng; /* maximum per device queuing */ + ushort dvc_cntl; /* 16 control bit for driver */ + ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */ + ushort serial_number_word1; /* 18 Board serial number word 1 */ + ushort serial_number_word2; /* 19 Board serial number word 2 */ + ushort serial_number_word3; /* 20 Board serial number word 3 */ + ushort check_sum; /* 21 EEP check sum */ + uchar oem_name[16]; /* 22 OEM name */ + ushort dvc_err_code; /* 30 last device driver error code */ + ushort adv_err_code; /* 31 last uc and Adv Lib error code */ + ushort adv_err_addr; /* 32 last uc error address */ + ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */ + ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ + ushort saved_adv_err_addr; /* 35 saved last uc error address */ + ushort reserved36; /* 36 reserved */ + ushort reserved37; /* 37 reserved */ + ushort reserved38; /* 38 reserved */ + ushort reserved39; /* 39 reserved */ + ushort reserved40; /* 40 reserved */ + ushort reserved41; /* 41 reserved */ + ushort reserved42; /* 42 reserved */ + ushort reserved43; /* 43 reserved */ + ushort reserved44; /* 44 reserved */ + ushort reserved45; /* 45 reserved */ + ushort reserved46; /* 46 reserved */ + ushort reserved47; /* 47 reserved */ + ushort reserved48; /* 48 reserved */ + ushort reserved49; /* 49 reserved */ + ushort reserved50; /* 50 reserved */ + ushort reserved51; /* 51 reserved */ + ushort reserved52; /* 52 reserved */ + ushort reserved53; /* 53 reserved */ + ushort reserved54; /* 54 reserved */ + ushort reserved55; /* 55 reserved */ + ushort cisptr_lsw; /* 56 CIS PTR LSW */ + ushort cisprt_msw; /* 57 CIS PTR MSW */ + ushort subsysvid; /* 58 SubSystem Vendor ID */ + ushort subsysid; /* 59 SubSystem ID */ + ushort reserved60; /* 60 reserved */ + ushort reserved61; /* 61 reserved */ + ushort reserved62; /* 62 reserved */ + ushort reserved63; /* 63 reserved */ +} ADVEEP_38C0800_CONFIG; /* * EEPROM Commands @@ -2279,15 +2418,15 @@ #define BIOS_CTRL_INIT_VERBOSE 0x0800 #define BIOS_CTRL_SCSI_PARITY 0x1000 -/* - * ASC 3550 Internal Memory Size - 8KB - */ -#define ADV_CONDOR_MEMSIZE 0x2000 /* 8 KB Internal Memory */ +#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */ +#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */ -/* - * ASC 3550 I/O Length - 64 bytes - */ -#define ADV_CONDOR_IOLEN 0x40 /* I/O Port Range in bytes */ +#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */ +#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */ + +#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */ +#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */ +#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */ /* * Byte I/O register address from base of 'iop_base'. @@ -2306,11 +2445,11 @@ #define IOPB_RES_ADDR_B 0x0B #define IOPB_RES_ADDR_C 0x0C #define IOPB_RES_ADDR_D 0x0D -#define IOPB_RES_ADDR_E 0x0E +#define IOPB_SOFT_OVER_WR 0x0E #define IOPB_RES_ADDR_F 0x0F #define IOPB_MEM_CFG 0x10 -#define IOPB_RES_ADDR_11 0x11 -#define IOPB_RES_ADDR_12 0x12 +#define IOPB_GPIO_CNTL 0x11 +#define IOPB_GPIO_DATA 0x12 #define IOPB_RES_ADDR_13 0x13 #define IOPB_FLASH_PAGE 0x14 #define IOPB_RES_ADDR_15 0x15 @@ -2348,8 +2487,8 @@ #define IOPB_RES_ADDR_35 0x35 #define IOPB_RES_ADDR_36 0x36 #define IOPB_RES_ADDR_37 0x37 -#define IOPB_RES_ADDR_38 0x38 -#define IOPB_RES_ADDR_39 0x39 +#define IOPB_RAM_BIST 0x38 +#define IOPB_PLL_TEST 0x39 #define IOPB_RES_ADDR_3A 0x3A #define IOPB_RES_ADDR_3B 0x3B #define IOPB_RFIFO_CNT 0x3C @@ -2402,8 +2541,8 @@ #define IOPDW_RES_ADDR_8 0x08 #define IOPDW_RES_ADDR_C 0x0C #define IOPDW_RES_ADDR_10 0x10 -#define IOPDW_RES_ADDR_14 0x14 -#define IOPDW_RES_ADDR_18 0x18 +#define IOPDW_COMMA 0x14 +#define IOPDW_COMMB 0x18 #define IOPDW_RES_ADDR_1C 0x1C #define IOPDW_SDMA_ADDR0 0x20 #define IOPDW_SDMA_ADDR1 0x24 @@ -2453,9 +2592,14 @@ #define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3 #define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2 +#define ADV_TICKLE_NOP 0x00 +#define ADV_TICKLE_A 0x01 +#define ADV_TICKLE_B 0x02 +#define ADV_TICKLE_C 0x03 + #define ADV_SCSI_CTRL_RSTOUT 0x2000 -#define AdvIsIntPending(port) \ +#define AdvIsIntPending(port) \ (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR) /* @@ -2492,6 +2636,28 @@ #define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */ #define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */ +/* + * Addendum for ASC-38C0800 Chip + */ +#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */ +#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */ +#define HVD 0x1000 /* HVD Device Detect */ +#define LVD 0x0800 /* LVD Device Detect */ +#define SE 0x0400 /* SE Device Detect */ +#define TERM_LVD 0x00C0 /* LVD Termination Bits */ +#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */ +#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */ +#define TERM_SE 0x0030 /* SE Termination Bits */ +#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */ +#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */ +#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */ +#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */ +#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */ +#define C_DET_SE 0x0003 /* SE Cable Detect Bits */ +#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */ +#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */ + + #define CABLE_ILLEGAL_A 0x7 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */ @@ -2499,35 +2665,6 @@ /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */ /* - The following table details the SCSI_CFG1 Termination Polarity, - Termination Control and Cable Detect bits. - - Cable Detect | Termination - Bit 3 2 1 0 | 5 4 | Notes - _____________|________|____________________ - 1 1 1 0 | on on | Internal wide only - 1 1 0 1 | on on | Internal narrow only - 1 0 1 1 | on on | External narrow only - 0 x 1 1 | on on | External wide only - 1 1 0 0 | on off| Internal wide and internal narrow - 1 0 1 0 | on off| Internal wide and external narrow - 0 x 1 0 | off off| Internal wide and external wide - 1 0 0 1 | on off| Internal narrow and external narrow - 0 x 0 1 | on off| Internal narrow and external wide - 1 1 1 1 | on on | No devices are attached - x 0 0 0 | on on | Illegal (all 3 connectors are used) - 0 x 0 0 | on on | Illegal (all 3 connectors are used) - - x means don't-care (either '0' or '1') - - If term_pol (bit 13) is '0' (active-low terminator enable), then: - 'on' is '0' and 'off' is '1'. - - If term_pol bit is '1' (meaning active-hi terminator enable), then: - 'on' is '1' and 'off' is '0'. - */ - -/* * MEM_CFG Register bit definitions */ #define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */ @@ -2564,6 +2701,22 @@ #define READ_CMD_MRL 0x02 /* Memory Read Long */ #define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */ +/* + * ASC-38C0800 RAM BIST Register bit definitions + */ +#define RAM_TEST_MODE 0x80 +#define PRE_TEST_MODE 0x40 +#define NORMAL_MODE 0x00 +#define RAM_TEST_DONE 0x10 +#define RAM_TEST_STATUS 0x0F +#define RAM_TEST_HOST_ERROR 0x08 +#define RAM_TEST_INTRAM_ERROR 0x04 +#define RAM_TEST_RISC_ERROR 0x02 +#define RAM_TEST_SCSI_ERROR 0x01 +#define RAM_TEST_SUCCESS 0x00 +#define PRE_TEST_VALUE 0x05 +#define NORMAL_VALUE 0x00 + /* a_advlib.h */ /* @@ -2580,6 +2733,7 @@ /* * ASC_DVC_VAR 'warn_code' values */ +#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */ #define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */ #define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */ #define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */ @@ -2596,14 +2750,18 @@ */ #define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */ #define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */ +#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */ #define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */ #define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */ #define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */ +#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */ #define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */ #define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */ #define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */ #define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */ -#define ASC_IERR_RW_LRAM 0x8000 /* read/write local RAM error */ +#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */ +#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */ +#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */ /* * Fixed locations of microcode operating variables. @@ -2611,37 +2769,38 @@ #define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */ #define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */ #define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */ -#define ASC_MC_STACK_BEGIN 0x002E /* microcode stack begin */ -#define ASC_MC_STACK_END 0x0030 /* microcode stack end */ #define ASC_MC_VERSION_DATE 0x0038 /* microcode version */ #define ASC_MC_VERSION_NUM 0x003A /* microcode number */ -#define ASCV_VER_SERIAL_W 0x003C /* used in dos_init */ #define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */ #define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */ -#define ASC_MC_HALTCODE 0x0094 /* microcode halt code */ -#define ASC_MC_CALLERPC 0x0096 /* microcode halt caller PC */ -#define ASC_MC_ADAPTER_SCSI_ID 0x0098 /* one ID byte + reserved */ -#define ASC_MC_ULTRA_ABLE 0x009C +#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */ +#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */ +#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */ +#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */ +#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */ +#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */ +#define ASC_MC_CHIP_TYPE 0x009A +#define ASC_MC_INTRB_CODE 0x009B +#define ASC_MC_WDTR_ABLE 0x009C #define ASC_MC_SDTR_ABLE 0x009E #define ASC_MC_TAGQNG_ABLE 0x00A0 #define ASC_MC_DISC_ENABLE 0x00A2 +#define ASC_MC_IDLE_CMD_STATUS 0x00A4 #define ASC_MC_IDLE_CMD 0x00A6 -#define ASC_MC_IDLE_PARA_STAT 0x00A8 +#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8 #define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC #define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE #define ASC_MC_DEFAULT_MEM_CFG 0x00B0 #define ASC_MC_DEFAULT_SEL_MASK 0x00B2 -#define ASC_MC_RISC_NEXT_READY 0x00B4 -#define ASC_MC_RISC_NEXT_DONE 0x00B5 #define ASC_MC_SDTR_DONE 0x00B6 #define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0 #define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0 #define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100 -#define ASC_MC_WDTR_ABLE 0x0120 /* Wide Transfer TID bitmask. */ #define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */ #define ASC_MC_WDTR_DONE 0x0124 -#define ASC_MC_HOST_NEXT_READY 0x0128 /* Host Next Ready RQL Entry. */ -#define ASC_MC_HOST_NEXT_DONE 0x0129 /* Host Next Done RQL Entry. */ +#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */ +#define ASC_MC_ICQ 0x0160 +#define ASC_MC_IRQ 0x0164 /* * BIOS LRAM variable absolute offsets. @@ -2650,7 +2809,6 @@ #define BIOS_CODELEN 0x56 #define BIOS_SIGNATURE 0x58 #define BIOS_VERSION 0x5A -#define BIOS_SIGNATURE 0x58 /* * Microcode Control Flags @@ -2667,50 +2825,61 @@ #define HSHK_CFG_RATE 0x0F00 #define HSHK_CFG_OFFSET 0x001F -/* - * LRAM RISC Queue Lists (LRAM addresses 0x1200 - 0x19FF) - * - * Each of the 255 Adv Library/Microcode RISC queue lists or mailboxes - * starting at LRAM address 0x1200 is 8 bytes and has the following - * structure. Only 253 of these are actually used for command queues. - */ - -#define ASC_MC_RISC_Q_LIST_BASE 0x1200 -#define ASC_MC_RISC_Q_LIST_SIZE 0x0008 -#define ASC_MC_RISC_Q_TOTAL_CNT 0x00FF /* Num. queue slots in LRAM. */ -#define ASC_MC_RISC_Q_FIRST 0x0001 -#define ASC_MC_RISC_Q_LAST 0x00FF - #define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */ #define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */ #define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */ #define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */ -/* RISC Queue List structure - 8 bytes */ -#define RQL_FWD 0 /* forward pointer (1 byte) */ -#define RQL_BWD 1 /* backward pointer (1 byte) */ -#define RQL_STATE 2 /* state byte - free, ready, done, aborted (1 byte) */ -#define RQL_TID 3 /* request target id (1 byte) */ -#define RQL_PHYADDR 4 /* request physical pointer (4 bytes) */ - -/* RISC Queue List state values */ -#define ASC_MC_QS_FREE 0x00 -#define ASC_MC_QS_READY 0x01 -#define ASC_MC_QS_DONE 0x40 -#define ASC_MC_QS_ABORTED 0x80 - -/* RISC Queue List pointer values */ -#define ASC_MC_NULL_Q 0x00 /* NULL_Q == 0 */ -#define ASC_MC_BIOS_Q 0xFF /* BIOS_Q = 255 */ - -/* ASC_SCSI_REQ_Q 'cntl' field values */ -#define ASC_MC_QC_START_MOTOR 0x02 /* Issue start motor. */ -#define ASC_MC_QC_NO_OVERRUN 0x04 /* Don't report overrun. */ -#define ASC_MC_QC_FIRST_DMA 0x08 /* Internal microcode flag. */ -#define ASC_MC_QC_ABORTED 0x10 /* Request aborted by host. */ -#define ASC_MC_QC_REQ_SENSE 0x20 /* Auto-Request Sense. */ -#define ASC_MC_QC_DOS_REQ 0x80 /* Request issued by DOS. */ +#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */ +#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */ +#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */ +#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */ +#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */ + +#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */ +#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */ +#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */ +#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */ +#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */ +/* + * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or + * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used. + */ +#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */ +#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */ + +typedef struct adv_carr_t +{ + ulong carr_va; /* Carrier Virtual Address */ + ulong carr_pa; /* Carrier Physical Address */ + ulong areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */ + /* + * next_vpa [31:4] Carrier Virtual or Physical Next Pointer + * + * next_vpa [3:1] Reserved Bits + * next_vpa [0] Done Flag set in Response Queue. + */ + ulong next_vpa; +} ADV_CARR_T; + +/* + * Mask used to eliminate low 4 bits of carrier 'next_vpa' field. + */ +#define ASC_NEXT_VPA_MASK 0xFFFFFFF0 +#define ASC_RQ_DONE 0x00000001 +#define ASC_CQ_STOPPER 0x00000000 + +#define ASC_GET_CARRP(carrp) ((ADV_CARR_T *) ((carrp) & ASC_NEXT_VPA_MASK)) + +#define ADV_PAGE_SIZE 4096 /* Assume 4KB page size. */ + +#define ADV_CARRIER_NUM_PAGE_CROSSING \ + (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \ + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE) + +#define ADV_CARRIER_BUFSIZE \ + ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T)) /* * ASC_SCSI_REQ_Q 'a_flag' definitions @@ -2720,6 +2889,11 @@ */ #define ADV_POLL_REQUEST 0x01 /* poll for request completion */ #define ADV_SCSIQ_DONE 0x02 /* request done */ +#define ADV_DONT_RETRY 0x08 /* don't do retry */ + +#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */ +#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */ +#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */ /* * Adapter temporary configuration structure @@ -2744,12 +2918,20 @@ ushort pci_slot_info; /* high byte device/function number */ /* bits 7-3 device num., bits 2-0 function num. */ /* low byte bus num. */ - ushort bios_boot_wait; /* BIOS boot time delay */ ushort serial1; /* EEPROM serial number word 1 */ ushort serial2; /* EEPROM serial number word 2 */ ushort serial3; /* EEPROM serial number word 3 */ } ADV_DVC_CFG; +struct adv_dvc_var; +struct adv_scsi_req_q; + +typedef void (* ADV_ISR_CALLBACK) + (struct adv_dvc_var *, struct adv_scsi_req_q *); + +typedef void (* ADV_ASYNC_CALLBACK) + (struct adv_dvc_var *, uchar); + /* * Adapter operation variable structure. * @@ -2766,23 +2948,32 @@ AdvPortAddr iop_base; /* I/O port address */ ushort err_code; /* fatal error code */ ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */ - Ptr2Func isr_callback; /* pointer to function, called in AdvISR() */ - Ptr2Func sbreset_callback; /* pointer to function, called in AdvISR() */ + ADV_ISR_CALLBACK isr_callback; + ADV_ASYNC_CALLBACK async_callback; ushort wdtr_able; /* try WDTR for a device */ ushort sdtr_able; /* try SDTR for a device */ ushort ultra_able; /* try SDTR Ultra speed for a device */ + ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */ + ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */ + ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */ + ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */ ushort tagqng_able; /* try tagged queuing with a device */ uchar max_dvc_qng; /* maximum number of tagged commands per device */ ushort start_motor; /* start motor command allowed */ uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */ uchar chip_no; /* should be assigned by caller */ uchar max_host_qng; /* maximum number of Q'ed command allowed */ - uchar cur_host_qng; /* total number of queue command */ uchar irq_no; /* IRQ number */ ushort no_scam; /* scam_tolerant of EEPROM */ - ushort idle_cmd_done; /* microcode idle command done set by AdvISR() */ ulong drv_ptr; /* driver pointer to private structure */ uchar chip_scsi_id; /* chip SCSI target ID */ + uchar chip_type; + uchar bist_err_code; + ADV_CARR_T *carrier_buf; + ADV_CARR_T *carr_freelist; /* Carrier free list. */ + ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */ + ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */ + ushort carr_pending_cnt; /* Count of pending carriers. */ /* * Note: The following fields will not be used after initialization. The * driver may discard the buffer after initialization is done. @@ -2795,17 +2986,17 @@ typedef struct asc_sg_block { uchar reserved1; uchar reserved2; - uchar first_entry_no; /* starting entry number */ - uchar last_entry_no; /* last entry number */ + uchar reserved3; + uchar sg_cnt; /* Valid entries in block. */ struct asc_sg_block *sg_ptr; /* links to the next sg block */ struct { - ulong sg_addr; /* SG element address */ - ulong sg_count; /* SG element count */ + ulong sg_addr; /* SG element address. */ + ulong sg_count; /* SG element count. */ } sg_list[NO_OF_SG_PER_BLOCK]; } ADV_SG_BLOCK; /* - * ASC_SCSI_REQ_Q - microcode request structure + * ADV_SCSI_REQ_Q - microcode request structure * * All fields in this structure up to byte 60 are used by the microcode. * The microcode makes assumptions about the size and ordering of fields @@ -2814,35 +3005,36 @@ */ typedef struct adv_scsi_req_q { uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */ - uchar sg_entry_cnt; /* SG element count. Zero for no SG. */ + uchar reserved; uchar target_id; /* Device target identifier. */ uchar target_lun; /* Device target logical unit number. */ ulong data_addr; /* Data buffer physical address. */ ulong data_cnt; /* Data count. Ucode sets to residual. */ - ulong sense_addr; /* Sense buffer physical address. */ - ulong srb_ptr; /* Driver request pointer. */ - uchar a_flag; /* Adv Library flag field. */ - uchar sense_len; /* Auto-sense length. Ucode sets to residual. */ + ulong sense_addr; + ulong carr_pa; + uchar mflag; + uchar sense_len; uchar cdb_len; /* SCSI CDB length. */ - uchar tag_code; /* SCSI-2 Tag Queue Code: 00, 20-22. */ + uchar scsi_cntl; uchar done_status; /* Completion status. */ uchar scsi_status; /* SCSI status byte. */ uchar host_status; /* Ucode host status. */ - uchar ux_sg_ix; /* Ucode working SG variable. */ + uchar sg_working_ix; uchar cdb[12]; /* SCSI command block. */ ulong sg_real_addr; /* SG list physical address. */ - struct adv_scsi_req_q *free_scsiq_link; - ulong ux_wk_data_cnt; /* Saved data count at disconnection. */ + ulong scsiq_rptr; + ulong sg_working_data_cnt; struct adv_scsi_req_q *scsiq_ptr; - ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */ + ulong carr_va; /* * End of microcode structure - 60 bytes. The rest of the structure * is used by the Adv Library and ignored by the microcode. */ - ulong vsense_addr; /* Sense buffer virtual address. */ + ulong srb_ptr; + ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */ ulong vdata_addr; /* Data buffer virtual address. */ - uchar orig_sense_len; /* Original length of sense buffer. */ -} ADV_SCSI_REQ_Q; /* BIOS - 70 bytes, DOS - 76 bytes, W95, WNT - 69 bytes */ + uchar a_flag; +} ADV_SCSI_REQ_Q; /* * Microcode idle loop commands @@ -2853,7 +3045,12 @@ #define IDLE_CMD_SEND_INT 0x0004 #define IDLE_CMD_ABORT 0x0008 #define IDLE_CMD_DEVICE_RESET 0x0010 -#define IDLE_CMD_SCSI_RESET 0x0020 +#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */ +#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */ +#define IDLE_CMD_SCSIREQ 0x0080 + +#define IDLE_CMD_STATUS_SUCCESS 0x0001 +#define IDLE_CMD_STATUS_FAILURE 0x0002 /* * AdvSendIdleCmd() flag definitions. @@ -2863,8 +3060,17 @@ /* * Wait loop time out values. */ -#define SCSI_WAIT_10_SEC 10 /* 10 seconds */ -#define SCSI_MS_PER_SEC 1000 /* milliseconds per second */ +#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */ +#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */ +#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */ +#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */ +#define SCSI_MAX_RETRY 10 /* retry count */ + +#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */ +#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */ +#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */ + +#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */ /* * Device drivers must define the following functions. @@ -2886,21 +3092,23 @@ STATIC int AdvISR(ADV_DVC_VAR *); STATIC int AdvInitGetConfig(ADV_DVC_VAR *); STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *); -STATIC int AdvResetSB(ADV_DVC_VAR *); +STATIC int AdvInitAsc38C0800Driver(ADV_DVC_VAR *); +STATIC int AdvResetChipAndSB(ADV_DVC_VAR *); +STATIC int AdvResetSB(ADV_DVC_VAR *asc_dvc); /* * Internal Adv Library functions. */ -STATIC int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong, int); -STATIC void AdvResetChip(ADV_DVC_VAR *); -STATIC int AdvSendScsiCmd(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); +STATIC int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong); STATIC void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); -STATIC int AdvInitFromEEP(ADV_DVC_VAR *); -STATIC ushort AdvGetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *); -STATIC void AdvSetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *); +STATIC int AdvInitFrom3550EEP(ADV_DVC_VAR *); +STATIC int AdvInitFrom38C0800EEP(ADV_DVC_VAR *); +STATIC ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *); +STATIC void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *); +STATIC ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *); +STATIC void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *); STATIC void AdvWaitEEPCmd(AdvPortAddr); STATIC ushort AdvReadEEPWord(AdvPortAddr, int); -STATIC void AdvResetSCSIBus(ADV_DVC_VAR *); /* * PCI Bus Definitions @@ -2911,20 +3119,16 @@ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) /* Read byte from a register. */ -#define AdvReadByteRegister(iop_base, reg_off) \ - (inp((iop_base) + (reg_off))) +#define AdvReadByteRegister(iop_base, reg_off) (inp((iop_base) + (reg_off))) /* Write byte to a register. */ -#define AdvWriteByteRegister(iop_base, reg_off, byte) \ - (outp((iop_base) + (reg_off), (byte))) +#define AdvWriteByteRegister(iop_base, reg_off, byte) (outp((iop_base) + (reg_off), (byte))) /* Read word (2 bytes) from a register. */ -#define AdvReadWordRegister(iop_base, reg_off) \ - (inpw((iop_base) + (reg_off))) +#define AdvReadWordRegister(iop_base, reg_off) (inpw((iop_base) + (reg_off))) /* Write word (2 bytes) to a register. */ -#define AdvWriteWordRegister(iop_base, reg_off, word) \ - (outpw((iop_base) + (reg_off), (word))) +#define AdvWriteWordRegister(iop_base, reg_off, word) (outpw((iop_base) + (reg_off), (word))) /* Read byte from LRAM. */ #define AdvReadByteLram(iop_base, addr, byte) \ @@ -3060,9 +3264,9 @@ * ADV_TRUE(1) - Queue was successfully aborted. * ADV_FALSE(0) - Queue was not found on the active queue list. */ -#define AdvAbortSRB(asc_dvc, srb_ptr) \ - AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \ - (ulong) (srb_ptr), 0) +#define AdvAbortQueue(asc_dvc, scsiq) \ + AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \ + (ulong) (scsiq)) /* * Send a Bus Device Reset Message to the specified target ID. @@ -3077,7 +3281,7 @@ */ #define AdvResetDevice(asc_dvc, target_id) \ AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \ - (ulong) (target_id), 0) + (ulong) (target_id)) /* * SCSI Wide Type definition. @@ -3120,22 +3324,25 @@ #define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */ #define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */ #define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */ +#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */ +#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */ +#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */ +#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */ +#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */ #define QHSTA_M_WTM_TIMEOUT 0x41 #define QHSTA_M_BAD_CMPL_STATUS_IN 0x42 #define QHSTA_M_NO_AUTO_REQ_SENSE 0x43 #define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44 #define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */ +#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */ +#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */ -typedef int (* ADV_ISR_CALLBACK) - (ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); - -typedef int (* ADV_SBRESET_CALLBACK) - (ADV_DVC_VAR *); /* * Default EEPROM Configuration structure defined in a_init.c. */ -extern ADVEEP_CONFIG Default_EEPROM_Config; +extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config; +extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config; /* * DvcGetPhyAddr() flag arguments @@ -3145,9 +3352,11 @@ #define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */ #define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */ #define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */ +#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */ /* Return the address that is aligned at the next doubleword >= to 'addr'. */ #define ADV_DWALIGN(addr) (((ulong) (addr) + 0x3) & ~0x3) +#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF) /* * Total contiguous memory needed for driver SG blocks. @@ -3174,6 +3383,44 @@ #define ADV_ASSERT(a) #endif /* ADV_ASSERT */ +typedef struct { + uchar peri_dvc_type : 5; /* peripheral device type */ + uchar peri_qualifier : 3; /* peripheral qualifier */ + uchar dvc_type_modifier : 7; /* device type modifier (for SCSI I) */ + uchar rmb : 1; /* RMB - removable medium bit */ + uchar ansi_apr_ver : 3; /* ANSI approved version */ + uchar ecma_ver : 3; /* ECMA version */ + uchar iso_ver : 2; /* ISO version */ + uchar rsp_data_fmt : 4; /* response data format */ + /* 0 SCSI 1 */ + /* 1 CCS */ + /* 2 SCSI-2 */ + /* 3-F reserved */ + uchar res1 : 2; /* reserved */ + uchar TemIOP : 1; /* terminate I/O process bit (see 5.6.22) */ + uchar aenc : 1; /* asynch. event notification (processor) */ + uchar add_len; /* additional length */ + uchar res2; /* reserved */ + uchar res3; /* reserved */ + uchar StfRe : 1; /* soft reset implemented */ + uchar CmdQue : 1; /* command queuing */ + uchar res4 : 1; /* reserved */ + uchar Linked : 1; /* linked command for this logical unit */ + uchar Sync : 1; /* synchronous data transfer */ + uchar WBus16 : 1; /* wide bus 16 bit data transfer */ + uchar WBus32 : 1; /* wide bus 32 bit data transfer */ + uchar RelAdr : 1; /* relative addressing mode */ + uchar vendor_id[8]; /* vendor identification */ + uchar product_id[16]; /* product identification */ + uchar product_rev_level[4]; /* product revision level */ + uchar vendor_specific[20]; /* vendor specific */ + uchar IUS : 1; /* information unit supported */ + uchar QAS : 1; /* quick arbitrate supported */ + uchar Clocking : 2; /* clocking field */ + uchar res5 : 4; /* reserved */ + uchar res6; /* reserved */ +} ADV_SCSI_INQUIRY; /* 58 bytes */ + /* * --- Driver Constants and Macros @@ -3203,11 +3450,17 @@ * are not used when the driver is built as a module, cf. linux/init.h. */ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23) +#define ASC_INITFUNC(type, func) type func #define ASC_INITDATA #define ASC_INIT #else /* version >= v2.1.23 */ -#define ASC_INITDATA __initdata -#define ASC_INIT __init +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,16) +#define ASC_INITFUNC(type, func) __initfunc(type func) +#else /* version >= v2.3.16 */ +#define ASC_INITFUNC(type, func) type __init func +#endif /* version >= v2.3.16 */ +#define ASC_INITDATA __initdata +#define ASC_INIT __init #endif /* version >= v2.1.23 */ #define ASC_INFO_SIZE 128 /* advansys_info() line size */ @@ -3350,11 +3603,12 @@ #define PCI_MAX_BUS 0xFF #define PCI_IOADDRESS_MASK 0xFFFE #define ASC_PCI_VENDORID 0x10CD -#define ASC_PCI_DEVICE_ID_CNT 4 /* PCI Device ID count. */ +#define ASC_PCI_DEVICE_ID_CNT 5 /* PCI Device ID count. */ #define ASC_PCI_DEVICE_ID_1100 0x1100 #define ASC_PCI_DEVICE_ID_1200 0x1200 #define ASC_PCI_DEVICE_ID_1300 0x1300 -#define ASC_PCI_DEVICE_ID_2300 0x2300 +#define ASC_PCI_DEVICE_ID_2300 0x2300 /* ASC-3550 */ +#define ASC_PCI_DEVICE_ID_2500 0x2500 /* ASC-38C0800 */ /* PCI IO Port Addresses to generate special cycle */ @@ -3660,14 +3914,12 @@ ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */ Scsi_Device *device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */ ushort reqcnt[ADV_MAX_TID+1]; /* Starvation request count */ -#if ASC_QUEUE_FLOW_CONTROL - ushort nerrcnt[ADV_MAX_TID+1]; /* No error request count */ -#endif /* ASC_QUEUE_FLOW_CONTROL */ ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */ ushort queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */ union { - ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */ - ADVEEP_CONFIG adv_eep; /* Wide EEPROM config. */ + ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */ + ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */ + ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */ } eep_config; ulong last_reset; /* Saved last reset time */ #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) @@ -3690,6 +3942,7 @@ */ void *ioremap_addr; /* I/O Memory remap address. */ ushort ioport; /* I/O Port address. */ + ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */ adv_req_t *orig_reqp; /* adv_req_t memory block. */ adv_req_t *adv_reqp; /* Request structures. */ adv_sgblk_t *orig_sgblkp; /* adv_sgblk_t memory block. */ @@ -3808,6 +4061,7 @@ * 16 elements of each structure. v1.3.0 kernels will probably * not need any more than this number. */ +uchar adv_carr_buf[20 * sizeof(ADV_CARR_T)] = { 0 }; uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 }; uchar adv_sgblk_buf[16 * sizeof(adv_sgblk_t)] = { 0 }; #endif /* version >= v1,3,0 */ @@ -3854,6 +4108,7 @@ STATIC int adv_get_sglist(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, Scsi_Cmnd *); STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *); STATIC void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); +STATIC void adv_async_callback(ADV_DVC_VAR *, uchar); #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI STATIC int asc_srch_pci_dev(PCI_DEVICE *); @@ -3883,7 +4138,7 @@ STATIC int asc_prt_line(char *, int, char *fmt, ...); #endif /* version >= v1.3.0 */ -/* Declaration for Asc Library internal functions reference by driver. */ +/* Declaration for Asc Library internal functions referenced by driver. */ STATIC int AscFindSignature(PortAddr); STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); @@ -3940,7 +4195,6 @@ int hostno, int inout) { #ifdef CONFIG_PROC_FS - struct Scsi_Host *shp; asc_board_t *boardp; int i; @@ -4150,9 +4404,9 @@ #else /* CONFIG_PROC_FS */ return 0; #endif /* CONFIG_PROC_FS */ - } #endif /* version >= v1.3.0 */ + /* * advansys_detect() * @@ -4166,20 +4420,27 @@ * it must not call SCSI mid-level functions including scsi_malloc() * and scsi_free(). */ -int ASC_INIT +ASC_INITFUNC( +int, advansys_detect(Scsi_Host_Template *tpnt) +) { static int detect_called = ASC_FALSE; int iop; int bus; - struct Scsi_Host *shp; - asc_board_t *boardp; + struct Scsi_Host *shp = NULL; + asc_board_t *boardp = NULL; ASC_DVC_VAR *asc_dvc_varp = NULL; ADV_DVC_VAR *adv_dvc_varp = NULL; int ioport = 0; int share_irq = FALSE; + int iolen = 0; #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI + int pci_init_search = 0; + PCI_DEVICE pci_device[ASC_NUM_BOARD_SUPPORTED]; + int pci_card_cnt_max = 0; + int pci_card_cnt = 0; PCI_DEVICE pciDevice; PCI_CONFIG_SPACE pciConfig; #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) @@ -4188,13 +4449,18 @@ #endif /* ASC_CONFIG_PCI */ #else /* version >= v2.1.93 */ #ifdef CONFIG_PCI + int pci_init_search = 0; + struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED]; + int pci_card_cnt_max = 0; + int pci_card_cnt = 0; struct pci_dev *pci_devp = NULL; int pci_device_id_cnt = 0; unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = { ASC_PCI_DEVICE_ID_1100, ASC_PCI_DEVICE_ID_1200, ASC_PCI_DEVICE_ID_1300, - ASC_PCI_DEVICE_ID_2300 + ASC_PCI_DEVICE_ID_2300, + ASC_PCI_DEVICE_ID_2500 }; unsigned long pci_memory_address; #endif /* CONFIG_PCI */ @@ -4308,10 +4574,10 @@ (AscGetChipVersion(iop, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT) == 0) { /* - * Don't clear 'asc_ioport[ioport]'. Try - * this board again for VL. Increment - * 'ioport' past this board. - */ + * Don't clear 'asc_ioport[ioport]'. Try + * this board again for VL. Increment + * 'ioport' past this board. + */ ioport++; goto ioport_try_again; } @@ -4330,12 +4596,54 @@ iop = AscSearchIOPortAddr(iop, asc_bus[bus]); break; + case ASC_IS_PCI: #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI - case ASC_IS_PCI: - if (asc_srch_pci_dev(&pciDevice) != PCI_DEVICE_FOUND) { + if (pci_init_search == 0) { + int i, j; + + pci_init_search = 1; + + /* Find all PCI cards. */ + while (asc_srch_pci_dev(&pciDevice) == PCI_DEVICE_FOUND) { + pci_device[pci_card_cnt_max++] = pciDevice; + } + + /* + * Sort PCI cards in ascending order by PCI Bus, Slot, + * and Device Number. + */ + for (i = 0; i < pci_card_cnt_max - 1; i++) + { + for (j = i + 1; j < pci_card_cnt_max; j++) { + if ((pci_device[j].busNumber < + pci_device[i].busNumber) || + ((pci_device[j].busNumber == + pci_device[i].busNumber) && + (pci_device[j].slotNumber < + pci_device[i].slotNumber)) || + ((pci_device[j].busNumber == + pci_device[i].busNumber) && + (pci_device[j].slotNumber == + pci_device[i].slotNumber) && + (pci_device[j].devFunc < + pci_device[i].devFunc))) { + pciDevice = pci_device[i]; + pci_device[i] = pci_device[j]; + pci_device[j] = pciDevice; + } + } + } + + pci_card_cnt = 0; + } else { + pci_card_cnt++; + } + + if (pci_card_cnt == pci_card_cnt_max) { iop = 0; } else { + pciDevice = pci_device[pci_card_cnt]; ASC_DBG2(2, "advansys_detect: slotFound %d, busNumber %d\n", pciDevice.slotFound, pciDevice.busNumber); @@ -4351,31 +4659,69 @@ #endif /* ASC_CONFIG_PCI */ #else /* version >= v2.1.93 */ #ifdef CONFIG_PCI - case ASC_IS_PCI: - while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) { - if ((pci_devp = pci_find_device(ASC_PCI_VENDORID, - pci_device_id[pci_device_id_cnt], pci_devp)) == NULL) { - pci_device_id_cnt++; - } else { - break; + if (pci_init_search == 0) { + int i, j; + + pci_init_search = 1; + + /* Find all PCI cards. */ + while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) { + if ((pci_devp = pci_find_device(ASC_PCI_VENDORID, + pci_device_id[pci_device_id_cnt], pci_devp)) == + NULL) { + pci_device_id_cnt++; + } else { + pci_devicep[pci_card_cnt_max++] = pci_devp; + } + } + + /* + * Sort PCI cards in ascending order by PCI Bus, Slot, + * and Device Number. + */ + for (i = 0; i < pci_card_cnt_max - 1; i++) + { + for (j = i + 1; j < pci_card_cnt_max; j++) { + if ((pci_devicep[j]->bus->number < + pci_devicep[i]->bus->number) || + ((pci_devicep[j]->bus->number == + pci_devicep[i]->bus->number) && + (pci_devicep[j]->devfn < + pci_devicep[i]->devfn))) { + pci_devp = pci_devicep[i]; + pci_devicep[i] = pci_devicep[j]; + pci_devicep[j] = pci_devp; + } + } } + + pci_card_cnt = 0; + } else { + pci_card_cnt++; } - if (pci_devp == NULL) { + + if (pci_card_cnt == pci_card_cnt_max) { iop = 0; } else { + pci_devp = pci_devicep[pci_card_cnt]; + ASC_DBG2(2, "advansys_detect: devfn %d, bus number %d\n", pci_devp->devfn, pci_devp->bus->number); - iop = pci_devp->resource[0].start; +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13) + iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK; +#else /* version >= v2.3.13 */ + iop = pci_devp->resource[1].start & PCI_IOADDRESS_MASK; +#endif /* version >= v2.3.13 */ ASC_DBG2(1, "advansys_detect: vendorID %X, deviceID %X\n", pci_devp->vendor, pci_devp->device); ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n", iop, pci_devp->irq); } - break; #endif /* CONFIG_PCI */ #endif /* version >= v2.1.93 */ + break; default: ASC_PRINT1("advansys_detect: unknown bus type: %d\n", @@ -4418,14 +4764,18 @@ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI if (asc_bus[bus] == ASC_IS_PCI && - pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) { + (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300 || + pciConfig.deviceID == ASC_PCI_DEVICE_ID_2500)) + { boardp->flags |= ASC_IS_WIDE_BOARD; } #endif /* ASC_CONFIG_PCI */ #else /* version >= v2.1.93 */ #ifdef CONFIG_PCI if (asc_bus[bus] == ASC_IS_PCI && - pci_devp->device == ASC_PCI_DEVICE_ID_2300) { + (pci_devp->device == ASC_PCI_DEVICE_ID_2300 || + pci_devp->device == ASC_PCI_DEVICE_ID_2500)) + { boardp->flags |= ASC_IS_WIDE_BOARD; } #endif /* CONFIG_PCI */ @@ -4445,7 +4795,34 @@ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; adv_dvc_varp->drv_ptr = (ulong) boardp; adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg; - adv_dvc_varp->isr_callback = (Ptr2Func) adv_isr_callback; + adv_dvc_varp->isr_callback = adv_isr_callback; + adv_dvc_varp->async_callback = adv_async_callback; + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) +#ifdef ASC_CONFIG_PCI + if (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) + { + ASC_DBG(1, "advansys_detect: ASC-3550\n"); + adv_dvc_varp->chip_type = ADV_CHIP_ASC3550; + } else + { + ASC_DBG(1, "advansys_detect: ASC-38C0800\n"); + adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800; + } +#endif /* ASC_CONFIG_PCI */ +#else /* version >= v2.1.93 */ +#ifdef CONFIG_PCI + if (pci_devp->device == ASC_PCI_DEVICE_ID_2300) + { + ASC_DBG(1, "advansys_detect: ASC-3550\n"); + adv_dvc_varp->chip_type = ADV_CHIP_ASC3550; + } else + { + ASC_DBG(1, "advansys_detect: ASC-38C0800\n"); + adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800; + } +#endif /* CONFIG_PCI */ +#endif /* version >= v2.1.93 */ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) adv_dvc_varp->iop_base = iop; @@ -4461,39 +4838,61 @@ * PCI register base address will not cross a page * boundary. */ + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + iolen = ADV_3550_IOLEN; + } else { + iolen = ADV_38C0800_IOLEN; + } #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI pci_memory_address = pciConfig.baseAddress[1]; + ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n", + pci_memory_address); if ((boardp->ioremap_addr = ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) { ASC_PRINT3( "advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n", - boardp->id, pci_memory_address, ADV_CONDOR_IOLEN); + boardp->id, pci_memory_address, iolen); scsi_unregister(shp); asc_board_count--; continue; } + ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n", + (ulong) boardp->ioremap_addr); adv_dvc_varp->iop_base = (AdvPortAddr) (boardp->ioremap_addr + (pci_memory_address - (pci_memory_address & PAGE_MASK))); + ASC_DBG1(1, "advansys_detect: iop_base: %lx\n", + adv_dvc_varp->iop_base); #endif /* ASC_CONFIG_PCI */ #else /* version >= v2.1.93 */ #ifdef CONFIG_PCI +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13) + pci_memory_address = pci_devp->base_address[1]; +#else /* version >= v2.3.13 */ pci_memory_address = pci_devp->resource[1].start; +#endif /* version >= v2.3.13 */ + ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n", + pci_memory_address); if ((boardp->ioremap_addr = ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) { ASC_PRINT3( "advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n", - boardp->id, pci_memory_address, ADV_CONDOR_IOLEN); + boardp->id, pci_memory_address, iolen); scsi_unregister(shp); asc_board_count--; continue; } + ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n", + (ulong) boardp->ioremap_addr); adv_dvc_varp->iop_base = (AdvPortAddr) (boardp->ioremap_addr + (pci_memory_address - (pci_memory_address & PAGE_MASK))); + ASC_DBG1(1, "advansys_detect: iop_base: %lx\n", + adv_dvc_varp->iop_base); #endif /* CONFIG_PCI */ #endif /* version >= v2.1.93 */ #endif /* version >= v1,3,0 */ @@ -4505,6 +4904,9 @@ * displayed. */ boardp->ioport = iop; + + ASC_DBG2(1, "iopb_chip_id_1 %x, iopw_chip_id_0 %x\n", + (ushort) inp(iop + 1), (ushort) inpw(iop)); } #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) @@ -4586,9 +4988,9 @@ shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine; adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; adv_dvc_varp->cfg->pci_slot_info = - ASC_PCI_MKID(pciDevice.busNumber, - pciDevice.slotFound, - pciDevice.devFunc); + ASC_PCI_MKID(pciDevice.busNumber, + pciDevice.slotFound, + pciDevice.devFunc); shp->unchecked_isa_dma = FALSE; share_irq = TRUE; #endif /* ASC_CONFIG_PCI */ @@ -4597,9 +4999,9 @@ shp->irq = adv_dvc_varp->irq_no = pci_devp->irq; adv_dvc_varp->cfg->pci_device_id = pci_devp->device; adv_dvc_varp->cfg->pci_slot_info = - ASC_PCI_MKID(pci_devp->bus->number, - PCI_SLOT(pci_devp->devfn), - PCI_FUNC(pci_devp->devfn)); + ASC_PCI_MKID(pci_devp->bus->number, + PCI_SLOT(pci_devp->devfn), + PCI_FUNC(pci_devp->devfn)); shp->unchecked_isa_dma = FALSE; share_irq = TRUE; #endif /* CONFIG_PCI */ @@ -4616,7 +5018,7 @@ * longer be used. If the bus_type field must be * referenced only use the bit-wise AND operator "&". */ - ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n"); + ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n"); switch(ret = AscInitGetConfig(asc_dvc_varp)) { case 0: /* No error */ break; @@ -4776,30 +5178,62 @@ shp->irq = asc_dvc_varp->irq_no; } } else { - - ADVEEP_CONFIG *ep; + ADVEEP_3550_CONFIG *ep_3550; + ADVEEP_38C0800_CONFIG *ep_38C0800; /* * Save Wide EEP Configuration Information. */ - ep = &boardp->eep_config.adv_eep; - - ep->adapter_scsi_id = adv_dvc_varp->chip_scsi_id; - ep->max_host_qng = adv_dvc_varp->max_host_qng; - ep->max_dvc_qng = adv_dvc_varp->max_dvc_qng; - ep->termination = adv_dvc_varp->cfg->termination; - ep->disc_enable = adv_dvc_varp->cfg->disc_enable; - ep->bios_ctrl = adv_dvc_varp->bios_ctrl; - ep->wdtr_able = adv_dvc_varp->wdtr_able; - ep->sdtr_able = adv_dvc_varp->sdtr_able; - ep->ultra_able = adv_dvc_varp->ultra_able; - ep->tagqng_able = adv_dvc_varp->tagqng_able; - ep->start_motor = adv_dvc_varp->start_motor; - ep->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait; - ep->bios_boot_delay = adv_dvc_varp->cfg->bios_boot_wait; - ep->serial_number_word1 = adv_dvc_varp->cfg->serial1; - ep->serial_number_word2 = adv_dvc_varp->cfg->serial2; - ep->serial_number_word3 = adv_dvc_varp->cfg->serial3; + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + ep_3550 = &boardp->eep_config.adv_3550_eep; + + ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id; + ep_3550->max_host_qng = adv_dvc_varp->max_host_qng; + ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng; + ep_3550->termination = adv_dvc_varp->cfg->termination; + ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable; + ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl; + ep_3550->wdtr_able = adv_dvc_varp->wdtr_able; + ep_3550->sdtr_able = adv_dvc_varp->sdtr_able; + ep_3550->ultra_able = adv_dvc_varp->ultra_able; + ep_3550->tagqng_able = adv_dvc_varp->tagqng_able; + ep_3550->start_motor = adv_dvc_varp->start_motor; + ep_3550->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait; + ep_3550->serial_number_word1 = + adv_dvc_varp->cfg->serial1; + ep_3550->serial_number_word2 = + adv_dvc_varp->cfg->serial2; + ep_3550->serial_number_word3 = + adv_dvc_varp->cfg->serial3; + } else + { + ep_38C0800 = &boardp->eep_config.adv_38C0800_eep; + + ep_38C0800->adapter_scsi_id = adv_dvc_varp->chip_scsi_id; + ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng; + ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng; + ep_38C0800->termination_lvd = + adv_dvc_varp->cfg->termination; + ep_38C0800->disc_enable = adv_dvc_varp->cfg->disc_enable; + ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl; + ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able; + ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able; + ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1; + ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2; + ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3; + ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4; + ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able; + ep_38C0800->start_motor = adv_dvc_varp->start_motor; + ep_38C0800->scsi_reset_delay = + adv_dvc_varp->scsi_reset_wait; + ep_38C0800->serial_number_word1 = + adv_dvc_varp->cfg->serial1; + ep_38C0800->serial_number_word2 = + adv_dvc_varp->cfg->serial2; + ep_38C0800->serial_number_word3 = + adv_dvc_varp->cfg->serial3; + } /* * Set the adapter's target id bit in the 'init_tidmask' field. @@ -4842,7 +5276,7 @@ * Memory Mapped I/O. */ shp->io_port = iop; - shp->n_io_port = ADV_CONDOR_IOLEN; + shp->n_io_port = iolen; shp->this_id = adv_dvc_varp->chip_scsi_id; @@ -5065,18 +5499,31 @@ warn_code, err_code); } } else { + ADV_CARR_T *carrp; int req_cnt; adv_req_t *reqp = NULL; - int sg_cnt; + int sg_cnt = 0; adv_sgblk_t *sgp = NULL; #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) + carrp = (ADV_CARR_T *) &adv_carr_buf[0]; req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t); sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t); reqp = (adv_req_t *) &adv_req_buf[0]; sgp = (adv_sgblk_t *) &adv_sgblk_buf[0]; #else /* version >= v1.3.0 */ /* + * Allocate buffer carrier structures. + */ + carrp = + (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC); + ASC_DBG1(1, "advansys_detect: carrp %x\n", (unsigned) carrp); + + if (carrp == NULL) { + goto kmalloc_error; + } + + /* * Allocate up to 'max_host_qng' request structures for * the Wide board. */ @@ -5094,6 +5541,10 @@ break; } } + if (reqp == NULL) + { + goto kmalloc_error; + } /* * Allocate up to ADV_TOT_SG_LIST request structures for @@ -5112,19 +5563,27 @@ break; } } -#endif /* version >= v1.3.0 */ /* * If no request structures or scatter-gather structures could * be allocated, then return an error. Otherwise continue with * initialization. */ - if (reqp == NULL) { + kmalloc_error: + if (carrp == NULL) + { + ASC_PRINT1( +"advansys_detect: board %d: error: failed to kmalloc() carrier buffer.\n", + boardp->id); + err_code = ADV_ERROR; + } else if (reqp == NULL) { + kfree(carrp); ASC_PRINT1( "advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n", boardp->id); err_code = ADV_ERROR; } else if (sgp == NULL) { + kfree(carrp); kfree(reqp); ASC_PRINT1( "advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffer.\n", @@ -5132,6 +5591,9 @@ err_code = ADV_ERROR; } else { + /* Save carrier buffer pointer. */ + boardp->orig_carrp = carrp; + /* * Save original pointer for kfree() in case the * driver is built as a module and can be unloaded. @@ -5139,6 +5601,15 @@ boardp->orig_reqp = reqp; /* + * Save original pointer for kfree() in case the + * driver is built as a module and can be unloaded. + */ + boardp->orig_sgblkp = sgp; +#endif /* version >= v1.3.0 */ + + adv_dvc_varp->carrier_buf = carrp; + + /* * Point 'adv_reqp' to the request structures and * link them together. */ @@ -5150,12 +5621,6 @@ boardp->adv_reqp = &reqp[0]; /* - * Save original pointer for kfree() in case the - * driver is built as a module and can be unloaded. - */ - boardp->orig_sgblkp = sgp; - - /* * Point 'adv_sgblkp' to the request structures and * link them together. */ @@ -5166,24 +5631,37 @@ } boardp->adv_sgblkp = &sgp[0]; - ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n"); - warn_code = AdvInitAsc3550Driver(adv_dvc_varp); + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + ASC_DBG(2, + "advansys_detect: AdvInitAsc3550Driver()\n"); + warn_code = AdvInitAsc3550Driver(adv_dvc_varp); + } else { + ASC_DBG(2, + "advansys_detect: AdvInitAsc38C0800Driver()\n"); + warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp); + } err_code = adv_dvc_varp->err_code; if (warn_code || err_code) { ASC_PRINT3( -"AdvInitAsc3550Driver: board %d: error: warn %x, error %x\n", +"AdvInitAsc3550/38C0800Driver: board %d: error: warn %x, error %x\n", boardp->id, warn_code, adv_dvc_varp->err_code); } +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) } +#endif /* version >= v1,3,0 */ } if (err_code != 0) { release_region(shp->io_port, shp->n_io_port); - if (ASC_WIDE_BOARD(boardp)) { #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + if (ASC_WIDE_BOARD(boardp)) { iounmap(boardp->ioremap_addr); -#endif /* version >= v1,3,0 */ + if (boardp->orig_carrp) { + kfree(boardp->orig_carrp); + boardp->orig_carrp = NULL; + } if (boardp->orig_reqp) { kfree(boardp->orig_reqp); boardp->orig_reqp = boardp->adv_reqp = NULL; @@ -5193,6 +5671,7 @@ boardp->orig_sgblkp = boardp->adv_sgblkp = NULL; } } +#endif /* version >= v1,3,0 */ if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } @@ -5237,10 +5716,13 @@ free_dma(shp->dma_channel); } release_region(shp->io_port, shp->n_io_port); - if (ASC_WIDE_BOARD(boardp)) { #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + if (ASC_WIDE_BOARD(boardp)) { iounmap(boardp->ioremap_addr); -#endif /* version >= v1,3,0 */ + if (boardp->orig_carrp) { + kfree(boardp->orig_carrp); + boardp->orig_carrp = NULL; + } if (boardp->orig_reqp) { kfree(boardp->orig_reqp); boardp->orig_reqp = boardp->adv_reqp = NULL; @@ -5250,7 +5732,6 @@ boardp->orig_sgblkp = boardp->adv_sgblkp = NULL; } } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) ASC_ASSERT(boardp->prtbuf != NULL); kfree(boardp->prtbuf); #endif /* version >= v1.3.0 */ @@ -5276,6 +5757,8 @@ ASC_DVC_VAR *asc_dvc_varp; ADV_DVC_VAR *adv_dvc_varp; char *busname; + int iolen; + char *widename = NULL; boardp = ASC_BOARDP(shp); if (ASC_NARROW_BOARD(boardp)) { @@ -5342,21 +5825,31 @@ * I/O address is displayed through the driver /proc file. */ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + iolen = ADV_3550_IOLEN; + widename = "Ultra-Wide"; + } else { + iolen = ADV_38C0800_IOLEN; + widename = "Ultra2-Wide"; + } if (boardp->bios_signature == 0x55AA) { sprintf(info, -"AdvanSys SCSI %s: PCI Ultra-Wide: BIOS %X/%X, IO %X/%X, IRQ %u", +"AdvanSys SCSI %s: PCI %s: BIOS %X/%X, IO %X/%X, IRQ %u", ASC_VERSION, + widename, boardp->bios_codeseg << 4, boardp->bios_codelen > 0 ? (boardp->bios_codelen << 9) - 1 : 0, - (unsigned) boardp->ioport, ADV_CONDOR_IOLEN - 1, + (unsigned) boardp->ioport, iolen - 1, shp->irq); } else { sprintf(info, -"AdvanSys SCSI %s: PCI Ultra-Wide: IO %X/%X, IRQ %u", +"AdvanSys SCSI %s: PCI %s: IO %X/%X, IRQ %u", ASC_VERSION, + widename, (unsigned) boardp->ioport, - (ADV_CONDOR_IOLEN - 1), + (iolen - 1), shp->irq); } } @@ -5579,7 +6072,7 @@ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; scp->result = HOST_BYTE(DID_ABORT); - /* sti(); - FIXME!!! Enable interrupts for AscAbortSRB() must be careful about io_lock. */ + /* sti(); XXX */ /* Enable interrupts for AscAbortSRB(). */ ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n", (unsigned) scp); switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) { @@ -5607,22 +6100,23 @@ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; scp->result = HOST_BYTE(DID_ABORT); - ASC_DBG1(1, "advansys_abort: before AdvAbortSRB(), scp %x\n", + ASC_DBG1(1, "advansys_abort: before AdvAbortQueue(), scp %x\n", (unsigned) scp); - switch (AdvAbortSRB(adv_dvc_varp, (ulong) scp)) { +#if 0 /* XXX */ + switch (AdvAbortQueue(adv_dvc_varp, (ulong) XXX)) { case ASC_TRUE: /* asc_isr_callback() will be called */ - ASC_DBG(1, "advansys_abort: AdvAbortSRB() TRUE\n"); + ASC_DBG(1, "advansys_abort: AdvAbortQueue() TRUE\n"); ret = SCSI_ABORT_PENDING; break; case ASC_FALSE: /* Request has apparently already completed. */ - ASC_DBG(1, "advansys_abort: AdvAbortSRB() FALSE\n"); + ASC_DBG(1, "advansys_abort: AdvAbortQueue() FALSE\n"); ret = SCSI_ABORT_NOT_RUNNING; break; case ASC_ERROR: default: - ASC_DBG(1, "advansys_abort: AdvAbortSRB() ERROR\n"); + ASC_DBG(1, "advansys_abort: AdvAbortQueue() ERROR\n"); ret = SCSI_ABORT_ERROR; break; } @@ -5631,6 +6125,10 @@ * been processed by calling AdvISR(). */ (void) AdvISR(adv_dvc_varp); +#else /* XXX */ + (void) AdvResetChipAndSB(adv_dvc_varp); + ret = SCSI_ABORT_SUCCESS; +#endif /* XXX */ } /* @@ -5644,7 +6142,6 @@ scp_found = asc_rmqueue(&boardp->done, scp); ASC_ASSERT(scp_found == ASC_TRUE); } - } else { /* * The command was not found on the active or waiting queues. @@ -5786,8 +6283,13 @@ } scp->result = HOST_BYTE(DID_ERROR); ret = SCSI_RESET_ERROR; +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0) } else if (time_after_eq(jiffies, boardp->last_reset) && time_before(jiffies, boardp->last_reset + (10 * HZ))) { +#else /* version < v2.1.0 */ + } else if (jiffies >= boardp->last_reset && + jiffies < (boardp->last_reset + (10 * HZ))) { +#endif /* version < v2.1.0 */ /* * Don't allow a reset to be attempted within 10 seconds * of the last reset. @@ -5849,9 +6351,9 @@ * Reset the target's SCSI bus. */ ASC_DBG(1, "advansys_reset: before AscResetSB()\n"); - /* sti(); FIXME!!! Enable interrupts for AscResetSB(). */ + /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */ status = AscResetSB(asc_dvc_varp); - /* cli(); FIXME!!! */ + /* cli(); XXX */ switch (status) { case ASC_TRUE: ASC_DBG(1, "advansys_reset: AscResetSB() success\n"); @@ -5874,9 +6376,9 @@ ASC_DBG1(1, "advansys_reset: before AscResetDevice(), target %d\n", scp->target); - /* sti(); FIXME!!! Enable interrupts for AscResetDevice(). */ + /* sti(); XXX */ /* Enable interrupts for AscResetDevice(). */ status = AscResetDevice(asc_dvc_varp, scp->target); - /* cli(); FIXME!!! */ + /* cli(); XXX */ switch (status) { case ASC_TRUE: @@ -5888,9 +6390,9 @@ default: ASC_DBG(1, "advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n"); - /* sti(); FIXME!!! Enable interrupts for AscResetSB(). */ + /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */ status = AscResetSB(asc_dvc_varp); - /* cli(); */ + /* cli(); XXX */ switch (status) { case ASC_TRUE: ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n"); @@ -5923,15 +6425,16 @@ /* * Reset the target's SCSI bus. */ - ASC_DBG(1, "advansys_reset: before AdvResetSB()\n"); - switch (AdvResetSB(adv_dvc_varp)) { + ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n"); + switch (AdvResetChipAndSB(adv_dvc_varp)) { case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AdvResetSB() success\n"); + ASC_DBG(1, + "advansys_reset: AdvResetChipAndSB() success\n"); ret = SCSI_RESET_SUCCESS; break; case ASC_FALSE: default: - ASC_DBG(1, "advansys_reset: AdvResetSB() failed\n"); + ASC_DBG(1, "advansys_reset: AdvResetChipAndSB() failed\n"); ret = SCSI_RESET_ERROR; break; } @@ -5960,16 +6463,18 @@ case ASC_FALSE: default: ASC_DBG(1, -"advansys_reset: AdvResetDevice() failed; Calling AdvResetSB()\n"); +"advansys_reset: AdvResetDevice() failed; Calling AdvResetChipAndSB()\n"); - switch (AdvResetSB(adv_dvc_varp)) { + switch (AdvResetChipAndSB(adv_dvc_varp)) { case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AdvResetSB() TRUE\n"); + ASC_DBG(1, + "advansys_reset: AdvResetChipAndSB() TRUE\n"); ret = SCSI_RESET_SUCCESS; break; case ASC_FALSE: default: - ASC_DBG(1, "advansys_reset: AdvResetSB() ERROR\n"); + ASC_DBG(1, + "advansys_reset: AdvResetChipAndSB() ERROR\n"); ret = SCSI_RESET_ERROR; break; } @@ -6188,8 +6693,10 @@ * ints[2] - second argument * ... */ -void ASC_INIT +ASC_INITFUNC( +void, advansys_setup(char *str, int *ints) +) { int i; @@ -6541,27 +7048,6 @@ */ boardp->reqcnt[scp->target]++; -#if ASC_QUEUE_FLOW_CONTROL - /* - * Conditionally increment the device queue depth. - * - * If no error occurred and there have been 100 consecutive - * successful requests and the current queue depth is less - * than the maximum queue depth, then increment the current - * queue depth. - */ - if (boardp->nerrcnt[scp->target]++ > 100) { - boardp->nerrcnt[scp->target] = 0; - if (device != NULL && - (device->queue_curr_depth < device->queue_depth) && - (!(boardp->queue_full & - ADV_TID_TO_TIDMASK(scp->target)) || - (boardp->queue_full_cnt[scp->target] > - device->queue_curr_depth))) { - device->queue_curr_depth++; - } - } -#endif /* ASC_QUEUE_FLOW_CONTROL */ asc_enqueue(&boardp->active, scp, ASC_BACK); ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); @@ -6569,26 +7055,12 @@ case ASC_BUSY: /* Caller must enqueue request and retry later. */ ASC_STATS(scp->host, exe_busy); -#if ASC_QUEUE_FLOW_CONTROL - /* - * Clear consecutive no error counter and if possible decrement - * queue depth. - */ - boardp->nerrcnt[scp->target] = 0; - if (device != NULL && device->queue_curr_depth > 1) { - device->queue_curr_depth--; - } -#endif /* ASC_QUEUE_FLOW_CONTROL */ break; case ASC_ERROR: ASC_PRINT2( "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n", boardp->id, asc_dvc_varp->err_code); ASC_STATS(scp->host, exe_error); -#if ASC_QUEUE_FLOW_CONTROL - /* Clear consecutive no error counter. */ - boardp->nerrcnt[scp->target] = 0; -#endif /* ASC_QUEUE_FLOW_CONTROL */ scp->result = HOST_BYTE(DID_ERROR); asc_enqueue(&boardp->done, scp, ASC_BACK); break; @@ -6597,10 +7069,6 @@ "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n", boardp->id, asc_dvc_varp->err_code); ASC_STATS(scp->host, exe_unknown); -#if ASC_QUEUE_FLOW_CONTROL - /* Clear consecutive no error counter. */ - boardp->nerrcnt[scp->target] = 0; -#endif /* ASC_QUEUE_FLOW_CONTROL */ scp->result = HOST_BYTE(DID_ERROR); asc_enqueue(&boardp->done, scp, ASC_BACK); break; @@ -6868,7 +7336,6 @@ scsiqp->target_id = scp->target; scsiqp->target_lun = scp->lun; - scsiqp->vsense_addr = (ulong) &scp->sense_buffer[0]; #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) scsiqp->sense_addr = (ulong) &scp->sense_buffer[0]; #else /* version >= v2.0.0 */ @@ -6994,7 +7461,7 @@ ADV_SG_BLOCK *sg_block; /* virtual address of a SG */ ulong sg_block_next_addr; /* block and its next */ ulong sg_block_physical_addr; - int sg_block_index, i; /* how many SG entries */ + int i; struct scatterlist *slp; int sg_elem_cnt; @@ -7013,10 +7480,8 @@ sg_block_physical_addr); scsiqp->sg_real_addr = sg_block_physical_addr; - sg_block_index = 0; do { - sg_block->first_entry_no = sg_block_index; for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) { sg_block->sg_list[i].sg_addr = @@ -7030,21 +7495,19 @@ if (--sg_elem_cnt == 0) { /* last entry, get out */ - scsiqp->sg_entry_cnt = sg_block_index + i + 1; - sg_block->last_entry_no = sg_block_index + i; + sg_block->sg_cnt = i + 1; sg_block->sg_ptr = 0L; /* next link = NULL */ return ADV_SUCCESS; } slp++; } + sg_block->sg_cnt = NO_OF_SG_PER_BLOCK; sg_block_next_addr += sizeof(ADV_SG_BLOCK); sg_block_physical_addr += sizeof(ADV_SG_BLOCK); ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) == sg_block_physical_addr); - sg_block_index += NO_OF_SG_PER_BLOCK; sg_block->sg_ptr = (ADV_SG_BLOCK *) sg_block_physical_addr; - sg_block->last_entry_no = sg_block_index - 1; sg_block = (ADV_SG_BLOCK *) sg_block_next_addr; /* virtual addr */ } while (1); @@ -7270,7 +7733,7 @@ * command that has been completed. * * Note: The adv_req_t request structure and adv_sgblk_t structure, - * if any, * dropped, because a board structure pointer can not be + * if any, are dropped, because a board structure pointer can not be * determined. */ scp = reqp->cmndp; @@ -7443,13 +7906,53 @@ return; } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI /* - * Search for an AdvanSys PCI device in the PCI configuration space. + * adv_async_callback() - Adv Library asynchronous event callback function. */ -STATIC int ASC_INIT -asc_srch_pci_dev(PCI_DEVICE *pciDevice) +STATIC void +adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code) +{ + switch (code) + { + case ADV_ASYNC_SCSI_BUS_RESET_DET: + /* + * The firmware detected a SCSI Bus reset. + */ + ASC_DBG(0, "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n"); + break; + + case ADV_ASYNC_RDMA_FAILURE: + /* + * Handle RDMA failure by resetting the SCSI Bus and + * possibly the chip if it is unresponsive. Log the error + * with a unique code. + */ + ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n"); + AdvResetChipAndSB(adv_dvc_varp); + break; + + case ADV_HOST_SCSI_BUS_RESET: + /* + * Host generated SCSI bus reset occurred. + */ + ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n"); + break; + + default: + ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code); + break; + } +} + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) +#ifdef ASC_CONFIG_PCI +/* + * Search for an AdvanSys PCI device in the PCI configuration space. + */ +ASC_INITFUNC( +STATIC int, +asc_srch_pci_dev(PCI_DEVICE *pciDevice) +) { int ret = PCI_DEVICE_NOT_FOUND; @@ -7486,8 +7989,10 @@ /* * Determine the access method to be used for 'pciDevice'. */ -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, asc_scan_method(void) +) { ushort data; PCI_DATA pciData; @@ -7516,8 +8021,10 @@ * * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND. */ -STATIC int ASC_INIT +ASC_INITFUNC( +STATIC int, asc_pci_find_dev(PCI_DEVICE *pciDevice) +) { PCI_DATA pciData; ushort vendorid, deviceid; @@ -7542,7 +8049,8 @@ ((deviceid == ASC_PCI_DEVICE_ID_1100) || (deviceid == ASC_PCI_DEVICE_ID_1200) || (deviceid == ASC_PCI_DEVICE_ID_1300) || - (deviceid == ASC_PCI_DEVICE_ID_2300))) { + (deviceid == ASC_PCI_DEVICE_ID_2300) || + (deviceid == ASC_PCI_DEVICE_ID_2500))) { pciDevice->slotFound = lslot; ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n"); return PCI_DEVICE_FOUND; @@ -7566,8 +8074,10 @@ /* * Read PCI configuration data into 'pciConfig'. */ -STATIC void ASC_INIT +ASC_INITFUNC( +STATIC void, asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig) +) { PCI_DATA pciData; uchar counter; @@ -7596,8 +8106,10 @@ * * The configuration mechanism is checked for the correct access method. */ -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, asc_get_cfg_word(PCI_DATA *pciData) +) { ushort tmp; ulong address; @@ -7626,7 +8138,7 @@ /* set for type 1 cycle, if needed */ outp(0xCFA, pciData->bus); /* set the function number */ - outp(0xCF8, 0x10 | (pciData->func << 1)) ; + outp(0xCF8, 0x10 | (pciData->func << 1)); /* * Read the configuration space type 2 locations. @@ -7677,8 +8189,10 @@ * * The configuration mechanism is checked for the correct access method. */ -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, asc_get_cfg_byte(PCI_DATA *pciData) +) { uchar tmp; ulong address; @@ -7755,8 +8269,10 @@ /* * Write a byte to the PCI configuration space. */ -STATIC void ASC_INIT +ASC_INITFUNC( +STATIC void, asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data) +) { ulong tmpl; ulong address; @@ -8498,19 +9014,29 @@ STATIC int asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) { - asc_board_t *boardp; - ADV_DVC_VAR *adv_dvc_varp; - int leftlen; - int totlen; - int len; - int i; - char *termstr; - uchar serialstr[13]; - ADVEEP_CONFIG *ep; + asc_board_t *boardp; + ADV_DVC_VAR *adv_dvc_varp; + int leftlen; + int totlen; + int len; + int i; + char *termstr; + uchar serialstr[13]; + ADVEEP_3550_CONFIG *ep_3550 = NULL; + ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL; + ushort word; + ushort *wordp; + ushort sdtr_speed = 0; boardp = ASC_BOARDP(shp); adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; - ep = &boardp->eep_config.adv_eep; + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + ep_3550 = &boardp->eep_config.adv_3550_eep; + } else + { + ep_38C0800 = &boardp->eep_config.adv_38C0800_eep; + } leftlen = cplen; totlen = len = 0; @@ -8519,8 +9045,15 @@ "\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no); ASC_PRT_NEXT(); - if (asc_get_eeprom_string(&ep->serial_number_word1, serialstr) == - ASC_TRUE) { + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + wordp = &ep_3550->serial_number_word1; + } else + { + wordp = &ep_38C0800->serial_number_word1; + } + + if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) { len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr); ASC_PRT_NEXT(); } else { @@ -8529,12 +9062,29 @@ ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + len = asc_prt_line(cp, leftlen, " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", - ep->adapter_scsi_id, ep->max_host_qng, ep->max_dvc_qng); - ASC_PRT_NEXT(); - - switch (ep->termination) { + ep_3550->adapter_scsi_id, ep_3550->max_host_qng, + ep_3550->max_dvc_qng); + ASC_PRT_NEXT(); + } else + { + len = asc_prt_line(cp, leftlen, +" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", + ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng, + ep_38C0800->max_dvc_qng); + ASC_PRT_NEXT(); + } + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + word = ep_3550->termination; + } else + { + word = ep_38C0800->termination_lvd; + } + switch (word) { case 1: termstr = "Low Off/High Off"; break; @@ -8550,10 +9100,19 @@ break; } - len = asc_prt_line(cp, leftlen, + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + len = asc_prt_line(cp, leftlen, " termination: %u (%s), bios_ctrl: %x\n", - ep->termination, termstr, ep->bios_ctrl); - ASC_PRT_NEXT(); + ep_3550->termination, termstr, ep_3550->bios_ctrl); + ASC_PRT_NEXT(); + } else + { + len = asc_prt_line(cp, leftlen, +" termination: %u (%s), bios_ctrl: %x\n", + ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl); + ASC_PRT_NEXT(); + } len = asc_prt_line(cp, leftlen, " Target ID: "); @@ -8565,72 +9124,150 @@ len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + word = ep_3550->disc_enable; + } else + { + word = ep_38C0800->disc_enable; + } len = asc_prt_line(cp, leftlen, " Disconnects: "); ASC_PRT_NEXT(); for (i = 0; i <= ADV_MAX_TID; i++) { len = asc_prt_line(cp, leftlen, " %c", - (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + word = ep_3550->tagqng_able; + } else + { + word = ep_38C0800->tagqng_able; + } len = asc_prt_line(cp, leftlen, " Command Queuing: "); ASC_PRT_NEXT(); for (i = 0; i <= ADV_MAX_TID; i++) { len = asc_prt_line(cp, leftlen, " %c", - (ep->tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + word = ep_3550->start_motor; + } else + { + word = ep_38C0800->start_motor; + } len = asc_prt_line(cp, leftlen, " Start Motor: "); ASC_PRT_NEXT(); for (i = 0; i <= ADV_MAX_TID; i++) { len = asc_prt_line(cp, leftlen, " %c", - (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + len = asc_prt_line(cp, leftlen, " Synchronous Transfer:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (ep->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + len = asc_prt_line(cp, leftlen, " Ultra Transfer: "); ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (ep->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + word = ep_3550->wdtr_able; + } else + { + word = ep_38C0800->wdtr_able; + } len = asc_prt_line(cp, leftlen, " Wide Transfer: "); ASC_PRT_NEXT(); for (i = 0; i <= ADV_MAX_TID; i++) { len = asc_prt_line(cp, leftlen, " %c", - (ep->wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) + { + len = asc_prt_line(cp, leftlen, +" Synchronous Transfer Speed (Mhz):\n "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + char *speed_str; + + if (i == 0) + { + sdtr_speed = adv_dvc_varp->sdtr_speed1; + } else if (i == 4) + { + sdtr_speed = adv_dvc_varp->sdtr_speed2; + } else if (i == 8) + { + sdtr_speed = adv_dvc_varp->sdtr_speed3; + } else if (i == 12) + { + sdtr_speed = adv_dvc_varp->sdtr_speed4; + } + switch (sdtr_speed & ADV_MAX_TID) + { + case 0: speed_str = "Off"; break; + case 1: speed_str = " 5"; break; + case 2: speed_str = " 10"; break; + case 3: speed_str = " 20"; break; + case 4: speed_str = " 40"; break; + case 5: speed_str = " 80"; break; + default: speed_str = "Unk"; break; + } + len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str); + ASC_PRT_NEXT(); + if (i == 7) + { + len = asc_prt_line(cp, leftlen, "\n "); + ASC_PRT_NEXT(); + } + sdtr_speed >>= 4; + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + } + return totlen; } @@ -8728,46 +9365,6 @@ } #endif /* version >= v1.3.89 */ -#if ASC_QUEUE_FLOW_CONTROL - if (ASC_NARROW_BOARD(boardp)) { - len = asc_prt_line(cp, leftlen, " queue_curr_depth:"); - ASC_PRT_NEXT(); - /* Use ASC_MAX_TID for Narrow Board. */ - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - if (boardp->device[i] == NULL) { - continue; - } - len = asc_prt_line(cp, leftlen, " %d:%d", - i, boardp->device[i]->queue_curr_depth); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " queue_count:"); - ASC_PRT_NEXT(); - /* Use ASC_MAX_TID for Narrow Board. */ - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - if (boardp->device[i] == NULL) { - continue; - } - len = asc_prt_line(cp, leftlen, " %d:%d", - i, boardp->device[i]->queue_count); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - } -#endif /* ASC_QUEUE_FLOW_CONTROL */ - return totlen; } @@ -8786,16 +9383,19 @@ asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen) { asc_board_t *boardp; + int chip_scsi_id; int leftlen; int totlen; int len; ASC_DVC_VAR *v; ASC_DVC_CFG *c; int i; + int renegotiate = 0; boardp = ASC_BOARDP(shp); v = &boardp->dvc_var.asc_dvc_var; c = &boardp->dvc_cfg.asc_dvc_cfg; + chip_scsi_id = c->chip_scsi_id; leftlen = cplen; totlen = len = 0; @@ -8824,11 +9424,11 @@ " Command Queuing:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } - len = asc_prt_line(cp, leftlen, " %d:%c", + len = asc_prt_line(cp, leftlen, " %X:%c", i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } @@ -8840,11 +9440,11 @@ " Command Queue Pending:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } - len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]); + len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -8855,11 +9455,11 @@ " Command Queue Limit:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } - len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]); + len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -8870,15 +9470,15 @@ " Command Queue Full:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) { - len = asc_prt_line(cp, leftlen, " %d:Y-%d", + len = asc_prt_line(cp, leftlen, " %X:Y-%d", i, boardp->queue_full_cnt[i]); } else { - len = asc_prt_line(cp, leftlen, " %d:N", i); + len = asc_prt_line(cp, leftlen, " %X:N", i); } ASC_PRT_NEXT(); } @@ -8889,11 +9489,11 @@ " Synchronous Transfer:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } - len = asc_prt_line(cp, leftlen, " %d:%c", + len = asc_prt_line(cp, leftlen, " %X:%c", i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } @@ -8903,26 +9503,50 @@ for (i = 0; i <= ASC_MAX_TID; i++) { uchar syn_period_ix; - if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) || + ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } + + len = asc_prt_line(cp, leftlen, " %X:", i); + ASC_PRT_NEXT(); + + if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) + { + len = asc_prt_line(cp, leftlen, " Asynchronous"); + ASC_PRT_NEXT(); + } else + { + syn_period_ix = + (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1); + + len = asc_prt_line(cp, leftlen, + " Transfer Period Factor: %d (%d.%d Mhz),", + v->sdtr_period_tbl[syn_period_ix], + 250 / v->sdtr_period_tbl[syn_period_ix], + ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix])); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d", + boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET); + ASC_PRT_NEXT(); + } + if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { - continue; + len = asc_prt_line(cp, leftlen, "*\n"); + renegotiate = 1; + } else + { + len = asc_prt_line(cp, leftlen, "\n"); } - syn_period_ix = (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1); - len = asc_prt_line(cp, leftlen, " %d:", i); ASC_PRT_NEXT(); + } + if (renegotiate) + { len = asc_prt_line(cp, leftlen, - " Transfer Period Factor: %d (%d.%d Mhz),", - v->sdtr_period_tbl[syn_period_ix], - 250 / v->sdtr_period_tbl[syn_period_ix], - ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix])); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n", - boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET); + " * = Re-negotiation pending before next command.\n"); ASC_PRT_NEXT(); } @@ -8954,8 +9578,11 @@ ushort chip_scsi_id; ushort lramword; uchar lrambyte; - ushort sdtr_able; - ushort period; + ushort tagqng_able; + ushort sdtr_able, wdtr_able; + ushort wdtr_done, sdtr_done; + ushort period = 0; + int renegotiate = 0; boardp = ASC_BOARDP(shp); v = &boardp->dvc_var.adv_dvc_var; @@ -8972,10 +9599,10 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" iop_base %lx, cable_detect: %X, err_code %u, idle_cmd_done %u\n", +" iop_base %lx, cable_detect: %X, err_code %u\n", v->iop_base, AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT, - v->err_code, v->idle_cmd_done); + v->err_code); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, @@ -8983,7 +9610,7 @@ c->chip_version, c->lib_version, c->mcode_date, c->mcode_version); ASC_PRT_NEXT(); - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, lramword); + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); len = asc_prt_line(cp, leftlen, " Queuing Enabled:"); ASC_PRT_NEXT(); @@ -8994,7 +9621,7 @@ } len = asc_prt_line(cp, leftlen, " %X:%c", - i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + i, (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -9034,7 +9661,7 @@ len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, lramword); + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); len = asc_prt_line(cp, leftlen, " Wide Enabled:"); ASC_PRT_NEXT(); @@ -9045,12 +9672,13 @@ } len = asc_prt_line(cp, leftlen, " %X:%c", - i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + i, (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); + AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done); len = asc_prt_line(cp, leftlen, " Transfer Bit Width:"); ASC_PRT_NEXT(); @@ -9062,9 +9690,17 @@ AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i), lramword); + len = asc_prt_line(cp, leftlen, " %X:%d", i, (lramword & 0x8000) ? 16 : 8); ASC_PRT_NEXT(); + + if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) && + (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { + len = asc_prt_line(cp, leftlen, "*"); + ASC_PRT_NEXT(); + renegotiate = 1; + } } len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); @@ -9086,6 +9722,7 @@ len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); + AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done); for (i = 0; i <= ADV_MAX_TID; i++) { AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i), @@ -9093,23 +9730,67 @@ lramword &= ~0x8000; if ((chip_scsi_id == i) || - ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0) || - (lramword == 0)) { + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) || + ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %X:", i); ASC_PRT_NEXT(); - - period = (((lramword >> 8) * 25) + 50)/4; - len = asc_prt_line(cp, leftlen, - " Transfer Period Factor: %d (%d.%d Mhz),", - period, 250/period, ASC_TENTHS(250, period)); + if ((lramword & 0x1F) == 0) /* Check for REQ/ACK Offset 0. */ + { + len = asc_prt_line(cp, leftlen, " Asynchronous"); + ASC_PRT_NEXT(); + } else + { + len = asc_prt_line(cp, leftlen, " Transfer Period Factor: "); + ASC_PRT_NEXT(); + + if ((lramword & 0x1F00) == 0x1100) /* 80 Mhz */ + { + len = asc_prt_line(cp, leftlen, "9 (80.0 Mhz),"); + ASC_PRT_NEXT(); + } else if ((lramword & 0x1F00) == 0x1000) /* 40 Mhz */ + { + len = asc_prt_line(cp, leftlen, "10 (40.0 Mhz),"); + ASC_PRT_NEXT(); + } else /* 20 Mhz or below. */ + { + period = (((lramword >> 8) * 25) + 50)/4; + + if (period == 0) /* Should never happen. */ + { + len = asc_prt_line(cp, leftlen, "%d (? Mhz), "); + ASC_PRT_NEXT(); + } else + { + len = asc_prt_line(cp, leftlen, + "%d (%d.%d Mhz),", + period, 250/period, ASC_TENTHS(250, period)); + ASC_PRT_NEXT(); + } + } + + len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d", + lramword & 0x1F); + ASC_PRT_NEXT(); + } + + if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { + len = asc_prt_line(cp, leftlen, "*\n"); + renegotiate = 1; + } else + { + len = asc_prt_line(cp, leftlen, "\n"); + } ASC_PRT_NEXT(); + } - len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n", - lramword & 0x1F); + if (renegotiate) + { + len = asc_prt_line(cp, leftlen, + " * = Re-negotiation pending before next command.\n"); ASC_PRT_NEXT(); } @@ -9164,7 +9845,7 @@ { va_list args; int ret; - char s[ASC_PRTLINE_SIZE]; + char s[ASC_PRTLINE_SIZE]; va_start(args, fmt); ret = vsprintf(s, fmt, args); @@ -9195,8 +9876,18 @@ STATIC void DvcSleepMilliSecond(ulong n) { +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) + ulong i; +#endif /* version < v2.1.0 */ + ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0) mdelay(n); +#else /* version < v2.1.0 */ + for (i = 0; i < n; i++) { + udelay(1000); + } +#endif /* version < v2.1.0 */ } STATIC int @@ -9346,10 +10037,12 @@ /* * Read a PCI configuration byte. */ -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, DvcReadPCIConfigByte( ASC_DVC_VAR asc_ptr_type *asc_dvc, ushort offset) +) { #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI @@ -9381,11 +10074,13 @@ /* * Write a PCI configuration byte. */ -STATIC void ASC_INIT +ASC_INITFUNC( +STATIC void, DvcWritePCIConfigByte( ASC_DVC_VAR asc_ptr_type *asc_dvc, ushort offset, uchar byte_data) +) { #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI @@ -9412,14 +10107,16 @@ * Return the BIOS address of the adapter at the specified * I/O port and with the specified bus type. */ -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscGetChipBiosAddress( PortAddr iop_base, ushort bus_type ) +) { - ushort cfg_lsw ; - ushort bios_addr ; + ushort cfg_lsw; + ushort bios_addr; /* * The PCI BIOS is re-located by the motherboard BIOS. Because @@ -9433,14 +10130,14 @@ if((bus_type & ASC_IS_EISA) != 0) { - cfg_lsw = AscGetEisaChipCfg(iop_base) ; - cfg_lsw &= 0x000F ; + cfg_lsw = AscGetEisaChipCfg(iop_base); + cfg_lsw &= 0x000F; bios_addr = (ushort)(ASC_BIOS_MIN_ADDR + - (cfg_lsw * ASC_BIOS_BANK_SIZE)) ; - return(bios_addr) ; + (cfg_lsw * ASC_BIOS_BANK_SIZE)); + return(bios_addr); }/* if */ - cfg_lsw = AscGetChipCfgLsw(iop_base) ; + cfg_lsw = AscGetChipCfgLsw(iop_base); /* * ISA PnP uses the top bit as the 32K BIOS flag @@ -9451,8 +10148,8 @@ }/* if */ bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) + - ASC_BIOS_MIN_ADDR) ; - return(bios_addr) ; + ASC_BIOS_MIN_ADDR); + return(bios_addr); } @@ -9493,10 +10190,12 @@ /* * Read a PCI configuration byte. */ -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, DvcAdvReadPCIConfigByte( ADV_DVC_VAR *asc_dvc, ushort offset) +) { #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI @@ -9528,11 +10227,13 @@ /* * Write a PCI configuration byte. */ -STATIC void ASC_INIT +ASC_INITFUNC( +STATIC void, DvcAdvWritePCIConfigByte( ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data) +) { #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) #ifdef ASC_CONFIG_PCI @@ -9743,12 +10444,13 @@ (unsigned) s->hostt, (unsigned) s->block); printk( -" wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n", - s->wish_block, (unsigned) s->base, s->io_port, s->n_io_port, - s->irq, s->dma_channel); +" wish_block %d, base %lu, io_port %lu, n_io_port %u, irq %d,\n", + s->wish_block, (ulong) s->base, (ulong) s->io_port, s->n_io_port, + s->irq); printk( -" this_id %d, can_queue %d,\n", s->this_id, s->can_queue); +" dma_channel %d, this_id %d, can_queue %d,\n", + s->dma_channel, s->this_id, s->can_queue); printk( " cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n", @@ -9966,15 +10668,23 @@ (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no); printk( -" max_host_qng 0x%x, cur_host_qng 0x%x, max_dvc_qng 0x%x\n", - (unsigned) h->max_host_qng, (unsigned) h->cur_host_qng, - (unsigned) h->max_dvc_qng); +" max_host_qng %x, max_dvc_qng %x, carr_freelist %lxn\n", + (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng, + (ulong) h->carr_freelist); + printk( -" no_scam 0x%x, tagqng_able 0x%x, chip_scsi_id 0x%x, cfg 0x%lx\n", - (unsigned) h->no_scam, (unsigned) h->tagqng_able, - (unsigned) h->chip_scsi_id, (ulong) h->cfg); +" icq_sp %lx, irq_sp %lx\n", + (ulong) h->icq_sp, + (ulong) h->irq_sp); + + printk( +" no_scam 0x%x, tagqng_able 0x%x\n", + (unsigned) h->no_scam, (unsigned) h->tagqng_able); + printk( +" chip_scsi_id 0x%x, cfg %lx\n", + (unsigned) h->chip_scsi_id, (ulong) h->cfg); } /* @@ -10012,7 +10722,7 @@ STATIC void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q) { - int i; + int sg_blk_cnt; struct asc_sg_block *sg_ptr; printk("ADV_SCSI_REQ_Q at addr %x\n", (unsigned) q); @@ -10025,6 +10735,10 @@ q->cntl, q->data_addr, q->vdata_addr); printk( +" cntl 0x%x, data_addr %lx, vdata_addr %lx\n", + q->cntl, q->data_addr, q->vdata_addr); + + printk( " data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", q->data_cnt, q->sense_addr, q->sense_len); @@ -10033,63 +10747,58 @@ q->cdb_len, q->done_status, q->host_status, q->scsi_status); printk( -" vsense_addr 0x%lx, scsiq_ptr 0x%lx, ux_wk_data_cnt %lu\n", - (ulong) q->vsense_addr, (ulong) q->scsiq_ptr, - (ulong) q->ux_wk_data_cnt); - - printk( -" sg_list_ptr 0x%lx, sg_real_addr 0x%lx, sg_entry_cnt %u\n", - (ulong) q->sg_list_ptr, (ulong) q->sg_real_addr, q->sg_entry_cnt); +" sg_working_ix %x, sg_working_data_cnt %lx, reserved %u\n", + q->sg_working_ix, q->sg_working_data_cnt, q->reserved); printk( -" ux_sg_ix %u, orig_sense_len %u\n", - q->ux_sg_ix, q->orig_sense_len); +" scsiq_rptr %lx, sg_real_addr %lx, sg_list_ptr %lx\n", + q->scsiq_rptr, q->sg_real_addr, (ulong) q->sg_list_ptr); /* Display the request's ADV_SG_BLOCK structures. */ - for (sg_ptr = q->sg_list_ptr, i = 0; sg_ptr != NULL; - sg_ptr = sg_ptr->sg_ptr, i++) { - /* - * 'sg_ptr' is a physical address. Convert it to a virtual - * address by indexing 'i' into the virtual address array - * 'sg_list_ptr'. - * - * At the end of the each iteration of the loop 'sg_ptr' is - * converted back into a physical address by setting 'sg_ptr' - * to the next pointer 'sg_ptr->sg_ptr'. - */ - sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[i]); - asc_prt_adv_sgblock(i, sg_ptr); - } -} - -/* - * asc_prt_adv_sgblock() + if (q->sg_list_ptr != NULL) + { + sg_blk_cnt = 0; + while (1) { + /* + * 'sg_ptr' is a physical address. Convert it to a virtual + * address by indexing 'sg_blk_cnt' into the virtual address + * array 'sg_list_ptr'. + * + * XXX - Assumes all SG physical blocks are virtually contiguous. + */ + sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[sg_blk_cnt]); + asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr); + if (sg_ptr->sg_ptr == NULL) + { + break; + } + sg_blk_cnt++; + } + } +} + +/* + * asc_prt_adv_sgblock() * * Display an ADV_SG_BLOCK structure. */ STATIC void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b) { - int i, s; - - /* Calculate starting entry number for the current block. */ - s = sgblockno * NO_OF_SG_PER_BLOCK; + int i; - printk(" ADV_SG_BLOCK at addr 0x%lx (sgblockno %lu)\n", - (ulong) b, (ulong) sgblockno); - printk( -" first_entry_no %lu, last_entry_no %lu, sg_ptr 0x%lx\n", - (ulong) b->first_entry_no, (ulong) b->last_entry_no, (ulong) b->sg_ptr); - ASC_ASSERT(b->first_entry_no - s >= 0); - ASC_ASSERT(b->last_entry_no - s >= 0); - ASC_ASSERT(b->last_entry_no - s <= NO_OF_SG_PER_BLOCK); - ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK); - ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK); - ASC_ASSERT(b->first_entry_no - s <= b->last_entry_no - s); - for (i = b->first_entry_no - s; i <= b->last_entry_no - s; i++) { - printk(" [%lu]: sg_addr 0x%lx, sg_count 0x%lx\n", - (ulong) i, (ulong) b->sg_list[i].sg_addr, - (ulong) b->sg_list[i].sg_count); + printk(" ASC_SG_BLOCK at addr %lx (sgblockno %d)\n", + (ulong) b, sgblockno); + printk(" sg_cnt %u, sg_ptr %lx\n", + b->sg_cnt, (ulong) b->sg_ptr); + ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK); + if (b->sg_ptr != NULL) + { + ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK); + } + for (i = 0; i < b->sg_cnt; i++) { + printk(" [%u]: sg_addr %lx, sg_count %lx\n", + i, b->sg_list[i].sg_addr, b->sg_list[i].sg_count); } } @@ -10116,7 +10825,7 @@ k = 8; m = 0; } else { - m = (l - i) % 4 ; + m = (l - i) % 4; } for (j = 0; j < k; j++) { @@ -10176,10 +10885,12 @@ * --- Asc Library Functions */ -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscGetEisaChipCfg( PortAddr iop_base ) +) { PortAddr eisa_cfg_iop; @@ -10188,11 +10899,13 @@ return (inpw(eisa_cfg_iop)); } -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, AscSetChipScsiID( PortAddr iop_base, uchar new_host_id ) +) { ushort cfg_lsw; @@ -10206,10 +10919,12 @@ return (AscGetChipScsiID(iop_base)); } -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, AscGetChipScsiCtrl( PortAddr iop_base ) +) { uchar sc; @@ -10219,11 +10934,13 @@ return (sc); } -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, AscGetChipVersion( PortAddr iop_base, ushort bus_type ) +) { if ((bus_type & ASC_IS_EISA) != 0) { PortAddr eisa_iop; @@ -10236,10 +10953,12 @@ return (AscGetChipVerNo(iop_base)); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscGetChipBusType( PortAddr iop_base ) +) { ushort chip_ver; @@ -10269,13 +10988,15 @@ return (0); } -STATIC ulong ASC_INIT +ASC_INITFUNC( +STATIC ulong, AscLoadMicroCode( PortAddr iop_base, ushort s_addr, ushort *mcode_buf, ushort mcode_size ) +) { ulong chksum; ushort mcode_word_size; @@ -10293,10 +11014,12 @@ return (chksum); } -STATIC int ASC_INIT +ASC_INITFUNC( +STATIC int, AscFindSignature( PortAddr iop_base ) +) { ushort sig_word; @@ -10317,11 +11040,13 @@ ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8 }; -STATIC PortAddr ASC_INIT +ASC_INITFUNC( +STATIC PortAddr, AscSearchIOPortAddr( PortAddr iop_beg, ushort bus_type ) +) { if (bus_type & ASC_IS_VL) { while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) { @@ -10352,10 +11077,12 @@ return (0); } -STATIC PortAddr ASC_INIT +ASC_INITFUNC( +STATIC PortAddr, AscSearchIOPortAddr11( PortAddr s_addr ) +) { int i; PortAddr iop_base; @@ -10381,30 +11108,36 @@ return (0); } -STATIC void ASC_INIT +ASC_INITFUNC( +STATIC void, AscToggleIRQAct( PortAddr iop_base ) +) { AscSetChipStatus(iop_base, CIW_IRQ_ACT); AscSetChipStatus(iop_base, 0); return; } -STATIC void ASC_INIT +ASC_INITFUNC( +STATIC void, AscSetISAPNPWaitForKey( void) +) { outp(ASC_ISA_PNP_PORT_ADDR, 0x02); outp(ASC_ISA_PNP_PORT_WRITE, 0x02); return; } -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, AscGetChipIRQ( PortAddr iop_base, ushort bus_type ) +) { ushort cfg_lsw; uchar chip_irq; @@ -10434,12 +11167,14 @@ return ((uchar) (chip_irq + ASC_MIN_IRQ_NO)); } -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, AscSetChipIRQ( PortAddr iop_base, uchar irq_no, ushort bus_type ) +) { ushort cfg_lsw; @@ -10473,10 +11208,12 @@ return (0); } -STATIC void ASC_INIT +ASC_INITFUNC( +STATIC void, AscEnableIsaDma( uchar dma_channel ) +) { if (dma_channel < 4) { outp(0x000B, (ushort) (0xC0 | dma_channel)); @@ -10527,7 +11264,6 @@ tid_no = ASC_TIX_TO_TID(target_ix); target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no); if (asc_dvc->pci_fix_asyn_xfer & target_id) { - asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB; } else { asyn_sdtr = 0; @@ -10754,19 +11490,169 @@ */ boardp->queue_full |= target_id; boardp->queue_full_cnt[tid_no] = cur_dvc_qng; -#if ASC_QUEUE_FLOW_CONTROL - if (boardp->device[tid_no] != NULL && - boardp->device[tid_no]->queue_curr_depth > - cur_dvc_qng) { - boardp->device[tid_no]->queue_curr_depth = - cur_dvc_qng; - } -#endif /* ASC_QUEUE_FLOW_CONTROL */ } } } AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); return (0); + } else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) + { + uchar q_no; + ushort q_addr; + ulong srb_ptr; + uchar sg_wk_q_no; + uchar first_sg_wk_q_no; + ASC_SCSI_Q *scsiq; /* Ptr to driver request. */ + ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */ + ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */ + ushort sg_list_dwords; + ushort sg_entry_cnt; + uchar next_qp; + int i; + + q_no = AscReadLramByte(iop_base, (ushort) ASCV_REQ_SG_LIST_QP); + if (q_no == ASC_QLINK_END) + { + return(0); + } + + q_addr = ASC_QNO_TO_QADDR(q_no); + + /* Read request's SRB pointer. */ + srb_ptr = AscReadLramDWord(iop_base, + (ushort) (q_addr + ASC_SCSIQ_D_SRBPTR)); + + /* + * Get request's first and working SG queue. + */ + sg_wk_q_no = AscReadLramByte(iop_base, + (ushort) (q_addr + ASC_SCSIQ_B_SG_WK_QP)); + + first_sg_wk_q_no = AscReadLramByte(iop_base, + (ushort) (q_addr + ASC_SCSIQ_B_FIRST_SG_WK_QP)); + + /* + * Reset request's working SG queue back to the + * first SG queue. + */ + AscWriteLramByte(iop_base, + (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SG_WK_QP), + first_sg_wk_q_no); + + /* + * Convert the request's SRB pointer to a host ASC_SCSI_REQ + * structure pointer using a macro provided by the driver. + * The ASC_SCSI_REQ pointer provides a pointer to the + * host ASC_SG_HEAD structure. + */ + scsiq = (ASC_SCSI_Q *) ASC_SRB2SCSIQ(srb_ptr); + + sg_head = scsiq->sg_head; + + /* + * Set sg_entry_cnt to the number of SG elements + * that will be completed on this interrupt. + * + * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1 + * SG elements. The data_cnt and data_addr fields which + * add 1 to the SG element capacity are not used when + * restarting SG handling after a halt. + */ + if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) + { + sg_entry_cnt = ASC_MAX_SG_LIST - 1; + + /* + * Keep track of remaining number of SG elements that will + * need to be handled on the next interrupt. + */ + scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1); + } else + { + sg_entry_cnt = scsiq->remain_sg_entry_cnt; + scsiq->remain_sg_entry_cnt = 0; + } + + /* + * Copy SG elements into the list of allocated SG queues. + * + * Last index completed is saved in scsiq->next_sg_index. + */ + next_qp = first_sg_wk_q_no; + q_addr = ASC_QNO_TO_QADDR(next_qp); + scsi_sg_q.sg_head_qp = q_no; + scsi_sg_q.cntl = QCSG_SG_XFER_LIST; + for( i = 0; i < sg_head->queue_cnt; i++) + { + scsi_sg_q.seq_no = i + 1; + if (sg_entry_cnt > ASC_SG_LIST_PER_Q) + { + sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2); + sg_entry_cnt -= ASC_SG_LIST_PER_Q; + /* + * After very first SG queue RISC FW uses next + * SG queue first element then checks sg_list_cnt + * against zero and then decrements, so set + * sg_list_cnt 1 less than number of SG elements + * in each SG queue. + */ + scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1; + scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1; + } else { + /* + * This is the last SG queue in the list of + * allocated SG queues. If there are more + * SG elements than will fit in the allocated + * queues, then set the QCSG_SG_XFER_MORE flag. + */ + if (scsiq->remain_sg_entry_cnt != 0) + { + scsi_sg_q.cntl |= QCSG_SG_XFER_MORE; + } else + { + scsi_sg_q.cntl |= QCSG_SG_XFER_END; + } + /* equals sg_entry_cnt * 2 */ + sg_list_dwords = sg_entry_cnt << 1; + scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1; + scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1; + sg_entry_cnt = 0; + } + + scsi_sg_q.q_no = next_qp; + AscMemWordCopyToLram(iop_base, + (ushort) (q_addr+ASC_SCSIQ_SGHD_CPY_BEG), + (ushort *) &scsi_sg_q, + (ushort) (sizeof(ASC_SG_LIST_Q) >> 1)); + + AscMemDWordCopyToLram( iop_base, + (ushort) (q_addr+ASC_SGQ_LIST_BEG ), + (ulong *) &sg_head->sg_list[scsiq->next_sg_index], + (ushort) sg_list_dwords); + + scsiq->next_sg_index += ASC_SG_LIST_PER_Q; + + /* + * If the just completed SG queue contained the + * last SG element, then no more SG queues need + * to be written. + */ + if (scsi_sg_q.cntl & QCSG_SG_XFER_END) + { + break; + } + + next_qp = AscReadLramByte( iop_base, + ( ushort )( q_addr+ASC_SCSIQ_B_FWD ) ); + q_addr = ASC_QNO_TO_QADDR( next_qp ); + } + + /* + * Clear the halt condition so the RISC will be restarted + * after the return. + */ + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return(0); } return (0); } @@ -10798,8 +11684,18 @@ (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN)); scsiq->sense_len = (uchar) _val; scsiq->extra_bytes = (uchar) (_val >> 8); - scsiq->remain_bytes = AscReadLramWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT)); + + /* + * Read high word of remain bytes from alternate location. + */ + scsiq->remain_bytes = (((ulong) AscReadLramWord( iop_base, + (ushort) (q_addr+ (ushort) ASC_SCSIQ_W_ALT_DC1))) << 16); + /* + * Read low word of remain bytes from original location. + */ + scsiq->remain_bytes += AscReadLramWord(iop_base, + (ushort) (q_addr+ (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT)); + scsiq->remain_bytes &= max_dma_count; return (sg_queue_cnt); } @@ -10957,6 +11853,12 @@ iop_base = asc_dvc->iop_base; int_pending = FALSE; + + if (AscIsIntPending(iop_base) == 0) + { + return int_pending; + } + if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) || (asc_dvc->isr_callback == 0) ) { @@ -10977,10 +11879,15 @@ chipstat = AscGetChipStatus(iop_base); if (chipstat & CSW_SCSI_RESET_LATCH) { if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) { + int i = 10; int_pending = TRUE; asc_dvc->sdtr_done = 0; saved_ctrl_reg &= (uchar) (~CC_HALT); - while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ; + while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) && + (i-- > 0)) + { + DvcSleepMilliSecond(100); + } AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT)); AscSetChipControl(iop_base, CC_HALT); AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); @@ -11034,82 +11941,82 @@ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x91, 0x10, 0x0A, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x23, 0x00, 0x24, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x88, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40, 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62, - 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00, + 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, - 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE2, 0x01, 0xA6, 0x97, 0xCE, 0x81, 0x00, 0x33, - 0x02, 0x00, 0xC0, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0x02, 0x01, 0x4F, 0x00, - 0x84, 0x97, 0x07, 0xA6, 0x0C, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC0, 0x88, 0x03, 0x03, 0x03, 0xDE, - 0x00, 0x33, 0x05, 0x00, 0xC0, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, - 0x00, 0xA2, 0x80, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x2C, 0x01, 0x80, 0x81, 0x03, 0x03, 0x80, 0x63, - 0xE2, 0x00, 0x07, 0xA6, 0x3C, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC0, 0x88, 0x03, 0x07, 0x02, 0x01, - 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, - 0xCD, 0x04, 0x15, 0x23, 0xF6, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, - 0x06, 0xA3, 0x6A, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xC0, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x76, 0x01, - 0x00, 0x33, 0x0B, 0x00, 0xC0, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC0, 0x88, - 0x50, 0x04, 0x90, 0x81, 0x06, 0xAB, 0x8A, 0x01, 0x90, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x9A, 0x01, - 0x50, 0x00, 0x00, 0xA3, 0x44, 0x01, 0x00, 0x05, 0x84, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, - 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xC6, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, - 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xBC, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, - 0x00, 0x33, 0x1B, 0x00, 0xC0, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, - 0x00, 0xA2, 0xDC, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE2, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, - 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x08, 0x02, 0x04, 0x01, 0x0C, 0xDE, - 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x84, 0x97, 0x04, 0x82, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, - 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, - 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x67, 0xEB, - 0x11, 0x23, 0xF6, 0x88, 0x04, 0x98, 0xF4, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x32, 0x02, - 0x7C, 0x95, 0x06, 0xA6, 0x3C, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0xC0, 0x88, 0x04, 0x01, 0x03, 0xD8, - 0xB2, 0x98, 0x6A, 0x96, 0x4E, 0x82, 0xFE, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, - 0x02, 0xA6, 0x78, 0x02, 0x07, 0xA6, 0x66, 0x02, 0x06, 0xA6, 0x6A, 0x02, 0x03, 0xA6, 0x6E, 0x02, - 0x00, 0x33, 0x10, 0x00, 0xC0, 0x88, 0x7C, 0x95, 0x50, 0x82, 0x60, 0x96, 0x50, 0x82, 0x04, 0x23, - 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61, - 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, - 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xB6, 0x02, 0x07, 0xA6, 0x66, 0x02, - 0x06, 0xA6, 0x6A, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xC0, 0x02, 0x00, 0xA6, 0xC0, 0x02, - 0x00, 0x33, 0x12, 0x00, 0xC0, 0x88, 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x98, 0x02, - 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35, - 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xF6, 0x82, 0x18, 0x23, 0x04, 0x61, - 0x18, 0xA0, 0xEE, 0x02, 0x04, 0x01, 0x9C, 0xC8, 0x00, 0x33, 0x1F, 0x00, 0xC0, 0x88, 0x08, 0x31, - 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x20, 0x03, 0x00, 0xA6, - 0x20, 0x03, 0x07, 0xA6, 0x18, 0x03, 0x06, 0xA6, 0x1C, 0x03, 0x03, 0xA6, 0x20, 0x04, 0x02, 0xA6, - 0x78, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC0, 0x88, 0x7C, 0x95, 0xFA, 0x82, 0x60, 0x96, 0xFA, 0x82, - 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, 0x07, 0x01, - 0x00, 0xA2, 0x60, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98, 0x7E, 0x98, 0x00, 0xA6, - 0x22, 0x03, 0x07, 0xA6, 0x58, 0x03, 0x03, 0xA6, 0x3C, 0x04, 0x06, 0xA6, 0x5C, 0x03, 0x01, 0xA6, - 0x22, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC0, 0x88, 0x7C, 0x95, 0x3E, 0x83, 0x60, 0x96, 0x3E, 0x83, - 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0xC0, 0x88, 0x00, 0x01, 0x05, 0x05, - 0xFF, 0xA2, 0x7E, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x3A, 0x83, 0x05, 0x05, 0x15, 0x01, - 0x00, 0xA2, 0x9E, 0x03, 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, - 0x01, 0xA6, 0x9A, 0x03, 0x00, 0xA6, 0x9A, 0x03, 0x12, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6, - 0xA8, 0x03, 0x00, 0xA6, 0xC0, 0x03, 0x12, 0x84, 0xA6, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA8, 0x03, - 0x07, 0xA6, 0xB6, 0x03, 0xD8, 0x83, 0x7C, 0x95, 0xAC, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC0, 0x88, - 0xA6, 0x98, 0x80, 0x42, 0x00, 0xA6, 0xC0, 0x03, 0x07, 0xA6, 0xCE, 0x03, 0xD8, 0x83, 0x7C, 0x95, - 0xC4, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC0, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, - 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x12, 0x84, 0x06, 0xF0, 0x06, 0xA4, 0xF6, 0x03, 0x80, 0x6B, - 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x10, 0x04, 0x07, 0xA6, 0x08, 0x04, 0x06, 0xA6, - 0x0C, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC0, 0x88, 0x7C, 0x95, 0xF6, 0x83, 0x60, 0x96, 0xF6, 0x83, - 0x20, 0x84, 0x06, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, + 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88, + 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00, 0x84, 0x97, 0x07, 0xA6, + 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00, + 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6, + 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x34, 0x01, 0x00, 0x33, + 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, + 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23, + 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01, 0x00, 0x33, 0x0A, 0x00, + 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, + 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01, + 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x3C, 0x01, 0x00, 0x05, + 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, + 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, + 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0xC2, 0x88, 0x06, 0x23, + 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0, + 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, + 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x84, 0x97, + 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, + 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, + 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88, 0x04, 0x98, 0xF0, 0x80, + 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6, + 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95, + 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02, 0x07, 0xA6, 0x5A, 0x02, + 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96, + 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC, + 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, + 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, + 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02, + 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43, + 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, + 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82, + 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8, 0x00, 0x33, 0x1F, 0x00, + 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, + 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6, + 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xEE, 0x82, + 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, + 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98, + 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6, 0x3C, 0x04, 0x06, 0xA6, + 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83, + 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33, + 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x7A, 0x03, + 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03, + 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03, + 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6, 0xA4, 0x03, 0x00, 0xA6, + 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, + 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42, + 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95, 0xC0, 0x83, 0x00, 0x33, + 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, + 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, + 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04, 0x06, 0xA6, 0x0A, 0x04, + 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84, + 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6, 0x38, 0x04, 0x00, 0x33, - 0x30, 0x00, 0xC0, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, + 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, - 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC0, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, + 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00, - 0x00, 0x33, 0x1D, 0x00, 0xC0, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, - 0xC0, 0x88, 0x42, 0x23, 0xF6, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04, 0x08, 0x23, 0x22, 0xA3, + 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, + 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04, 0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23, - 0xF6, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF6, 0x88, 0x04, 0x98, - 0x00, 0xA2, 0xC0, 0x04, 0xB2, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF0, 0x81, - 0x47, 0x23, 0xF6, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB2, 0x98, 0x00, 0x33, 0x00, 0x81, - 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x08, 0x02, 0x43, 0x23, 0xF6, 0x88, 0x04, 0x23, + 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98, + 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xE8, 0x81, + 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, + 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xF4, 0x04, 0x00, 0x33, - 0x27, 0x00, 0xC0, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, + 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05, 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85, 0x46, 0x97, 0xCD, 0x04, 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85, @@ -11118,16 +12025,16 @@ 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xF8, 0x05, - 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xC0, 0x88, 0x04, 0xA0, + 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x62, 0x97, 0x04, 0x85, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0, 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05, 0x80, 0x67, 0x80, 0x63, - 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23, 0xF6, 0x88, 0x07, 0x23, + 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03, - 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC0, 0x88, 0x1D, 0x01, 0x01, 0xD6, + 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, @@ -11139,12 +12046,12 @@ 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x07, 0xA6, 0xD6, 0x06, - 0x00, 0x33, 0x2A, 0x00, 0xC0, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, - 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC0, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E, + 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, + 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, - 0x2C, 0x00, 0xC0, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, - 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC0, 0x88, 0x00, 0x00, 0x80, 0x67, + 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, + 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88, 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05, 0x81, 0x05, @@ -11154,7 +12061,7 @@ 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xC4, 0x07, 0x00, 0x33, - 0x07, 0x00, 0xC0, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, + 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07, 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, @@ -11165,19 +12072,19 @@ 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08, - 0x00, 0x33, 0x3E, 0x00, 0xC0, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x38, 0x2B, + 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36, - 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, - 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB2, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, - 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, 0x13, 0x23, - 0xF6, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, - 0xE0, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, - 0x41, 0x23, 0xF6, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84, + 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A, + 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, + 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, + 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, + 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, + 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84, }; STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf); -STATIC ulong _asc_mcode_chksum ASC_INITDATA = 0x012B5442UL; +STATIC ulong _asc_mcode_chksum ASC_INITDATA = 0x012C453FUL; #define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16 STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = @@ -11244,7 +12151,7 @@ n_q_required = 1; if (scsiq->cdbptr[0] == SCSICMD_RequestSense) { if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) { - asc_dvc->sdtr_done &= ~scsiq->q1.target_id ; + asc_dvc->sdtr_done &= ~scsiq->q1.target_id; sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); AscMsgOutSDTR(asc_dvc, asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & @@ -11266,12 +12173,15 @@ DvcLeaveCritical(last_int_level); return (ERR); } - if (sg_entry_cnt > ASC_MAX_SG_LIST) { - return (ERR); +#if !CC_VERY_LONG_SG_LIST + if (sg_entry_cnt > ASC_MAX_SG_LIST) + { + return(ERR); } +#endif /* !CC_VERY_LONG_SG_LIST */ if (sg_entry_cnt == 1) { - scsiq->q1.data_addr = sg_head->sg_list[0].addr; - scsiq->q1.data_cnt = sg_head->sg_list[0].bytes; + scsiq->q1.data_addr = (ulong) sg_head->sg_list[0].addr; + scsiq->q1.data_cnt = (ulong) sg_head->sg_list[0].bytes; scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE); } sg_entry_cnt_minus_one = sg_entry_cnt - 1; @@ -11283,7 +12193,7 @@ if (scsiq->q1.cntl & QC_SG_HEAD) { data_cnt = 0; for (i = 0; i < sg_entry_cnt; i++) { - data_cnt += sg_head->sg_list[i].bytes; + data_cnt += (ulong) sg_head->sg_list[i].bytes; } } else { data_cnt = scsiq->q1.data_cnt; @@ -11317,8 +12227,9 @@ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { if ((scsi_cmd == SCSICMD_Read6) || (scsi_cmd == SCSICMD_Read10)) { - addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr + - sg_head->sg_list[sg_entry_cnt_minus_one].bytes; + addr = + (ulong) sg_head->sg_list[sg_entry_cnt_minus_one].addr + + (ulong) sg_head->sg_list[sg_entry_cnt_minus_one].bytes; extra_bytes = (uchar) ((ushort) addr & 0x0003); if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) @@ -11332,6 +12243,15 @@ } } sg_head->entry_to_copy = sg_head->entry_cnt; + /* + * Set the sg_entry_cnt to the maximum possible. The rest of + * the SG elements will be copied when the RISC completes the + * SG elements that fit and halts. + */ + if (sg_entry_cnt > ASC_MAX_SG_LIST) + { + sg_entry_cnt = ASC_MAX_SG_LIST; + } n_q_required = AscSgListToQueue(sg_entry_cnt); if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >= (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) { @@ -11558,9 +12478,39 @@ sg_head = scsiq->sg_head; saved_data_addr = scsiq->q1.data_addr; saved_data_cnt = scsiq->q1.data_cnt; - scsiq->q1.data_addr = sg_head->sg_list[0].addr; - scsiq->q1.data_cnt = sg_head->sg_list[0].bytes; - sg_entry_cnt = sg_head->entry_cnt - 1; + scsiq->q1.data_addr = (ulong) sg_head->sg_list[0].addr; + scsiq->q1.data_cnt = (ulong) sg_head->sg_list[0].bytes; + /* + * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST + * then not all SG elements will fit in the allocated queues. + * The rest of the SG elements will be copied when the RISC + * completes the SG elements that fit and halts. + */ + if (sg_head->entry_cnt > ASC_MAX_SG_LIST) + { + /* + * Set sg_entry_cnt to be the number of SG elements that + * will fit in the allocated SG queues. It is minus 1 because + * first SG element handled above. ASC_MAX_SG_LIST is already + * inflated by 1 to account for this. For example it may + * be 50 which is 1 + 7 queues * 7 SG elements. + */ + sg_entry_cnt = ASC_MAX_SG_LIST - 1; + + /* + * Keep track of remaining number of SG elements that will + * need to be handled from a_isr.c. + */ + scsiq->remain_sg_entry_cnt = sg_head->entry_cnt - ASC_MAX_SG_LIST; + } else + { + /* + * Set sg_entry_cnt to be the number of SG elements that + * will fit in the allocated SG queues. Refer to comment + * above regarding why it is - 1. + */ + sg_entry_cnt = sg_head->entry_cnt - 1; + } if (sg_entry_cnt != 0) { scsiq->q1.cntl |= QC_SG_HEAD; q_addr = ASC_QNO_TO_QADDR(q_no); @@ -11581,7 +12531,19 @@ scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1; } } else { - scsi_sg_q.cntl |= QCSG_SG_XFER_END; + /* + * This is the last SG queue in the list of + * allocated SG queues. If there are more + * SG elements than will fit in the allocated + * queues, then set the QCSG_SG_XFER_MORE flag. + */ + if (sg_head->entry_cnt > ASC_MAX_SG_LIST) + { + scsi_sg_q.cntl |= QCSG_SG_XFER_MORE; + } else + { + scsi_sg_q.cntl |= QCSG_SG_XFER_END; + } sg_list_dwords = sg_entry_cnt << 1; if (i == 0) { scsi_sg_q.sg_list_cnt = sg_entry_cnt; @@ -11605,6 +12567,7 @@ (ulong *) & sg_head->sg_list[sg_index], (ushort) sg_list_dwords); sg_index += ASC_SG_LIST_PER_Q; + scsiq->next_sg_index = sg_index; } } else { scsiq->q1.cntl &= ~QC_SG_HEAD; @@ -11790,7 +12753,7 @@ if (org_id == (0x01 << i)) break; } - org_id = i; + org_id = (ASC_SCSI_BIT_ID_TYPE) i; AscWriteChipDvcID(iop_base, id); if (AscReadChipDvcID(iop_base) == (0x01 << id)) { AscSetBank(iop_base, 0); @@ -11929,7 +12892,7 @@ uchar q_status; int count = 0; - while (scsiq->q1.q_no == 0) ; + while (scsiq->q1.q_no == 0); q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no); do { q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS); @@ -12024,7 +12987,7 @@ period_table = asc_dvc->sdtr_period_tbl; max_index = (int) asc_dvc->max_sdtr_index; - min_index = (int)asc_dvc->host_init_sdtr_index ; + min_index = (int)asc_dvc->host_init_sdtr_index; if ((syn_time <= period_table[max_index])) { for (i = min_index; i < (max_index - 1); i++) { if (syn_time <= period_table[i]) { @@ -12323,7 +13286,7 @@ if (sg_head.entry_cnt > 1) { return (0L); } - return (sg_head.sg_list[0].addr); + return ((ulong) sg_head.sg_list[0].addr); } STATIC void @@ -12338,10 +13301,12 @@ udelay((nano_sec + 999)/1000); } -STATIC ulong ASC_INIT +ASC_INITFUNC( +STATIC ulong, AscGetEisaProductID( PortAddr iop_base ) +) { PortAddr eisa_iop; ushort product_id_high, product_id_low; @@ -12354,10 +13319,12 @@ return (product_id); } -STATIC PortAddr ASC_INIT +ASC_INITFUNC( +STATIC PortAddr, AscSearchIOPortAddrEISA( PortAddr iop_base ) +) { ulong eisa_product_id; @@ -12530,9 +13497,13 @@ ) { PortAddr iop_base; + int i = 10; iop_base = asc_dvc->iop_base; - while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ; + while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) + { + DvcSleepMilliSecond(100); + } AscStopChip(iop_base); AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT); DvcDelayNanoSecond(asc_dvc, 60000); @@ -12546,10 +13517,12 @@ return (AscIsChipHalted(iop_base)); } -STATIC ulong ASC_INIT +ASC_INITFUNC( +STATIC ulong, AscGetMaxDmaCount( ushort bus_type ) +) { if (bus_type & ASC_IS_ISA) return (ASC_MAX_ISA_DMA_COUNT); @@ -12558,10 +13531,12 @@ return (ASC_MAX_PCI_DMA_COUNT); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscGetIsaDmaChannel( PortAddr iop_base ) +) { ushort channel; @@ -12573,11 +13548,13 @@ return (channel + 4); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscSetIsaDmaChannel( PortAddr iop_base, ushort dma_channel ) +) { ushort cfg_lsw; uchar value; @@ -12595,11 +13572,13 @@ return (0); } -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, AscSetIsaDmaSpeed( PortAddr iop_base, uchar speed_value ) +) { speed_value &= 0x07; AscSetBank(iop_base, 1); @@ -12608,10 +13587,12 @@ return (AscGetIsaDmaSpeed(iop_base)); } -STATIC uchar ASC_INIT +ASC_INITFUNC( +STATIC uchar, AscGetIsaDmaSpeed( PortAddr iop_base ) +) { uchar speed_value; @@ -12622,10 +13603,12 @@ return (speed_value); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscReadPCIConfigWord( ASC_DVC_VAR asc_ptr_type *asc_dvc, ushort pci_config_offset) +) { uchar lsb, msb; @@ -12634,10 +13617,12 @@ return ((ushort) ((msb << 8) | lsb)); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscInitGetConfig( ASC_DVC_VAR asc_ptr_type * asc_dvc ) +) { ushort warn_code; PortAddr iop_base; @@ -12717,10 +13702,12 @@ return(warn_code); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscInitSetConfig( ASC_DVC_VAR asc_ptr_type * asc_dvc ) +) { ushort warn_code = 0; @@ -12736,10 +13723,12 @@ return (warn_code); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscInitFromAscDvcVar( ASC_DVC_VAR asc_ptr_type * asc_dvc ) +) { PortAddr iop_base; ushort cfg_msw; @@ -12797,16 +13786,15 @@ return (warn_code); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscInitAsc1000Driver( ASC_DVC_VAR asc_ptr_type * asc_dvc ) +) { ushort warn_code; PortAddr iop_base; - extern ushort _asc_mcode_size; - extern ulong _asc_mcode_chksum; - extern uchar _asc_mcode_buf[]; iop_base = asc_dvc->iop_base; warn_code = 0; @@ -12837,10 +13825,12 @@ return (warn_code); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscInitAscDvcVar( ASC_DVC_VAR asc_ptr_type * asc_dvc ) +) { int i; PortAddr iop_base; @@ -12869,12 +13859,12 @@ asc_dvc->no_scam = 0; asc_dvc->unit_not_ready = 0; asc_dvc->queue_full_or_busy = 0; - asc_dvc->redo_scam = 0 ; - asc_dvc->res2 = 0 ; - asc_dvc->host_init_sdtr_index = 0 ; - asc_dvc->res7 = 0 ; - asc_dvc->res8 = 0 ; - asc_dvc->cfg->can_tagged_qng = 0 ; + asc_dvc->redo_scam = 0; + asc_dvc->res2 = 0; + asc_dvc->host_init_sdtr_index = 0; + asc_dvc->res7 = 0; + asc_dvc->res8 = 0; + asc_dvc->cfg->can_tagged_qng = 0; asc_dvc->cfg->cmd_qng_enabled = 0; asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL; asc_dvc->init_sdtr = 0; @@ -12950,10 +13940,12 @@ return (warn_code); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscInitFromEEP( ASC_DVC_VAR asc_ptr_type * asc_dvc ) +) { ASCEEP_CONFIG eep_config_buf; ASCEEP_CONFIG *eep_config; @@ -13031,11 +14023,11 @@ /* Indicate EEPROM-less board. */ eep_config->adapter_info[5] = 0xBB; } else { - write_eep = 1 ; - warn_code |= ASC_WARN_EEPROM_CHKSUM ; + write_eep = 1; + warn_code |= ASC_WARN_EEPROM_CHKSUM; } } - asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr ; + asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr; asc_dvc->cfg->disc_enable = eep_config->disc_enable; asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng; asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed; @@ -13103,10 +14095,12 @@ return (warn_code); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscInitMicroCodeVar( ASC_DVC_VAR asc_ptr_type * asc_dvc ) +) { int i; ushort warn_code; @@ -13151,10 +14145,12 @@ return (warn_code); } -STATIC int ASC_INIT +ASC_INITFUNC( +STATIC int, AscTestExternalLram( ASC_DVC_VAR asc_ptr_type * asc_dvc ) +) { PortAddr iop_base; ushort q_addr; @@ -13176,11 +14172,13 @@ return (sta); } -STATIC int ASC_INIT +ASC_INITFUNC( +STATIC int, AscWriteEEPCmdReg( PortAddr iop_base, uchar cmd_reg ) +) { uchar read_back; int retry; @@ -13199,11 +14197,13 @@ } } -STATIC int ASC_INIT +ASC_INITFUNC( +STATIC int, AscWriteEEPDataReg( PortAddr iop_base, ushort data_reg ) +) { ushort read_back; int retry; @@ -13222,29 +14222,35 @@ } } -STATIC void ASC_INIT +ASC_INITFUNC( +STATIC void, AscWaitEEPRead( void ) +) { DvcSleepMilliSecond(1); return; } -STATIC void ASC_INIT +ASC_INITFUNC( +STATIC void, AscWaitEEPWrite( void ) +) { DvcSleepMilliSecond(20); return; } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscReadEEPWord( PortAddr iop_base, uchar addr ) +) { ushort read_wval; uchar cmd_reg; @@ -13259,12 +14265,14 @@ return (read_wval); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscWriteEEPWord( PortAddr iop_base, uchar addr, ushort word_val ) +) { ushort read_wval; @@ -13284,11 +14292,13 @@ return (read_wval); } -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AscGetEEPConfig( PortAddr iop_base, ASCEEP_CONFIG * cfg_buf, ushort bus_type ) +) { ushort wval; ushort sum; @@ -13323,11 +14333,13 @@ return (sum); } -STATIC int ASC_INIT +ASC_INITFUNC( +STATIC int, AscSetEEPConfigOnce( PortAddr iop_base, ASCEEP_CONFIG * cfg_buf, ushort bus_type ) +) { int n_error; ushort *wbuf; @@ -13378,11 +14390,13 @@ return (n_error); } -STATIC int ASC_INIT +ASC_INITFUNC( +STATIC int, AscSetEEPConfig( PortAddr iop_base, ASCEEP_CONFIG * cfg_buf, ushort bus_type ) +) { int retry; int n_error; @@ -13406,55 +14420,35 @@ uchar tid_no, ASC_SCSI_INQUIRY *inq) { - uchar dvc_type; - ASC_SCSI_BIT_ID_TYPE tid_bits; + uchar dvc_type; + ASC_SCSI_BIT_ID_TYPE tid_bits; dvc_type = inq->byte0.peri_dvc_type; tid_bits = ASC_TIX_TO_TARGET_ID(tid_no); - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) { - if (!(asc_dvc->init_sdtr & tid_bits)) { + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) + { + if (!(asc_dvc->init_sdtr & tid_bits)) + { if ((dvc_type == SCSI_TYPE_CDROM) && (AscCompareString((uchar *) inq->vendor_id, - (uchar *) "HP ", 3) == 0)) { + (uchar *) "HP ", 3) == 0)) + { asc_dvc->pci_fix_asyn_xfer_always |= tid_bits; } asc_dvc->pci_fix_asyn_xfer |= tid_bits; if ((dvc_type == SCSI_TYPE_PROC) || - (dvc_type == SCSI_TYPE_SCANNER)) { - asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; - } - if ((dvc_type == SCSI_TYPE_SASD) && - (AscCompareString((uchar *) inq->vendor_id, - (uchar *) "TANDBERG", 8) == 0) && - (AscCompareString((uchar *) inq->product_id, - (uchar *) " TDC 36", 7) == 0)) { - asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; - } - if ((dvc_type == SCSI_TYPE_SASD) && - (AscCompareString((uchar *) inq->vendor_id, - (uchar *) "WANGTEK ", 8) == 0)) { - asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; - } - - if ((dvc_type == SCSI_TYPE_CDROM) && - (AscCompareString((uchar *) inq->vendor_id, - (uchar *) "NEC ", 8) == 0) && - (AscCompareString((uchar *) inq->product_id, - (uchar *) "CD-ROM DRIVE ", 16) == 0)) { + (dvc_type == SCSI_TYPE_SCANNER) || + (dvc_type == SCSI_TYPE_CDROM) || + (dvc_type == SCSI_TYPE_SASD)) + { asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; } - if ((dvc_type == SCSI_TYPE_CDROM) && - (AscCompareString((uchar *) inq->vendor_id, - (uchar *) "YAMAHA", 6) == 0) && - (AscCompareString((uchar *) inq->product_id, - (uchar *) "CDR400", 6) == 0)) { - asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; - } - if (asc_dvc->pci_fix_asyn_xfer & tid_bits) { + if (asc_dvc->pci_fix_asyn_xfer & tid_bits) + { AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no, - ASYN_SDTR_DATA_FIX_PCI_REV_AB); + ASYN_SDTR_DATA_FIX_PCI_REV_AB); } } } @@ -13718,299 +14712,666 @@ * --- Adv Library Functions */ -/* a_qswap.h */ -STATIC unsigned char _adv_mcode_buf[] ASC_INITDATA = { - 0x9C, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0x44, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x01, 0xD6, 0x11, 0x00, 0x00, 0x70, 0x01, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x10, 0x2D, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0xF7, 0x70, 0x01, 0x0C, 0x1C, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF2, 0xD6, 0x0A, - 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x3E, 0x57, 0x3C, 0x56, 0x0C, 0x1C, 0x00, 0xFC, - 0xA6, 0x00, 0x01, 0x58, 0xAA, 0x13, 0x20, 0xF0, 0xA6, 0x03, 0x06, 0xEC, 0xB9, 0x00, 0x0E, 0x47, - 0x03, 0xE6, 0x10, 0x00, 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0x06, 0xEA, 0xB9, 0x00, 0x47, 0x4B, - 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x01, 0x48, 0x4E, 0x12, 0x03, 0xF6, 0xC0, 0x00, - 0x00, 0xF2, 0x68, 0x0A, 0x41, 0x58, 0x03, 0xF6, 0xD0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x49, 0x44, - 0x59, 0xF0, 0x0A, 0x02, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x44, 0x58, 0x00, 0xF2, - 0xE2, 0x0D, 0x02, 0xCC, 0x4A, 0xE4, 0x01, 0x00, 0x55, 0xF0, 0x08, 0x03, 0x45, 0xF4, 0x02, 0x00, - 0x83, 0x5A, 0x04, 0xCC, 0x01, 0x4A, 0x12, 0x12, 0x00, 0xF2, 0xE2, 0x0D, 0x00, 0xCD, 0x48, 0xE4, - 0x01, 0x00, 0xE9, 0x13, 0x00, 0xF2, 0xC6, 0x0F, 0xFA, 0x10, 0x0E, 0x47, 0x03, 0xE6, 0x10, 0x00, - 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0xCE, 0x47, 0x97, 0x13, 0x04, 0xEC, 0xB4, 0x00, 0x00, 0xF2, - 0xE2, 0x0D, 0x00, 0xCD, 0x48, 0xE4, 0x00, 0x00, 0x12, 0x12, 0x3E, 0x57, 0x06, 0xCC, 0x45, 0xF4, - 0x02, 0x00, 0x83, 0x5A, 0x00, 0xCC, 0x00, 0xEA, 0xB4, 0x00, 0x92, 0x10, 0x00, 0xF0, 0x8C, 0x01, - 0x43, 0xF0, 0x5C, 0x02, 0x44, 0xF0, 0x60, 0x02, 0x45, 0xF0, 0x64, 0x02, 0x46, 0xF0, 0x68, 0x02, - 0x47, 0xF0, 0x6E, 0x02, 0x48, 0xF0, 0x9E, 0x02, 0xB9, 0x54, 0x62, 0x10, 0x00, 0x1C, 0x5A, 0x10, - 0x02, 0x1C, 0x56, 0x10, 0x1E, 0x1C, 0x52, 0x10, 0x00, 0xF2, 0x1E, 0x11, 0x50, 0x10, 0x06, 0xFC, - 0xA8, 0x00, 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x4E, 0x0A, 0x8C, 0x10, 0x01, 0xF6, 0x01, 0x00, - 0x01, 0xFA, 0xA8, 0x00, 0x00, 0xF2, 0x2C, 0x0B, 0x06, 0x10, 0xB9, 0x54, 0x01, 0xFA, 0xA8, 0x00, - 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x58, 0x0A, 0x01, 0xFC, 0xA8, 0x00, 0x20, 0x10, 0x58, 0x1C, - 0x00, 0xF2, 0x1C, 0x0B, 0x5A, 0x1C, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54, 0x00, 0xFA, 0xA6, 0x00, - 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x72, 0x01, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54, - 0x00, 0xFA, 0xA6, 0x00, 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x80, 0x01, 0x03, 0xF6, - 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x01, 0x48, 0x0A, 0x13, 0x00, 0xF2, 0x38, 0x10, 0x00, 0xF2, - 0x54, 0x0F, 0x24, 0x10, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x02, 0xF6, 0xD0, 0x00, - 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x49, 0x44, 0x5B, 0xF0, 0x04, 0x03, 0x00, 0xF2, 0x9C, 0x0F, - 0x00, 0xF0, 0x80, 0x01, 0x00, 0xF2, 0x14, 0x10, 0x0C, 0x1C, 0x02, 0x4B, 0xBF, 0x57, 0x9E, 0x43, - 0x77, 0x57, 0x07, 0x4B, 0x20, 0xF0, 0xA6, 0x03, 0x40, 0x1C, 0x1E, 0xF0, 0x30, 0x03, 0x26, 0xF0, - 0x2C, 0x03, 0xA0, 0xF0, 0x1A, 0x03, 0x11, 0xF0, 0xA6, 0x03, 0x12, 0x10, 0x9F, 0xF0, 0x3E, 0x03, - 0x46, 0x1C, 0x82, 0xE7, 0x05, 0x00, 0x9E, 0xE7, 0x11, 0x00, 0x00, 0xF0, 0x06, 0x0A, 0x0C, 0x1C, - 0x48, 0x1C, 0x46, 0x1C, 0x38, 0x54, 0x00, 0xEC, 0xBA, 0x00, 0x08, 0x44, 0x00, 0xEA, 0xBA, 0x00, - 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x08, 0x44, 0x00, 0x4C, 0x82, 0xE7, 0x02, 0x00, - 0x00, 0xF2, 0x12, 0x11, 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0x70, 0x03, 0x00, 0xF2, 0x60, 0x0B, - 0x06, 0xF0, 0x80, 0x03, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0, 0xFC, 0x09, 0x00, 0xF0, 0x02, 0x0A, - 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0x55, 0xF0, 0xAC, 0x04, 0x01, 0xE6, 0x0C, 0x00, 0x00, 0xF2, - 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11, 0x01, 0xF0, - 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x46, 0x1C, 0x0C, 0x1C, 0x67, 0x1B, 0xBF, 0x57, 0x77, 0x57, - 0x02, 0x4B, 0x48, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x92, 0x0D, 0x30, 0x1C, 0x96, 0xF0, 0xBC, 0x03, - 0xB1, 0xF0, 0xC0, 0x03, 0x1E, 0xF0, 0xFC, 0x09, 0x85, 0xF0, 0x02, 0x0A, 0x00, 0xFC, 0xBE, 0x00, - 0x98, 0x57, 0x14, 0x12, 0x01, 0xE6, 0x0C, 0x00, 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11, - 0x01, 0xF0, 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, - 0x01, 0x48, 0x55, 0xF0, 0x98, 0x04, 0x03, 0x82, 0x03, 0xFC, 0xA0, 0x00, 0x9B, 0x57, 0x40, 0x12, - 0x69, 0x18, 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0x42, 0x04, 0x69, 0x08, 0x00, 0xF2, 0x12, 0x11, - 0x85, 0xF0, 0x02, 0x0A, 0x68, 0x08, 0x4C, 0x44, 0x28, 0x12, 0x44, 0x48, 0x03, 0xF6, 0xE0, 0x00, - 0x00, 0xF2, 0x68, 0x0A, 0x45, 0x58, 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0xCC, 0x01, 0x48, 0x55, 0xF0, - 0x98, 0x04, 0x4C, 0x44, 0xEF, 0x13, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2, 0x14, 0x10, 0x08, 0x10, - 0x68, 0x18, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D, 0x04, 0x80, 0x18, 0xE4, 0x10, 0x00, 0x28, 0x12, - 0x01, 0xE6, 0x06, 0x00, 0x04, 0x80, 0x18, 0xE4, 0x01, 0x00, 0x04, 0x12, 0x01, 0xE6, 0x0D, 0x00, - 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, - 0x01, 0xF0, 0x1C, 0x0A, 0x00, 0xF0, 0x02, 0x0A, 0x69, 0x08, 0x05, 0x80, 0x48, 0xE4, 0x00, 0x00, - 0x0C, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA, 0xB8, 0x00, 0x00, 0xF2, 0xB6, 0x10, 0x82, 0xE7, - 0x02, 0x00, 0x1C, 0x90, 0x40, 0x5C, 0x00, 0x16, 0x01, 0xE6, 0x06, 0x00, 0x00, 0xF2, 0x4E, 0x0D, - 0x01, 0xF0, 0x80, 0x01, 0x1E, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0xA0, 0x04, 0x42, 0x5B, 0x06, 0xF7, - 0x03, 0x00, 0x46, 0x59, 0xBF, 0x57, 0x77, 0x57, 0x01, 0xE6, 0x80, 0x00, 0x07, 0x80, 0x31, 0x44, - 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x56, 0x13, 0x20, 0x80, 0x48, 0xE4, 0x03, 0x00, 0x4E, 0x12, - 0x00, 0xFC, 0xA2, 0x00, 0x98, 0x57, 0x55, 0xF0, 0x1C, 0x05, 0x31, 0xE4, 0x40, 0x00, 0x00, 0xFC, - 0xA0, 0x00, 0x98, 0x57, 0x36, 0x12, 0x4C, 0x1C, 0x00, 0xF2, 0x12, 0x11, 0x89, 0x48, 0x00, 0xF2, - 0x12, 0x11, 0x86, 0xF0, 0x2E, 0x05, 0x82, 0xE7, 0x06, 0x00, 0x1B, 0x80, 0x48, 0xE4, 0x22, 0x00, - 0x5B, 0xF0, 0x0C, 0x05, 0x48, 0xE4, 0x20, 0x00, 0x59, 0xF0, 0x10, 0x05, 0x00, 0xE6, 0x20, 0x00, - 0x09, 0x48, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0x2E, 0x05, 0x83, 0x80, 0x04, 0x10, 0x00, 0xF2, - 0xA2, 0x0D, 0x00, 0xE6, 0x01, 0x00, 0x00, 0xEA, 0x26, 0x01, 0x01, 0xEA, 0x27, 0x01, 0x04, 0x80, - 0x18, 0xE4, 0x10, 0x00, 0x36, 0x12, 0xB9, 0x54, 0x00, 0xF2, 0xF6, 0x0E, 0x01, 0xE6, 0x06, 0x00, - 0x04, 0x80, 0x18, 0xE4, 0x01, 0x00, 0x04, 0x12, 0x01, 0xE6, 0x0D, 0x00, 0x00, 0xF2, 0x4E, 0x0D, - 0x00, 0xF2, 0x12, 0x11, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11, 0x04, 0xE6, 0x02, 0x00, - 0x9E, 0xE7, 0x15, 0x00, 0x01, 0xF0, 0x1C, 0x0A, 0x00, 0xF0, 0x02, 0x0A, 0x00, 0xFC, 0x20, 0x01, - 0x98, 0x57, 0x34, 0x12, 0x00, 0xFC, 0x24, 0x01, 0x98, 0x57, 0x2C, 0x13, 0xB9, 0x54, 0x00, 0xF2, - 0xF6, 0x0E, 0x86, 0xF0, 0xA8, 0x05, 0x03, 0xF6, 0x01, 0x00, 0x00, 0xF2, 0x8C, 0x0E, 0x85, 0xF0, - 0x9E, 0x05, 0x82, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x60, 0x0B, 0x82, 0xE7, 0x02, 0x00, 0x00, 0xFC, - 0x24, 0x01, 0xB0, 0x57, 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFC, 0x9E, 0x00, 0x98, 0x57, 0x5A, 0x12, - 0x00, 0xFC, 0xB6, 0x00, 0x98, 0x57, 0x52, 0x13, 0x03, 0xE6, 0x0C, 0x00, 0x00, 0xFC, 0x9C, 0x00, - 0x98, 0x57, 0x04, 0x13, 0x03, 0xE6, 0x19, 0x00, 0x05, 0xE6, 0x08, 0x00, 0x00, 0xF6, 0x00, 0x01, - 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x04, 0x13, 0x05, 0xE6, - 0x0F, 0x00, 0xB9, 0x54, 0x00, 0xF2, 0xF6, 0x0E, 0x86, 0xF0, 0x0A, 0x06, 0x00, 0xF2, 0xBA, 0x0E, - 0x85, 0xF0, 0x00, 0x06, 0x82, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x60, 0x0B, 0x82, 0xE7, 0x02, 0x00, - 0x00, 0xFC, 0xB6, 0x00, 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0xF2, - 0xF6, 0x0E, 0x9C, 0x32, 0x4E, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x92, 0x0D, 0x30, 0x1C, 0x82, 0xE7, - 0x04, 0x00, 0xB1, 0xF0, 0x22, 0x06, 0x0A, 0xF0, 0x3E, 0x06, 0x05, 0xF0, 0xD6, 0x06, 0x06, 0xF0, - 0xDC, 0x06, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0, 0xFC, 0x09, 0x00, 0xF0, 0x02, 0x0A, 0x04, 0x80, - 0x18, 0xE4, 0x20, 0x00, 0x30, 0x12, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x21, 0x80, - 0x18, 0xE4, 0xE0, 0x00, 0x09, 0x48, 0x00, 0xF2, 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, - 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x99, 0xA4, 0x00, 0xF2, 0x12, 0x11, - 0x09, 0xE7, 0x00, 0x00, 0x9A, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x34, 0x12, 0x09, 0xE7, - 0x1B, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x21, 0x80, 0x18, 0xE4, 0xE0, 0x00, 0x09, 0x48, 0x00, 0xF2, - 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, - 0x12, 0x11, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF0, - 0x0C, 0x09, 0xBB, 0x55, 0x9A, 0x81, 0x03, 0xF7, 0x20, 0x00, 0x09, 0x6F, 0x93, 0x45, 0x55, 0xF0, - 0xE2, 0x06, 0xB1, 0xF0, 0xC2, 0x06, 0x0A, 0xF0, 0xBA, 0x06, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0, - 0xFC, 0x09, 0x00, 0xF0, 0x02, 0x0A, 0x00, 0xF2, 0x60, 0x0B, 0x47, 0x10, 0x09, 0xE7, 0x08, 0x00, - 0x41, 0x10, 0x05, 0x80, 0x48, 0xE4, 0x00, 0x00, 0x1E, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA, - 0xB8, 0x00, 0x00, 0xF2, 0xB6, 0x10, 0x2C, 0x90, 0xAE, 0x90, 0x08, 0x50, 0x8A, 0x50, 0x38, 0x54, - 0x1F, 0x40, 0x00, 0xF2, 0xB4, 0x0D, 0x08, 0x10, 0x08, 0x90, 0x8A, 0x90, 0x30, 0x50, 0xB2, 0x50, - 0x9C, 0x32, 0x0C, 0x92, 0x8E, 0x92, 0x38, 0x54, 0x04, 0x80, 0x30, 0xE4, 0x08, 0x00, 0x04, 0x40, - 0x0C, 0x1C, 0x00, 0xF6, 0x03, 0x00, 0xB1, 0xF0, 0x26, 0x07, 0x9E, 0xF0, 0x3A, 0x07, 0x01, 0x48, - 0x55, 0xF0, 0xFC, 0x09, 0x0C, 0x1C, 0x10, 0x44, 0xED, 0x10, 0x0B, 0xF0, 0x5E, 0x07, 0x0C, 0xF0, - 0x62, 0x07, 0x05, 0xF0, 0x52, 0x07, 0x06, 0xF0, 0x58, 0x07, 0x09, 0xF0, 0x24, 0x09, 0x00, 0xF0, - 0x02, 0x0A, 0x00, 0xF2, 0x60, 0x0B, 0xCF, 0x10, 0x09, 0xE7, 0x08, 0x00, 0xC9, 0x10, 0x2E, 0x1C, - 0x02, 0x10, 0x2C, 0x1C, 0xAA, 0xF0, 0x64, 0x07, 0xAC, 0xF0, 0x72, 0x07, 0x40, 0x10, 0x34, 0x1C, - 0xF3, 0x10, 0xAD, 0xF0, 0x7C, 0x07, 0xC8, 0x10, 0x36, 0x1C, 0xE9, 0x10, 0x2B, 0xF0, 0x82, 0x08, - 0x6B, 0x18, 0x18, 0xF4, 0x00, 0xFE, 0x20, 0x12, 0x01, 0x58, 0xD2, 0xF0, 0x82, 0x08, 0x76, 0x18, - 0x18, 0xF4, 0x03, 0x00, 0xEC, 0x12, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xE2, 0x12, - 0x0B, 0xF0, 0x64, 0x07, 0x0C, 0xF0, 0x64, 0x07, 0x36, 0x1C, 0x34, 0x1C, 0xB7, 0x10, 0x38, 0x54, - 0xB9, 0x54, 0x84, 0x80, 0x19, 0xE4, 0x20, 0x00, 0xB2, 0x13, 0x85, 0x80, 0x81, 0x48, 0x66, 0x12, - 0x04, 0x80, 0x18, 0xE4, 0x08, 0x00, 0x58, 0x13, 0x1F, 0x80, 0x08, 0x44, 0xC8, 0x44, 0x9F, 0x12, - 0x1F, 0x40, 0x34, 0x91, 0xB6, 0x91, 0x44, 0x55, 0xE5, 0x55, 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49, - 0xBB, 0x55, 0x82, 0x81, 0xC0, 0x55, 0x48, 0xF4, 0x0F, 0x00, 0x5A, 0xF0, 0x1A, 0x08, 0x4A, 0xE4, - 0x17, 0x00, 0xD5, 0xF0, 0xFA, 0x07, 0x02, 0xF6, 0x0F, 0x00, 0x02, 0xF4, 0x02, 0x00, 0x02, 0xEA, - 0xB8, 0x00, 0x04, 0x91, 0x86, 0x91, 0x02, 0x4B, 0x2C, 0x90, 0x08, 0x50, 0x2E, 0x90, 0x0A, 0x50, - 0x2C, 0x51, 0xAE, 0x51, 0x00, 0xF2, 0xB6, 0x10, 0x38, 0x54, 0x00, 0xF2, 0xB4, 0x0D, 0x56, 0x10, - 0x34, 0x91, 0xB6, 0x91, 0x0C, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x08, 0x00, 0x41, 0x12, 0x0C, 0x91, - 0x8E, 0x91, 0x04, 0x80, 0x18, 0xE4, 0xF7, 0x00, 0x04, 0x40, 0x30, 0x90, 0xB2, 0x90, 0x36, 0x10, - 0x02, 0x80, 0x48, 0xE4, 0x10, 0x00, 0x31, 0x12, 0x82, 0xE7, 0x10, 0x00, 0x84, 0x80, 0x19, 0xE4, - 0x20, 0x00, 0x10, 0x13, 0x0C, 0x90, 0x8E, 0x90, 0x5D, 0xF0, 0x78, 0x07, 0x0C, 0x58, 0x8D, 0x58, - 0x00, 0xF0, 0x64, 0x07, 0x38, 0x54, 0xB9, 0x54, 0x19, 0x80, 0xF1, 0x10, 0x3A, 0x55, 0x19, 0x81, - 0xBB, 0x55, 0x10, 0x90, 0x92, 0x90, 0x10, 0x58, 0x91, 0x58, 0x14, 0x59, 0x95, 0x59, 0x00, 0xF0, - 0x64, 0x07, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x06, 0x12, 0x6C, 0x19, 0x19, 0x41, 0x7C, 0x10, - 0x6C, 0x19, 0x0C, 0x51, 0xED, 0x19, 0x8E, 0x51, 0x6B, 0x18, 0x18, 0xF4, 0x00, 0xFF, 0x02, 0x13, - 0x6A, 0x10, 0x01, 0x58, 0xD2, 0xF0, 0xC0, 0x08, 0x76, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x0A, 0x12, - 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0x06, 0x13, 0x9E, 0xE7, 0x16, 0x00, 0x4C, 0x10, - 0xD1, 0xF0, 0xCA, 0x08, 0x9E, 0xE7, 0x17, 0x00, 0x42, 0x10, 0xD0, 0xF0, 0xD4, 0x08, 0x9E, 0xE7, - 0x19, 0x00, 0x38, 0x10, 0xCF, 0xF0, 0xDE, 0x08, 0x9E, 0xE7, 0x20, 0x00, 0x2E, 0x10, 0xCE, 0xF0, - 0xE8, 0x08, 0x9E, 0xE7, 0x21, 0x00, 0x24, 0x10, 0xCD, 0xF0, 0xF2, 0x08, 0x9E, 0xE7, 0x22, 0x00, - 0x1A, 0x10, 0xCC, 0xF0, 0x04, 0x09, 0x84, 0x80, 0x19, 0xE4, 0x04, 0x00, 0x06, 0x12, 0x9E, 0xE7, - 0x12, 0x00, 0x08, 0x10, 0xCB, 0xF0, 0x0C, 0x09, 0x9E, 0xE7, 0x24, 0x00, 0xB1, 0xF0, 0x0C, 0x09, - 0x05, 0xF0, 0x1E, 0x09, 0x09, 0xF0, 0x24, 0x09, 0x1E, 0xF0, 0xFC, 0x09, 0xE4, 0x10, 0x00, 0xF2, - 0x60, 0x0B, 0xE9, 0x10, 0x9C, 0x32, 0x82, 0xE7, 0x20, 0x00, 0x32, 0x1C, 0xE9, 0x09, 0x00, 0xF2, - 0x12, 0x11, 0x85, 0xF0, 0x02, 0x0A, 0x69, 0x08, 0x01, 0xF0, 0x44, 0x09, 0x1E, 0xF0, 0xFC, 0x09, - 0x00, 0xF0, 0x38, 0x09, 0x30, 0x44, 0x06, 0x12, 0x9E, 0xE7, 0x42, 0x00, 0xB8, 0x10, 0x04, 0xF6, - 0x01, 0x00, 0xB3, 0x45, 0x74, 0x12, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x22, 0x13, 0x4B, 0xE4, - 0x02, 0x00, 0x36, 0x12, 0x4B, 0xE4, 0x28, 0x00, 0xAC, 0x13, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, - 0xC8, 0x11, 0x03, 0xF6, 0xD0, 0x00, 0xFA, 0x14, 0x82, 0xE7, 0x01, 0x00, 0x00, 0xF0, 0x80, 0x01, - 0x9E, 0xE7, 0x44, 0x00, 0x4B, 0xE4, 0x02, 0x00, 0x06, 0x12, 0x03, 0xE6, 0x02, 0x00, 0x76, 0x10, - 0x00, 0xF2, 0xA2, 0x0D, 0x03, 0xE6, 0x02, 0x00, 0x6C, 0x10, 0x00, 0xF2, 0xA2, 0x0D, 0x19, 0x82, - 0x34, 0x46, 0x0A, 0x13, 0x03, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x43, 0x00, 0x68, 0x10, 0x04, 0x80, - 0x30, 0xE4, 0x20, 0x00, 0x04, 0x40, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11, 0x82, 0xE7, - 0x01, 0x00, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF0, 0x08, 0x03, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, - 0x06, 0x12, 0x03, 0xE6, 0x02, 0x00, 0x3E, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x3A, 0x12, - 0x04, 0x80, 0x18, 0xE4, 0xFD, 0x00, 0x04, 0x40, 0x1C, 0x1C, 0x9D, 0xF0, 0xEA, 0x09, 0x1C, 0x1C, - 0x9D, 0xF0, 0xF0, 0x09, 0xC1, 0x10, 0x9E, 0xE7, 0x13, 0x00, 0x0A, 0x10, 0x9E, 0xE7, 0x41, 0x00, - 0x04, 0x10, 0x9E, 0xE7, 0x24, 0x00, 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0xD5, 0xF0, 0x8A, 0x02, - 0x04, 0xE6, 0x04, 0x00, 0x06, 0x10, 0x04, 0xE6, 0x04, 0x00, 0x9D, 0x41, 0x1C, 0x42, 0x9F, 0xE7, - 0x00, 0x00, 0x06, 0xF7, 0x02, 0x00, 0x03, 0xF6, 0xE0, 0x00, 0x3C, 0x14, 0x44, 0x58, 0x45, 0x58, - 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0xF2, 0x7E, 0x10, 0x00, 0xF2, 0xC6, 0x0F, 0x3C, 0x14, 0x1E, 0x1C, - 0x00, 0xF0, 0x80, 0x01, 0x12, 0x1C, 0x22, 0x1C, 0xD2, 0x14, 0x00, 0xF0, 0x72, 0x01, 0x83, 0x59, - 0x03, 0xDC, 0x73, 0x57, 0x80, 0x5D, 0x00, 0x16, 0x83, 0x59, 0x03, 0xDC, 0x38, 0x54, 0x70, 0x57, - 0x33, 0x54, 0x3B, 0x54, 0x80, 0x5D, 0x00, 0x16, 0x03, 0x57, 0x83, 0x59, 0x38, 0x54, 0x00, 0xCC, - 0x00, 0x16, 0x03, 0x57, 0x83, 0x59, 0x00, 0x4C, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4, 0x01, 0x00, - 0x0E, 0x12, 0x48, 0xE4, 0x05, 0x00, 0x08, 0x12, 0x00, 0xF2, 0xBC, 0x11, 0x00, 0xF2, 0xC8, 0x11, - 0xC1, 0x5A, 0x3A, 0x55, 0x02, 0xEC, 0xB5, 0x00, 0x45, 0x59, 0x00, 0xF2, 0xF6, 0x0D, 0x83, 0x58, - 0x30, 0xE7, 0x00, 0x00, 0x10, 0x4D, 0x30, 0xE7, 0x40, 0x00, 0x10, 0x4F, 0x38, 0x90, 0xBA, 0x90, - 0x10, 0x5C, 0x80, 0x5C, 0x83, 0x5A, 0x10, 0x4E, 0x04, 0xEA, 0xB5, 0x00, 0x43, 0x5B, 0x03, 0xF4, - 0xE0, 0x00, 0x83, 0x59, 0x04, 0xCC, 0x01, 0x4A, 0x0A, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D, - 0x00, 0xF2, 0x38, 0x10, 0x00, 0x16, 0x08, 0x1C, 0x00, 0xFC, 0xAC, 0x00, 0x06, 0x58, 0x67, 0x18, - 0x18, 0xF4, 0x8F, 0xE1, 0x01, 0xFC, 0xAE, 0x00, 0x19, 0xF4, 0x70, 0x1E, 0xB0, 0x54, 0x07, 0x58, - 0x00, 0xFC, 0xB0, 0x00, 0x08, 0x58, 0x00, 0xFC, 0xB2, 0x00, 0x09, 0x58, 0x0A, 0x1C, 0x00, 0xE6, - 0x0F, 0x00, 0x00, 0xEA, 0xB9, 0x00, 0x38, 0x54, 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFA, 0xB6, 0x00, - 0x18, 0x1C, 0x14, 0x1C, 0x10, 0x1C, 0x32, 0x1C, 0x12, 0x1C, 0x00, 0x16, 0x3E, 0x57, 0x0C, 0x14, - 0x0E, 0x47, 0x07, 0xE6, 0x10, 0x00, 0xCE, 0x47, 0xF5, 0x13, 0x00, 0x16, 0x00, 0xF2, 0xA2, 0x0D, - 0x02, 0x4B, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x68, 0x0A, 0x01, 0x48, 0x20, 0x12, 0x44, 0x58, - 0x45, 0x58, 0x9E, 0xE7, 0x15, 0x00, 0x9C, 0xE7, 0x04, 0x00, 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0xF2, - 0x7E, 0x10, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2, 0x7A, 0x0A, 0x1E, 0x1C, 0xD5, 0x10, 0x00, 0x16, - 0x69, 0x08, 0x48, 0xE4, 0x04, 0x00, 0x64, 0x12, 0x48, 0xE4, 0x02, 0x00, 0x20, 0x12, 0x48, 0xE4, - 0x03, 0x00, 0x1A, 0x12, 0x48, 0xE4, 0x08, 0x00, 0x14, 0x12, 0x48, 0xE4, 0x01, 0x00, 0xF0, 0x12, - 0x48, 0xE4, 0x07, 0x00, 0x12, 0x12, 0x01, 0xE6, 0x07, 0x00, 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2, - 0x12, 0x11, 0x05, 0xF0, 0x60, 0x0B, 0x00, 0x16, 0x00, 0xE6, 0x01, 0x00, 0x00, 0xEA, 0x99, 0x00, - 0x02, 0x80, 0x48, 0xE4, 0x03, 0x00, 0xE7, 0x12, 0x48, 0xE4, 0x06, 0x00, 0xE1, 0x12, 0x01, 0xE6, - 0x06, 0x00, 0x00, 0xF2, 0x4E, 0x0D, 0x00, 0xF2, 0x12, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7, - 0x15, 0x00, 0x01, 0xF0, 0x1C, 0x0A, 0x00, 0xF0, 0x02, 0x0A, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4, - 0x10, 0x00, 0x1C, 0x12, 0x82, 0xE7, 0x08, 0x00, 0x3C, 0x56, 0x03, 0x82, 0x00, 0xF2, 0xE2, 0x0D, - 0x30, 0xE7, 0x08, 0x00, 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF0, 0x80, 0x01, - 0x6C, 0x19, 0xED, 0x19, 0x5D, 0xF0, 0xD4, 0x0B, 0x44, 0x55, 0xE5, 0x55, 0x59, 0xF0, 0x52, 0x0C, - 0x04, 0x55, 0xA5, 0x55, 0x1F, 0x80, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80, 0x49, 0x44, - 0x2E, 0x13, 0x01, 0xEC, 0xB8, 0x00, 0x41, 0xE4, 0x02, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x49, 0xE4, - 0x11, 0x00, 0x59, 0xF0, 0x2E, 0x0C, 0x01, 0xE6, 0x17, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x02, 0x4B, - 0x88, 0x90, 0xAC, 0x50, 0x8A, 0x90, 0xAE, 0x50, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80, - 0x10, 0x44, 0x02, 0x4B, 0x1F, 0x40, 0xC0, 0x44, 0x00, 0xF2, 0xB4, 0x0D, 0x04, 0x55, 0xA5, 0x55, - 0x9F, 0x10, 0x0C, 0x51, 0x8E, 0x51, 0x30, 0x90, 0xB2, 0x90, 0x00, 0x56, 0xA1, 0x56, 0x30, 0x50, - 0xB2, 0x50, 0x34, 0x90, 0xB6, 0x90, 0x40, 0x56, 0xE1, 0x56, 0x34, 0x50, 0xB6, 0x50, 0x65, 0x10, - 0xB1, 0xF0, 0x70, 0x0C, 0x85, 0xF0, 0xCA, 0x0B, 0xE9, 0x09, 0x4B, 0xE4, 0x03, 0x00, 0x78, 0x12, - 0x4B, 0xE4, 0x02, 0x00, 0x01, 0x13, 0xB1, 0xF0, 0x86, 0x0C, 0x85, 0xF0, 0xCA, 0x0B, 0x69, 0x08, - 0x48, 0xE4, 0x03, 0x00, 0xD5, 0xF0, 0x86, 0x0B, 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0xCA, 0x0B, - 0xE8, 0x09, 0x3C, 0x56, 0x00, 0xFC, 0x20, 0x01, 0x98, 0x57, 0x02, 0x13, 0xBB, 0x45, 0x4B, 0xE4, - 0x00, 0x00, 0x08, 0x12, 0x03, 0xE6, 0x01, 0x00, 0x04, 0xF6, 0x00, 0x80, 0xA8, 0x14, 0xD2, 0x14, - 0x30, 0x1C, 0x02, 0x80, 0x48, 0xE4, 0x03, 0x00, 0x10, 0x13, 0x00, 0xFC, 0xB6, 0x00, 0x98, 0x57, - 0x02, 0x13, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF0, 0x8E, 0x0B, 0x00, 0xFC, 0x24, 0x01, 0xB0, 0x57, - 0x00, 0xFA, 0x24, 0x01, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0x8E, 0x0B, - 0x00, 0xF2, 0x8C, 0x0E, 0x00, 0xF0, 0x8E, 0x0B, 0xB1, 0xF0, 0xF8, 0x0C, 0x85, 0xF0, 0x86, 0x0B, - 0x69, 0x08, 0x48, 0xE4, 0x01, 0x00, 0xD5, 0xF0, 0x86, 0x0B, 0xFC, 0x14, 0x42, 0x58, 0x6C, 0x14, - 0x80, 0x14, 0x30, 0x1C, 0x4A, 0xF4, 0x02, 0x00, 0x55, 0xF0, 0x86, 0x0B, 0x4A, 0xF4, 0x01, 0x00, - 0x0E, 0x12, 0x02, 0x80, 0x48, 0xE4, 0x03, 0x00, 0x06, 0x13, 0x3E, 0x1C, 0x00, 0xF0, 0x8E, 0x0B, - 0x00, 0xFC, 0xB6, 0x00, 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2, - 0x12, 0x11, 0x86, 0xF0, 0x8E, 0x0B, 0x00, 0xF2, 0xBA, 0x0E, 0x00, 0xF0, 0x8E, 0x0B, 0x4C, 0x1C, - 0xB1, 0xF0, 0x50, 0x0D, 0x85, 0xF0, 0x5C, 0x0D, 0x69, 0x08, 0xF3, 0x10, 0x86, 0xF0, 0x64, 0x0D, - 0x4E, 0x1C, 0x89, 0x48, 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, - 0x00, 0xDC, 0x18, 0xF4, 0xFF, 0x7F, 0x30, 0x56, 0x00, 0x5C, 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, - 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x30, 0x56, 0x00, 0x5C, - 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x0B, 0x58, - 0x00, 0x16, 0x03, 0xF6, 0x24, 0x01, 0x00, 0xF2, 0x58, 0x0A, 0x03, 0xF6, 0xB6, 0x00, 0x00, 0xF2, - 0x58, 0x0A, 0x00, 0x16, 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49, 0x18, 0xF4, 0xFF, 0x00, 0x00, 0x54, - 0x00, 0x54, 0x00, 0x54, 0x00, 0xF4, 0x08, 0x00, 0xE1, 0x18, 0x80, 0x54, 0x03, 0x58, 0x00, 0xDD, - 0x01, 0xDD, 0x02, 0xDD, 0x03, 0xDC, 0x02, 0x4B, 0x30, 0x50, 0xB2, 0x50, 0x34, 0x51, 0xB6, 0x51, - 0x00, 0x16, 0x45, 0x5A, 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56, 0x05, 0xF4, - 0x02, 0x12, 0x83, 0x5A, 0x00, 0x16, 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56, - 0x05, 0xF4, 0x00, 0x12, 0x83, 0x5A, 0x00, 0x16, 0x38, 0x54, 0xBB, 0x55, 0x3C, 0x56, 0xBD, 0x56, - 0x00, 0xF2, 0x12, 0x11, 0x85, 0xF0, 0x82, 0x0E, 0xE9, 0x09, 0xC1, 0x59, 0x00, 0xF2, 0x12, 0x11, - 0x85, 0xF0, 0x82, 0x0E, 0xE8, 0x0A, 0x83, 0x55, 0x83, 0x55, 0x4B, 0xF4, 0x90, 0x01, 0x5C, 0xF0, - 0x36, 0x0E, 0xBD, 0x56, 0x40, 0x10, 0x4B, 0xF4, 0x30, 0x00, 0x59, 0xF0, 0x48, 0x0E, 0x01, 0xF6, - 0x0C, 0x00, 0x00, 0xF6, 0x01, 0x00, 0x2E, 0x10, 0x02, 0xFC, 0x9C, 0x00, 0x9A, 0x57, 0x14, 0x13, - 0x4B, 0xF4, 0x64, 0x00, 0x59, 0xF0, 0x64, 0x0E, 0x03, 0xF6, 0x64, 0x00, 0x01, 0xF6, 0x19, 0x00, - 0x00, 0xF6, 0x01, 0x00, 0x43, 0xF4, 0x33, 0x00, 0x56, 0xF0, 0x76, 0x0E, 0x04, 0xF4, 0x00, 0x01, - 0x43, 0xF4, 0x19, 0x00, 0xF3, 0x10, 0xB4, 0x56, 0xC3, 0x58, 0x02, 0xFC, 0x9E, 0x00, 0x9A, 0x57, - 0x08, 0x13, 0x3C, 0x56, 0x00, 0xF6, 0x02, 0x00, 0x00, 0x16, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00, - 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xB8, 0x0E, 0x09, 0xE7, 0x02, 0x00, 0x00, 0xF2, 0x12, 0x11, - 0x86, 0xF0, 0xB8, 0x0E, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xB8, 0x0E, - 0x4E, 0x1C, 0x89, 0x49, 0x00, 0xF2, 0x12, 0x11, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, - 0x12, 0x11, 0x86, 0xF0, 0xF2, 0x0E, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, - 0xF2, 0x0E, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xF2, 0x0E, 0x89, 0x49, - 0x00, 0xF2, 0x12, 0x11, 0x86, 0xF0, 0xF2, 0x0E, 0x4E, 0x1C, 0x89, 0x4A, 0x00, 0xF2, 0x12, 0x11, - 0x00, 0x16, 0x3C, 0x56, 0x00, 0x16, 0x00, 0xEC, 0x26, 0x01, 0x48, 0xE4, 0x01, 0x00, 0x1E, 0x13, - 0x38, 0x44, 0x00, 0xEA, 0x26, 0x01, 0x49, 0xF4, 0x00, 0x00, 0x04, 0x12, 0x4E, 0x1C, 0x02, 0x10, - 0x4C, 0x1C, 0x01, 0xEC, 0x27, 0x01, 0x89, 0x48, 0x00, 0xF2, 0x12, 0x11, 0x02, 0x14, 0x00, 0x16, - 0x85, 0xF0, 0x52, 0x0F, 0x38, 0x54, 0x00, 0xEA, 0x99, 0x00, 0x00, 0xF2, 0x60, 0x0B, 0x02, 0x80, - 0x48, 0xE4, 0x06, 0x00, 0x1C, 0x13, 0x00, 0xEC, 0x99, 0x00, 0x48, 0xE4, 0x01, 0x00, 0x0A, 0x12, - 0x04, 0x80, 0x30, 0xE4, 0x01, 0x00, 0x04, 0x40, 0x08, 0x10, 0x04, 0x80, 0x18, 0xE4, 0xFE, 0x00, - 0x04, 0x40, 0x00, 0x16, 0x02, 0xF6, 0xE0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x81, 0x48, - 0x22, 0x12, 0x00, 0x4E, 0x83, 0x5A, 0x90, 0x4C, 0x20, 0xE7, 0x00, 0x00, 0xC3, 0x58, 0x1B, 0xF4, - 0xFF, 0x00, 0x83, 0x55, 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12, 0x8B, 0x55, 0x83, 0x59, - 0x00, 0x4E, 0x00, 0x16, 0x00, 0x4E, 0x02, 0xF6, 0xF0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x00, 0x4E, - 0x83, 0x5A, 0x30, 0xE7, 0x00, 0x00, 0x20, 0xE7, 0x00, 0x00, 0x00, 0x16, 0x02, 0xF6, 0xF0, 0x00, - 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x00, 0x4E, 0x83, 0x5A, 0x30, 0xE7, 0x00, 0x00, 0x80, 0x4C, - 0xC3, 0x58, 0x1B, 0xF4, 0xFF, 0x00, 0x83, 0x55, 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12, - 0x83, 0x59, 0x00, 0x4E, 0x00, 0x16, 0x03, 0xF6, 0xE0, 0x00, 0x03, 0x57, 0x83, 0x59, 0x3A, 0x55, - 0x02, 0xCC, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D, 0xC0, 0x5A, 0x40, 0x5C, 0x38, 0x54, 0x00, 0xCD, - 0x01, 0xCC, 0x4A, 0x46, 0x0A, 0x13, 0x83, 0x59, 0x00, 0x4C, 0x01, 0x48, 0x16, 0x13, 0x0C, 0x10, - 0xC5, 0x58, 0x00, 0xF2, 0xF6, 0x0D, 0x00, 0x4C, 0x01, 0x48, 0x08, 0x13, 0x05, 0xF6, 0xF0, 0x00, - 0x05, 0x57, 0x08, 0x10, 0x45, 0x58, 0x00, 0xF2, 0xF6, 0x0D, 0x8D, 0x56, 0x83, 0x5A, 0x80, 0x4C, - 0x05, 0x17, 0x00, 0x16, 0x02, 0x4B, 0x06, 0xF7, 0x04, 0x00, 0x62, 0x0B, 0x03, 0x82, 0x00, 0xF2, - 0xE2, 0x0D, 0x02, 0x80, 0x00, 0x4C, 0x45, 0xF4, 0x02, 0x00, 0x52, 0x14, 0x06, 0xF7, 0x02, 0x00, - 0x06, 0x14, 0x00, 0xF2, 0x54, 0x0F, 0x00, 0x16, 0x02, 0x4B, 0x01, 0xF6, 0xFF, 0x00, 0x38, 0x1C, - 0x05, 0xF4, 0x04, 0x00, 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x1D, 0xF7, 0x3C, 0x00, 0xB8, 0xF0, - 0x4E, 0x10, 0x9C, 0x14, 0x01, 0x48, 0x1C, 0x13, 0x0E, 0xF7, 0x3C, 0x00, 0x03, 0xF7, 0x04, 0x00, - 0xAF, 0x19, 0x03, 0x42, 0x45, 0xF4, 0x02, 0x00, 0x83, 0x5A, 0x02, 0xCC, 0x02, 0x41, 0x45, 0xF4, - 0x02, 0x00, 0x00, 0x16, 0x91, 0x44, 0xD5, 0xF0, 0x3E, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x01, 0xF6, - 0xFF, 0x00, 0x38, 0x1C, 0x05, 0xF4, 0x04, 0x00, 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x0E, 0xF7, - 0x3C, 0x00, 0x03, 0xF7, 0x04, 0x00, 0x0F, 0x79, 0x1C, 0xF7, 0x3C, 0x00, 0xB8, 0xF0, 0x9C, 0x10, - 0x4E, 0x14, 0x01, 0x48, 0x06, 0x13, 0x45, 0xF4, 0x04, 0x00, 0x00, 0x16, 0x91, 0x44, 0xD5, 0xF0, - 0x82, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x02, 0xF6, 0xFF, 0x00, 0x38, 0x1C, 0x2C, 0xBC, 0xAE, 0xBC, - 0xE2, 0x08, 0x00, 0xEC, 0xB8, 0x00, 0x02, 0x48, 0x1D, 0xF7, 0x80, 0x00, 0xB8, 0xF0, 0xCC, 0x10, - 0x1E, 0x14, 0x01, 0x48, 0x0E, 0x13, 0x0E, 0xF7, 0x80, 0x00, 0x38, 0x54, 0x03, 0x58, 0xAF, 0x19, - 0x82, 0x48, 0x00, 0x16, 0x82, 0x48, 0x12, 0x45, 0xD5, 0xF0, 0xBA, 0x10, 0x00, 0xF0, 0x9E, 0x02, - 0x39, 0xF0, 0xF8, 0x10, 0x38, 0x44, 0x00, 0x16, 0x7E, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x04, 0x13, - 0x61, 0x18, 0x00, 0x16, 0x38, 0x1C, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xF1, 0x12, - 0xE3, 0x10, 0x30, 0x44, 0x30, 0x44, 0x30, 0x44, 0xB1, 0xF0, 0x18, 0x11, 0x00, 0x16, 0x3E, 0x57, - 0x03, 0xF6, 0xE0, 0x00, 0x03, 0x57, 0x83, 0x59, 0x04, 0xCC, 0x01, 0x4A, 0x6A, 0x12, 0x45, 0x5A, - 0x00, 0xF2, 0xF6, 0x0D, 0x02, 0x4B, 0x70, 0x14, 0x34, 0x13, 0x02, 0x80, 0x48, 0xE4, 0x08, 0x00, - 0x18, 0x12, 0x9C, 0xE7, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2, - 0x7A, 0x0A, 0x1E, 0x1C, 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x30, 0xE4, 0x10, 0x00, 0x04, 0x40, - 0x00, 0xF2, 0xE2, 0x0D, 0x20, 0xE7, 0x01, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x04, 0xDC, - 0x01, 0x4A, 0x24, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF6, 0x0D, 0x43, 0x5B, 0x06, 0xEC, 0x98, 0x00, - 0x00, 0xF2, 0x38, 0x10, 0xC6, 0x59, 0x20, 0x14, 0x0A, 0x13, 0x00, 0xF2, 0xC6, 0x0F, 0x00, 0xF2, - 0x14, 0x10, 0xA7, 0x10, 0x83, 0x5A, 0xD7, 0x10, 0x0E, 0x47, 0x07, 0xE6, 0x10, 0x00, 0xCE, 0x47, - 0x5A, 0xF0, 0x20, 0x11, 0xB9, 0x54, 0x00, 0x16, 0x14, 0x90, 0x96, 0x90, 0x02, 0xFC, 0xA8, 0x00, - 0x03, 0xFC, 0xAA, 0x00, 0x48, 0x55, 0x02, 0x13, 0xC9, 0x55, 0x00, 0x16, 0x00, 0xEC, 0xBA, 0x00, - 0x10, 0x44, 0x00, 0xEA, 0xBA, 0x00, 0x00, 0x16, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x68, 0x0A, - 0x10, 0x44, 0x00, 0x4C, 0x00, 0x16 -}; - -unsigned short _adv_mcode_size ASC_INITDATA = - sizeof(_adv_mcode_buf); /* 0x11D6 */ -unsigned long _adv_mcode_chksum ASC_INITDATA = 0x03494981UL; +/* a_mcode.h */ +STATIC unsigned char _adv_asc3550_buf[] = { + 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x00, 0xfc, 0x48, 0xe4, 0x01, 0x00, 0x01, 0xf6, + 0x00, 0xf6, 0x18, 0xe4, 0x0a, 0x19, 0x18, 0x80, 0x02, 0x00, 0xff, 0xff, 0x03, 0xf6, 0x00, 0xfa, + 0xff, 0x00, 0x82, 0xe7, 0x9e, 0xe7, 0x01, 0xfa, 0x06, 0x0e, 0x09, 0xe7, 0x00, 0xea, 0x01, 0xe6, + 0x03, 0x00, 0x08, 0x00, 0x18, 0xf4, 0x55, 0xf0, 0x3e, 0x01, 0x3e, 0x57, 0x04, 0x00, 0x1e, 0xf0, + 0x85, 0xf0, 0x00, 0xe6, 0x00, 0xec, 0x32, 0xf0, 0x86, 0xf0, 0xa4, 0x0c, 0xd0, 0x01, 0xd5, 0xf0, + 0xf6, 0x18, 0x38, 0x54, 0x98, 0x57, 0xbc, 0x00, 0xb1, 0xf0, 0xb4, 0x00, 0x01, 0xfc, 0x02, 0x13, + 0x03, 0xfc, 0x9e, 0x0c, 0x00, 0x57, 0x01, 0xf0, 0x03, 0xe6, 0x0c, 0x1c, 0x10, 0x00, 0x18, 0x40, + 0x30, 0x12, 0x3e, 0x1c, 0xbd, 0x00, 0xe0, 0x00, 0x02, 0x48, 0x02, 0x80, 0x3c, 0x00, 0x4e, 0x01, + 0x66, 0x15, 0x6c, 0x01, 0x6e, 0x01, 0xbb, 0x00, 0xda, 0x12, 0x00, 0x4e, 0x01, 0x01, 0x01, 0xea, + 0x08, 0x12, 0x30, 0xe4, 0x6a, 0x0f, 0xa8, 0x0c, 0xae, 0x0f, 0xb6, 0x00, 0xb9, 0x54, 0x00, 0x80, + 0x04, 0x12, 0x06, 0xf7, 0x24, 0x01, 0x28, 0x01, 0x32, 0x00, 0x3c, 0x01, 0x3c, 0x56, 0x3e, 0x00, + 0x4b, 0xe4, 0x4c, 0x1c, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, + 0x78, 0x01, 0x00, 0x01, 0x02, 0xee, 0x02, 0xfc, 0x03, 0x58, 0x03, 0xf7, 0x04, 0x80, 0x05, 0xfc, + 0x08, 0x44, 0x09, 0xf0, 0x0a, 0x15, 0x10, 0x44, 0x1b, 0x80, 0x20, 0x01, 0x38, 0x1c, 0x40, 0x00, + 0x4b, 0xf4, 0x4e, 0x1c, 0x5b, 0xf0, 0x5d, 0xf0, 0x80, 0x00, 0xaa, 0x00, 0xaa, 0x14, 0xb6, 0x08, + 0xb8, 0x0f, 0xbb, 0x55, 0xbd, 0x56, 0xbe, 0x00, 0xc0, 0x00, 0x00, 0x4c, 0x00, 0xdc, 0x02, 0x4a, + 0x05, 0xf0, 0x05, 0xf8, 0x06, 0x13, 0x08, 0x13, 0x0c, 0x00, 0x0e, 0x47, 0x0e, 0xf7, 0x0f, 0x00, + 0x19, 0x00, 0x20, 0x00, 0x2a, 0x01, 0x32, 0x1c, 0x36, 0x00, 0x38, 0x12, 0x3c, 0x0b, 0x45, 0x5a, + 0x56, 0x14, 0x59, 0xf0, 0x62, 0x0a, 0x69, 0x08, 0x83, 0x59, 0xae, 0x17, 0xb8, 0xf0, 0xba, 0x0f, + 0xba, 0x17, 0xf0, 0x00, 0xf6, 0x0d, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0x10, 0x04, 0xea, 0x04, 0xf6, + 0x04, 0xfc, 0x05, 0x00, 0x06, 0x00, 0x06, 0x12, 0x0a, 0x10, 0x0b, 0xf0, 0x0c, 0xf0, 0x12, 0x10, + 0x30, 0x1c, 0x33, 0x00, 0x34, 0x00, 0x38, 0x44, 0x40, 0x5c, 0x4a, 0xe4, 0x5a, 0x14, 0x62, 0x1a, + 0x64, 0x0a, 0x68, 0x08, 0x68, 0x54, 0x83, 0x55, 0x83, 0x5a, 0x91, 0x44, 0x98, 0x12, 0x9a, 0x16, + 0xa4, 0x00, 0xb0, 0x57, 0xb5, 0x00, 0xba, 0x00, 0xce, 0x45, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, + 0xec, 0x0d, 0x00, 0x54, 0x01, 0x48, 0x01, 0x58, 0x02, 0x10, 0x02, 0xe6, 0x03, 0xa1, 0x04, 0x13, + 0x05, 0xe6, 0x06, 0x0b, 0x06, 0x83, 0x06, 0xf0, 0x07, 0x00, 0x0a, 0x00, 0x0a, 0x12, 0x0a, 0xf0, + 0x0c, 0x04, 0x0c, 0x10, 0x0c, 0x12, 0x0e, 0x13, 0x10, 0x10, 0x12, 0x1c, 0x17, 0x00, 0x18, 0x0e, + 0x19, 0xe4, 0x1a, 0x10, 0x1c, 0x00, 0x1c, 0x12, 0x1c, 0x14, 0x1d, 0xf7, 0x1e, 0x13, 0x20, 0x1c, + 0x20, 0xe7, 0x22, 0x01, 0x26, 0x01, 0x2a, 0x12, 0x30, 0xe7, 0x41, 0x58, 0x43, 0x48, 0x44, 0x55, + 0x46, 0x1c, 0x4e, 0xe4, 0x5c, 0xf0, 0x72, 0x02, 0x74, 0x03, 0x77, 0x57, 0x88, 0x12, 0x89, 0x48, + 0x92, 0x13, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x32, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x12, 0xb9, 0x00, + 0xba, 0x06, 0xbf, 0x57, 0xc0, 0x01, 0xc0, 0x08, 0xc2, 0x01, 0xfe, 0x9c, 0xf0, 0x26, 0x02, 0xfe, + 0xc6, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xfc, 0xfe, 0x18, 0x19, 0x00, 0xfa, 0xfe, 0x80, 0x01, 0xff, + 0x03, 0x00, 0x00, 0x2f, 0xfe, 0x01, 0x05, 0xff, 0x40, 0x00, 0x00, 0x0d, 0xff, 0x09, 0x00, 0x00, + 0xff, 0x08, 0x01, 0x01, 0xff, 0x10, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, + 0xf7, 0xfa, 0x35, 0x51, 0x0c, 0x01, 0xfe, 0xb6, 0x0e, 0xfe, 0x04, 0xf7, 0xfa, 0x51, 0x0c, 0x1d, + 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x20, 0xf0, 0xd0, 0x04, 0x55, 0x50, 0x02, 0xfe, + 0xe2, 0x0c, 0x01, 0xfe, 0x42, 0x0d, 0xfe, 0xe9, 0x12, 0x02, 0xfe, 0x04, 0x03, 0xfe, 0x28, 0x1c, + 0x04, 0xfe, 0xa6, 0x00, 0xfe, 0xdd, 0x12, 0x4e, 0x13, 0xfe, 0xa6, 0x00, 0xc3, 0xfe, 0x48, 0xf0, + 0xfe, 0x7c, 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0x96, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xb4, 0x02, 0xfe, + 0x46, 0xf0, 0xfe, 0x46, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x3a, + 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x3e, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x42, 0x02, 0x07, 0x0c, 0x9d, + 0x07, 0x06, 0x13, 0xb8, 0x02, 0x26, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, 0x1c, 0xfe, + 0xed, 0x10, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x0e, 0x17, 0xfe, 0xe7, 0x10, 0xfe, + 0x06, 0xfc, 0xf5, 0x0e, 0x7b, 0x01, 0xc0, 0x02, 0x26, 0x17, 0x54, 0x47, 0xba, 0x01, 0xfe, 0x2c, + 0x0f, 0x0e, 0x7b, 0x01, 0x9a, 0xfe, 0xbd, 0x10, 0x0e, 0x7b, 0x01, 0x9a, 0xfe, 0xad, 0x10, 0xfe, + 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x07, 0x06, 0x13, 0xb8, 0x35, 0x1f, 0x26, 0xfe, 0x3d, 0xf0, 0xfe, + 0xf8, 0x01, 0x27, 0xfe, 0x8a, 0x02, 0xfe, 0x5a, 0x1c, 0xd5, 0xfe, 0x14, 0x1c, 0x17, 0xfe, 0x30, + 0x00, 0x47, 0xba, 0x01, 0xfe, 0x1c, 0x0f, 0x07, 0x06, 0x13, 0xb8, 0x02, 0xfc, 0x22, 0x2b, 0x05, + 0x10, 0x2f, 0xfe, 0x69, 0x10, 0x07, 0x06, 0x13, 0xb8, 0xfe, 0x04, 0xec, 0x2b, 0x08, 0x2b, 0x07, + 0x3a, 0x1d, 0x01, 0x40, 0x7f, 0xfe, 0x05, 0xf6, 0xf5, 0x01, 0xfe, 0x40, 0x16, 0x0b, 0x49, 0x89, + 0x37, 0x11, 0x43, 0x1d, 0xca, 0x08, 0x1c, 0x07, 0x3f, 0x01, 0x6a, 0x02, 0x26, 0x0e, 0x3b, 0x01, + 0x14, 0x05, 0x10, 0xd3, 0x08, 0x1c, 0x07, 0x3f, 0x01, 0x76, 0xfe, 0x28, 0x10, 0x0e, 0xbd, 0x01, + 0x14, 0xe5, 0x0e, 0x7c, 0x01, 0x14, 0xfe, 0x49, 0x54, 0x72, 0xfe, 0x12, 0x03, 0x08, 0x1c, 0x07, + 0x3f, 0x01, 0x6a, 0x02, 0x26, 0x35, 0x7f, 0xfe, 0x02, 0xe8, 0x2d, 0xf9, 0xfe, 0x9e, 0x43, 0xed, + 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xd0, 0xfe, 0x40, 0x1c, 0x1f, 0xec, 0xfe, 0x26, 0xf0, 0xfe, + 0x70, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x5e, 0x03, 0xfe, 0x11, 0xf0, 0xd0, 0xfe, 0x0e, 0x10, 0xfe, + 0x9f, 0xf0, 0xfe, 0x7e, 0x03, 0xe8, 0x12, 0xfe, 0x11, 0x00, 0x02, 0x4b, 0x35, 0xfe, 0x48, 0x1c, + 0xe8, 0x1f, 0xec, 0x33, 0xec, 0xfe, 0x82, 0xf0, 0xfe, 0x84, 0x03, 0x29, 0x22, 0xbb, 0x68, 0x16, + 0xbb, 0x0e, 0x7c, 0x01, 0x14, 0x68, 0x7d, 0x08, 0x1c, 0x07, 0x3f, 0x01, 0x40, 0x11, 0x3b, 0x08, + 0x3b, 0x07, 0x99, 0x01, 0x6a, 0xf3, 0x11, 0xfe, 0xe4, 0x00, 0x2c, 0xfe, 0xca, 0x03, 0x1f, 0x31, + 0x20, 0xfe, 0xda, 0x03, 0x01, 0x4a, 0xcb, 0xfe, 0xea, 0x03, 0x69, 0x8e, 0xcf, 0xfe, 0xaa, 0x06, + 0x02, 0x25, 0x04, 0x7b, 0x2a, 0x1b, 0xfe, 0x1c, 0x05, 0x17, 0x84, 0x01, 0x38, 0x01, 0x95, 0x01, + 0x98, 0x33, 0xfe, 0x5c, 0x02, 0x02, 0xeb, 0xe8, 0x35, 0x51, 0x18, 0xfe, 0x67, 0x1b, 0xf9, 0xed, + 0xfe, 0x48, 0x1c, 0x8b, 0x01, 0xee, 0xa8, 0xfe, 0x96, 0xf0, 0xfe, 0x24, 0x04, 0x2c, 0xfe, 0x28, + 0x04, 0x33, 0x26, 0x0e, 0x3b, 0x01, 0x14, 0x05, 0x10, 0x1b, 0xfe, 0x08, 0x05, 0x3c, 0x92, 0x9e, + 0x2d, 0x81, 0x6d, 0x1f, 0x31, 0x20, 0x25, 0x04, 0x7b, 0x2a, 0xfe, 0x10, 0x12, 0x17, 0x84, 0x01, + 0x38, 0x33, 0xfe, 0x5c, 0x02, 0x02, 0xeb, 0x30, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x5e, + 0x12, 0x0b, 0x09, 0x06, 0xfe, 0x56, 0x12, 0x23, 0x28, 0x93, 0x01, 0x0a, 0x81, 0x6d, 0x20, 0xfe, + 0xd8, 0x04, 0x23, 0x28, 0x93, 0x01, 0x0a, 0x20, 0x25, 0x23, 0x28, 0xb1, 0xfe, 0x4c, 0x44, 0xfe, + 0x32, 0x12, 0x56, 0xfe, 0x44, 0x48, 0x08, 0xd6, 0xfe, 0x4c, 0x54, 0x72, 0xfe, 0x08, 0x05, 0x7f, + 0x9e, 0x2d, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x48, 0x13, 0x3d, 0x05, 0xfe, 0xcc, 0x00, + 0xfe, 0x40, 0x13, 0x0b, 0x09, 0x06, 0x8d, 0xfe, 0x06, 0x10, 0x23, 0x28, 0xb1, 0x0b, 0x09, 0x36, + 0xdb, 0x17, 0xa2, 0x0b, 0x09, 0x06, 0x50, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x38, 0x33, 0xfe, 0x86, + 0x0c, 0x02, 0x25, 0x39, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xac, 0x03, 0x17, 0xa2, 0x01, + 0x38, 0x33, 0x26, 0x1f, 0x26, 0x02, 0xfe, 0x10, 0x05, 0xfe, 0x42, 0x5b, 0x51, 0x18, 0xfe, 0x46, + 0x59, 0xf9, 0xed, 0x17, 0x74, 0xfe, 0x07, 0x80, 0xfe, 0x31, 0x44, 0x0b, 0x09, 0x0c, 0xfe, 0x78, + 0x13, 0xfe, 0x20, 0x80, 0x05, 0x18, 0xfe, 0x70, 0x12, 0x6c, 0x09, 0x06, 0xfe, 0x60, 0x13, 0x04, + 0xfe, 0xa2, 0x00, 0x2a, 0x1b, 0xfe, 0xa8, 0x05, 0xfe, 0x31, 0xe4, 0x6f, 0x6c, 0x09, 0x0c, 0xfe, + 0x4a, 0x13, 0x04, 0xfe, 0xa0, 0x00, 0x2a, 0xfe, 0x42, 0x12, 0x59, 0x2c, 0xfe, 0x68, 0x05, 0x1f, + 0x31, 0xef, 0x01, 0x0a, 0x24, 0xfe, 0xc0, 0x05, 0x11, 0xfe, 0xe3, 0x00, 0x29, 0x6c, 0xfe, 0x4a, + 0xf0, 0xfe, 0x92, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x8c, 0x05, 0xd1, 0x21, 0xfe, 0x21, 0x00, 0xa4, + 0x21, 0xfe, 0x22, 0x00, 0x9d, 0x21, 0x89, 0xfe, 0x09, 0x48, 0x01, 0x0a, 0x24, 0xfe, 0xc0, 0x05, + 0xfe, 0xe2, 0x08, 0x6c, 0x09, 0xda, 0x50, 0x01, 0xb6, 0x21, 0x06, 0x16, 0xe2, 0x47, 0xfe, 0x27, + 0x01, 0x0b, 0x09, 0x36, 0xe3, 0x4e, 0x01, 0xae, 0x17, 0xa2, 0x0b, 0x09, 0x06, 0x50, 0x17, 0xfe, + 0x0d, 0x00, 0x01, 0x38, 0x01, 0x95, 0x01, 0x98, 0x33, 0xfe, 0x86, 0x0c, 0x02, 0x25, 0x04, 0xfe, + 0x9c, 0x00, 0x2a, 0xfe, 0x3e, 0x12, 0x04, 0x52, 0x2a, 0xfe, 0x36, 0x13, 0x4e, 0x01, 0xae, 0x24, + 0xfe, 0x38, 0x06, 0x0e, 0x06, 0x6c, 0x09, 0x19, 0xfe, 0x02, 0x12, 0x79, 0x01, 0xfe, 0xf0, 0x13, + 0x20, 0xfe, 0x2e, 0x06, 0x11, 0xbe, 0x01, 0x4a, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x52, 0xb9, 0x0f, + 0x52, 0x04, 0xf4, 0x2a, 0xfe, 0x62, 0x12, 0x04, 0x4d, 0x2a, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x60, + 0x18, 0x01, 0xfe, 0xb2, 0x18, 0xe6, 0xc8, 0x19, 0x08, 0x61, 0xff, 0x02, 0x00, 0x57, 0x64, 0x7e, + 0x1a, 0x4f, 0xc7, 0xc8, 0x87, 0x4e, 0x01, 0xae, 0x24, 0xfe, 0xa2, 0x06, 0x6c, 0x09, 0x1e, 0xa3, + 0x7a, 0x0e, 0x54, 0x01, 0xfe, 0x1e, 0x14, 0x20, 0xfe, 0x98, 0x06, 0x11, 0xbe, 0x01, 0x4a, 0x11, + 0xfe, 0xe5, 0x00, 0x04, 0x4d, 0xb9, 0x0f, 0x4d, 0x07, 0x06, 0x01, 0xae, 0xf3, 0x71, 0x8b, 0x01, + 0xee, 0xa8, 0x11, 0xfe, 0xe2, 0x00, 0x2c, 0xf8, 0x1f, 0x31, 0xcf, 0xfe, 0xd6, 0x06, 0x80, 0xfe, + 0x74, 0x07, 0xcb, 0xfe, 0x7c, 0x07, 0x69, 0x8e, 0x02, 0x25, 0x0b, 0x09, 0x0c, 0xfe, 0x2e, 0x12, + 0x15, 0x18, 0x01, 0x0a, 0x15, 0x00, 0x01, 0x0a, 0x15, 0x00, 0x01, 0x0a, 0x15, 0x00, 0x01, 0x0a, + 0xfe, 0x99, 0xa4, 0x01, 0x0a, 0x15, 0x00, 0x02, 0xfe, 0x3a, 0x08, 0x66, 0x09, 0x1e, 0x8d, 0x0b, + 0x09, 0x1e, 0xfe, 0x30, 0x13, 0x15, 0xfe, 0x1b, 0x00, 0x01, 0x0a, 0x15, 0x00, 0x01, 0x0a, 0x15, + 0x00, 0x01, 0x0a, 0x15, 0x00, 0x01, 0x0a, 0x15, 0x06, 0x01, 0x0a, 0x15, 0x00, 0x02, 0xc9, 0x79, + 0xfe, 0x9a, 0x81, 0x65, 0x89, 0xfe, 0x09, 0x6f, 0xfe, 0x93, 0x45, 0x1b, 0xfe, 0x84, 0x07, 0x2c, + 0xfe, 0x5c, 0x07, 0x1f, 0x31, 0xcf, 0xfe, 0x54, 0x07, 0x69, 0x8e, 0x80, 0xfe, 0x74, 0x07, 0x02, + 0x25, 0x01, 0x4a, 0x02, 0xf8, 0x15, 0x19, 0x02, 0xf8, 0xfe, 0x9c, 0xf7, 0xfe, 0xf0, 0x07, 0xfe, + 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x73, 0xfe, 0xd2, 0x07, 0x0f, 0x5c, 0x13, 0x5d, 0x0b, 0x49, 0x6f, + 0x37, 0x01, 0xfe, 0xf6, 0x17, 0x05, 0x10, 0x82, 0xfe, 0x83, 0xe7, 0x88, 0xa4, 0xfe, 0x03, 0x40, + 0x0b, 0x49, 0x74, 0x37, 0x01, 0xb7, 0xab, 0xfe, 0x1f, 0x40, 0x16, 0x60, 0x01, 0xf6, 0xfe, 0x08, + 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x34, 0x51, 0xfe, 0xb6, 0x51, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, + 0x0f, 0x5a, 0x13, 0x5b, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, + 0x0f, 0x41, 0x13, 0x42, 0xfe, 0x4a, 0x10, 0x0b, 0x09, 0x6f, 0xe3, 0xfe, 0x2c, 0x90, 0xfe, 0xae, + 0x90, 0x0f, 0x5c, 0x13, 0x5d, 0x0b, 0x09, 0x74, 0xc7, 0x01, 0xb7, 0xfe, 0x1f, 0x80, 0x16, 0x60, + 0xfe, 0x34, 0x90, 0xfe, 0xb6, 0x90, 0x0f, 0x5e, 0x13, 0x5f, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, + 0x0f, 0x5a, 0x13, 0x5b, 0xfe, 0x28, 0x90, 0xfe, 0xaa, 0x90, 0x0f, 0x41, 0x13, 0x42, 0x0f, 0x3e, + 0x13, 0x57, 0x0b, 0x49, 0x19, 0x37, 0x35, 0x08, 0xa1, 0x2c, 0xfe, 0x50, 0x08, 0xfe, 0x9e, 0xf0, + 0xfe, 0x64, 0x08, 0xc2, 0x1b, 0x31, 0x35, 0x6b, 0xfe, 0xed, 0x10, 0xa5, 0xfe, 0x88, 0x08, 0xa6, + 0xfe, 0xa4, 0x08, 0x80, 0xfe, 0x7c, 0x08, 0xcb, 0xfe, 0x82, 0x08, 0x69, 0x8e, 0x02, 0x25, 0x01, + 0x4a, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x66, 0x09, 0x06, 0xfe, 0x10, 0x12, 0x66, + 0x09, 0x0c, 0x48, 0x0b, 0x09, 0x0c, 0xfe, 0x66, 0x12, 0xfe, 0x2e, 0x1c, 0xa7, 0x66, 0x09, 0x06, + 0x48, 0x66, 0x09, 0x0c, 0xfe, 0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x24, 0x09, + 0xfe, 0xac, 0xf0, 0xfe, 0xc4, 0x08, 0xfe, 0x92, 0x10, 0xfe, 0x34, 0x1c, 0xfe, 0xf3, 0x10, 0xfe, + 0xad, 0xf0, 0xfe, 0xd0, 0x08, 0x02, 0xfe, 0x32, 0x0a, 0xfe, 0x36, 0x1c, 0xfe, 0xe7, 0x10, 0xfe, + 0x2b, 0xf0, 0xb0, 0xfe, 0x6b, 0x18, 0x1a, 0xfe, 0x00, 0xfe, 0xdb, 0xc3, 0xfe, 0xd2, 0xf0, 0xb0, + 0xfe, 0x76, 0x18, 0x1a, 0x18, 0x1b, 0xb0, 0x04, 0xe1, 0x1a, 0x06, 0x1b, 0xb0, 0xa5, 0x77, 0xa6, + 0x77, 0xfe, 0x34, 0x1c, 0xfe, 0x36, 0x1c, 0xfe, 0xb1, 0x10, 0x8b, 0x59, 0x39, 0x17, 0xa2, 0x01, + 0x38, 0x12, 0xfe, 0x35, 0x00, 0x33, 0x4b, 0x12, 0x8c, 0x02, 0x4b, 0xfe, 0x74, 0x18, 0x1a, 0xfe, + 0x00, 0xf8, 0x1b, 0x77, 0x51, 0x1e, 0x01, 0xfe, 0x42, 0x0d, 0xd2, 0x08, 0x1c, 0x07, 0x3f, 0x01, + 0x6a, 0x22, 0x2d, 0x3c, 0x51, 0x18, 0x02, 0x77, 0xfe, 0x98, 0x80, 0xd8, 0x0c, 0x27, 0xfe, 0x14, + 0x0a, 0x0b, 0x09, 0x6f, 0xfe, 0x82, 0x12, 0x0b, 0x09, 0x19, 0xfe, 0x66, 0x13, 0x22, 0x60, 0x68, + 0xc6, 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, + 0x62, 0x2d, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x73, 0xfb, 0x04, 0x5c, 0x2e, 0x5d, 0x0f, 0xaa, + 0x13, 0x8c, 0x9b, 0x5c, 0x9c, 0x5d, 0x01, 0xb7, 0xab, 0x62, 0x2d, 0x16, 0x60, 0xa0, 0x3e, 0x67, + 0x57, 0x63, 0x5e, 0x30, 0x5f, 0xe7, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x3e, 0xfe, 0x05, 0xfa, + 0x57, 0x01, 0xf6, 0xfe, 0x36, 0x10, 0x29, 0x0f, 0xaa, 0x0f, 0x8c, 0x63, 0x5e, 0x30, 0x5f, 0xa7, + 0x0b, 0x09, 0x19, 0x1b, 0xfb, 0x63, 0x41, 0x30, 0x42, 0x0b, 0x09, 0xfe, 0xf7, 0x00, 0x37, 0x04, + 0x5a, 0x2e, 0x5b, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, + 0x77, 0x0b, 0x09, 0x19, 0x1b, 0xfb, 0x0b, 0x09, 0xfe, 0xf7, 0x00, 0x37, 0xfe, 0x3a, 0x55, 0xfe, + 0x19, 0x81, 0x79, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x3d, 0x05, 0xbf, 0x1b, + 0xfe, 0xcc, 0x08, 0x11, 0xbf, 0xfe, 0x98, 0x80, 0xd8, 0x0c, 0xfe, 0x14, 0x13, 0x04, 0x41, 0x2e, + 0x42, 0x73, 0xfe, 0xcc, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x77, 0x29, 0x4e, 0xfe, + 0x19, 0x80, 0xfe, 0xf1, 0x10, 0x0b, 0x09, 0x0c, 0xa3, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xfe, + 0x94, 0x10, 0xfe, 0x6c, 0x19, 0x9b, 0x41, 0xfe, 0xed, 0x19, 0x9c, 0x42, 0xfe, 0x0c, 0x51, 0xfe, + 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x1a, 0xfe, 0x00, 0xff, 0x2f, 0xfe, 0x7a, 0x10, 0xc3, 0xfe, 0xd2, + 0xf0, 0xfe, 0xac, 0x0a, 0xfe, 0x76, 0x18, 0x1a, 0x18, 0xce, 0x04, 0xe1, 0x1a, 0x06, 0x83, 0x12, + 0xfe, 0x16, 0x00, 0x02, 0x4b, 0xfe, 0xd1, 0xf0, 0xfe, 0xe2, 0x0a, 0x17, 0xa1, 0x01, 0x38, 0x12, + 0xd6, 0xfe, 0x48, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca, 0x0a, 0x12, 0xfe, 0x21, 0x00, 0x02, 0x4b, + 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x12, 0xfe, 0x22, 0x00, 0x02, 0x4b, 0xfe, 0xcb, 0xf0, 0xfe, + 0xe2, 0x0a, 0x12, 0xfe, 0x24, 0x00, 0x02, 0x4b, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x12, 0x88, + 0xd9, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x12, 0x89, 0xd4, 0xfe, 0xcc, 0xf0, 0xc9, 0xfe, 0x84, + 0x80, 0xd8, 0x19, 0xfe, 0xd5, 0x12, 0x12, 0xfe, 0x12, 0x00, 0x2c, 0xc9, 0x1f, 0x31, 0xa5, 0x25, + 0xa6, 0x25, 0x35, 0xf3, 0x2c, 0xfe, 0x1a, 0x0b, 0x1f, 0x31, 0x80, 0xfe, 0x36, 0x0b, 0x69, 0x8e, + 0xa5, 0xfe, 0xf0, 0x07, 0xa6, 0xfe, 0xf0, 0x07, 0x02, 0x25, 0x01, 0x4a, 0xfe, 0xdb, 0x10, 0x11, + 0xfe, 0xe8, 0x00, 0x8b, 0x81, 0x6d, 0xfe, 0x89, 0xf0, 0x25, 0x23, 0x28, 0xfe, 0xe9, 0x09, 0x01, + 0x0a, 0x81, 0x6d, 0x20, 0x25, 0x23, 0x28, 0x93, 0x33, 0xfe, 0x6e, 0x0b, 0x1f, 0x31, 0x02, 0xfe, + 0x62, 0x0b, 0xc2, 0x48, 0x12, 0xfe, 0x42, 0x00, 0x02, 0x4b, 0x9f, 0x06, 0xfe, 0x81, 0x49, 0xfe, + 0xcc, 0x12, 0x0b, 0x09, 0x0c, 0xfe, 0x5a, 0x13, 0x12, 0x00, 0x58, 0x0c, 0xfe, 0x6a, 0x12, 0x58, + 0xfe, 0x28, 0x00, 0x27, 0xfe, 0xb4, 0x0c, 0x0e, 0x7c, 0x01, 0x14, 0x05, 0x00, 0x83, 0x34, 0xfe, + 0x28, 0x00, 0x02, 0xfe, 0xb4, 0x0c, 0x01, 0x95, 0x01, 0x98, 0x0e, 0xbd, 0x01, 0xfe, 0x10, 0x0e, + 0xaf, 0x08, 0x3b, 0x07, 0x99, 0x01, 0x40, 0x11, 0x43, 0x08, 0x1c, 0x07, 0x3f, 0x01, 0x76, 0x02, + 0x26, 0x12, 0xfe, 0x44, 0x00, 0x58, 0x0c, 0xa3, 0x34, 0x0c, 0xfe, 0xc0, 0x10, 0x01, 0xb6, 0x34, + 0x0c, 0xfe, 0xb6, 0x10, 0x01, 0xb6, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xfe, 0x0a, 0x13, 0x34, + 0x0c, 0x12, 0xfe, 0x43, 0x00, 0xfe, 0xa2, 0x10, 0x0b, 0x49, 0x0c, 0x37, 0x01, 0x95, 0x01, 0x98, + 0xaf, 0x08, 0x3b, 0x07, 0x99, 0x01, 0x40, 0x11, 0x43, 0x08, 0x1c, 0x07, 0x3f, 0x01, 0x76, 0x51, + 0x0c, 0xaf, 0x1d, 0xca, 0x02, 0xfe, 0x48, 0x03, 0x0b, 0x09, 0x0c, 0xce, 0x34, 0x0c, 0x12, 0x00, + 0xfe, 0x54, 0x10, 0x66, 0x09, 0x1e, 0xfe, 0x50, 0x12, 0x0b, 0x09, 0x1e, 0xfe, 0x48, 0x13, 0xfe, + 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x72, 0x0c, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x78, + 0x0c, 0x0b, 0x49, 0x1e, 0x37, 0xfe, 0x95, 0x10, 0x12, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0c, + 0x79, 0xfe, 0x26, 0x10, 0x12, 0xfe, 0x13, 0x00, 0xd4, 0x12, 0xfe, 0x47, 0x00, 0xa4, 0x12, 0xfe, + 0x41, 0x00, 0x9d, 0x12, 0xfe, 0x24, 0x00, 0x04, 0x7b, 0x2a, 0x27, 0xeb, 0x79, 0xfe, 0x04, 0xe6, + 0x1e, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0xaf, 0x01, 0xd7, 0x02, 0x26, 0xd5, 0x17, 0x0c, 0x47, + 0xf2, 0xdf, 0x17, 0xfe, 0x31, 0x00, 0x47, 0xba, 0x01, 0xfe, 0x1c, 0x0f, 0x02, 0xfc, 0x1d, 0xfe, + 0x06, 0xec, 0xf7, 0x85, 0x34, 0x36, 0xbc, 0x2f, 0x1d, 0xfe, 0x06, 0xea, 0xf7, 0xfe, 0x47, 0x4b, + 0x7a, 0xfe, 0x75, 0x57, 0x04, 0x55, 0xfe, 0x98, 0x56, 0xfe, 0x28, 0x12, 0x0e, 0x7c, 0xfe, 0xfa, + 0x14, 0x4e, 0xe5, 0x0e, 0xbd, 0xfe, 0xf0, 0x14, 0xfe, 0x49, 0x54, 0x91, 0xfe, 0x28, 0x0d, 0x0e, + 0x1c, 0xfe, 0xe4, 0x14, 0xfe, 0x44, 0x48, 0x02, 0xfe, 0x48, 0x03, 0x0e, 0x55, 0xfe, 0xc8, 0x14, + 0x85, 0x34, 0x36, 0xbc, 0x2f, 0x1d, 0xfe, 0xce, 0x47, 0xfe, 0xbd, 0x13, 0x02, 0x26, 0x22, 0x2b, + 0x05, 0x10, 0xfe, 0x78, 0x12, 0x29, 0x16, 0x54, 0x16, 0xa9, 0x22, 0x43, 0x4e, 0x47, 0x43, 0xc2, + 0xfe, 0x0c, 0x13, 0xfe, 0xbc, 0xf0, 0xfe, 0xc4, 0x0d, 0x08, 0x06, 0x16, 0x54, 0x01, 0xfe, 0xd0, + 0x15, 0x04, 0xfe, 0x38, 0x01, 0x2e, 0xfe, 0x3a, 0x01, 0x73, 0xfe, 0xc8, 0x0d, 0x04, 0xfe, 0x38, + 0x01, 0x1a, 0xfe, 0xf0, 0xff, 0x0f, 0xfe, 0x60, 0x01, 0x04, 0xfe, 0x3a, 0x01, 0x0f, 0xfe, 0x62, + 0x01, 0x21, 0x06, 0x16, 0x43, 0xfe, 0x04, 0xec, 0x2b, 0x08, 0x2b, 0x07, 0x3a, 0x1d, 0x01, 0x40, + 0x7f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x40, 0x16, 0x11, 0x43, 0xca, 0x08, 0x06, + 0x03, 0x29, 0x03, 0x22, 0x54, 0xfe, 0xf7, 0x12, 0x22, 0xa9, 0x68, 0x16, 0xa9, 0x05, 0xa1, 0xfe, + 0x93, 0x13, 0xfe, 0x24, 0x1c, 0x17, 0x18, 0x47, 0xf2, 0xdf, 0xfe, 0xd9, 0x10, 0x94, 0xfe, 0x03, + 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0x94, 0xfe, 0x03, 0xdc, 0x29, 0xfe, 0x70, 0x57, + 0xfe, 0x33, 0x54, 0xfe, 0x3b, 0x54, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0x94, 0x29, 0xfe, + 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0x94, 0x7d, 0x03, 0x01, 0xfe, 0x70, 0x16, 0x3d, 0x05, 0x43, + 0xfe, 0x0a, 0x13, 0x08, 0x1c, 0x07, 0x3f, 0xd4, 0x01, 0x95, 0x01, 0x98, 0x08, 0x3b, 0x07, 0x99, + 0x01, 0x40, 0x11, 0xfe, 0xe9, 0x00, 0x0b, 0x09, 0x89, 0xfe, 0x52, 0x13, 0x01, 0xfe, 0x02, 0x16, + 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0x0f, 0xfe, 0x64, 0x01, 0xfe, 0x16, 0x90, 0x0f, 0xfe, 0x66, + 0x01, 0x0b, 0x09, 0x74, 0x8d, 0xfe, 0x03, 0x80, 0x6b, 0x3c, 0x11, 0x75, 0x08, 0x2b, 0x07, 0x3a, + 0x1d, 0x92, 0x01, 0x6a, 0xfe, 0x62, 0x08, 0x68, 0x3c, 0x11, 0x75, 0x08, 0x2b, 0x07, 0x3a, 0x1d, + 0x92, 0x01, 0x6a, 0x62, 0x2d, 0x11, 0x75, 0x08, 0x2b, 0x07, 0x3a, 0x1d, 0x92, 0x01, 0x76, 0x03, + 0xfe, 0x08, 0x1c, 0x04, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x04, 0xfe, 0xae, 0x00, 0xfe, 0x07, + 0x58, 0x04, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x04, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, + 0x0a, 0x1c, 0x21, 0x87, 0x16, 0xf7, 0x29, 0x0f, 0x52, 0x0f, 0x4d, 0x21, 0x10, 0x16, 0x2b, 0x16, + 0x3a, 0x56, 0x9f, 0xd6, 0x08, 0x2b, 0x07, 0x3a, 0x1d, 0x01, 0x76, 0x7f, 0x11, 0x75, 0xfe, 0x14, + 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xf6, 0x0e, 0xd5, 0x8b, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, + 0x18, 0x1c, 0x03, 0x1d, 0xfe, 0x0c, 0x14, 0x85, 0xfe, 0x07, 0xe6, 0x36, 0xfe, 0xce, 0x47, 0xfe, + 0xf5, 0x13, 0x03, 0x01, 0xb6, 0x0e, 0x3b, 0x01, 0x14, 0x05, 0x10, 0xd3, 0x0e, 0x1c, 0x01, 0x14, + 0x05, 0x10, 0xdb, 0xfe, 0x44, 0x58, 0x3c, 0xfe, 0x01, 0xec, 0xba, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, + 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1e, 0x9e, 0x2d, 0x01, 0xd7, 0xfe, 0xc9, 0x10, 0x03, 0x35, 0x81, + 0x6d, 0x23, 0x28, 0xb1, 0x05, 0x1e, 0xfe, 0x48, 0x12, 0x05, 0x0c, 0xfe, 0x4c, 0x12, 0x05, 0x18, + 0x38, 0x05, 0xcc, 0x1b, 0xfe, 0xc0, 0x10, 0x05, 0xfe, 0x23, 0x00, 0x1b, 0xfe, 0xcc, 0x10, 0x05, + 0x06, 0x1b, 0xfe, 0x2a, 0x11, 0x05, 0x19, 0xfe, 0x12, 0x12, 0x05, 0x00, 0x1b, 0x25, 0x17, 0xcc, + 0x01, 0x38, 0xc4, 0x39, 0x01, 0x0a, 0x80, 0x4a, 0x03, 0x39, 0x11, 0xfe, 0xcc, 0x00, 0x02, 0x26, + 0x39, 0x3d, 0x05, 0xbf, 0xfe, 0xe3, 0x13, 0x63, 0x41, 0x30, 0x42, 0x73, 0xfe, 0x7e, 0x10, 0x0b, + 0x09, 0x6f, 0xfe, 0x72, 0x12, 0xa0, 0x3e, 0x67, 0x57, 0xe7, 0xfe, 0xe5, 0x55, 0x91, 0xfe, 0x48, + 0x10, 0x22, 0x60, 0xfe, 0x26, 0x13, 0x04, 0xaa, 0x2e, 0x8c, 0x73, 0xfe, 0x98, 0x0c, 0x0f, 0x5c, + 0x13, 0x5d, 0x29, 0x0f, 0xaa, 0x0f, 0x8c, 0x01, 0xb7, 0x21, 0x87, 0x6b, 0x16, 0x60, 0x01, 0xf6, + 0xa0, 0x3e, 0x67, 0x57, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x3e, 0xfe, 0x05, + 0xfa, 0x57, 0xfe, 0x91, 0x10, 0x04, 0x5e, 0x2e, 0x5f, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0f, + 0x5e, 0x13, 0x5f, 0xd1, 0xa0, 0x3e, 0x67, 0x57, 0xe7, 0xfe, 0xe5, 0x55, 0x04, 0x5a, 0x2e, 0x5b, + 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0f, 0x5a, 0x13, 0x5b, 0x0b, 0x09, 0x6f, 0xfe, 0x1e, 0x12, + 0x22, 0x60, 0xfe, 0x1f, 0x40, 0x04, 0x5c, 0x2e, 0x5d, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x04, + 0x5e, 0x2e, 0x5f, 0xfe, 0x34, 0x50, 0xfe, 0xb6, 0x50, 0x04, 0x5a, 0x2e, 0x5b, 0xfe, 0x08, 0x50, + 0xfe, 0x8a, 0x50, 0x04, 0x41, 0x2e, 0x42, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x02, 0x97, 0x21, + 0x06, 0x16, 0xf1, 0x02, 0x78, 0x39, 0x01, 0x0a, 0x20, 0x4c, 0x23, 0x28, 0xb1, 0x05, 0x06, 0x27, + 0x4c, 0x3d, 0x05, 0xbf, 0x27, 0x78, 0x01, 0xee, 0x1a, 0x4f, 0x1b, 0x4c, 0x0b, 0x09, 0x0c, 0xde, + 0x63, 0x41, 0x30, 0x42, 0xfe, 0x0a, 0x55, 0x2f, 0xfe, 0x8b, 0x55, 0x9b, 0x41, 0x9c, 0x42, 0xfe, + 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x78, 0xfe, 0x19, 0x81, 0xfe, 0x0a, 0x45, 0xfe, 0x19, 0x41, + 0x02, 0x78, 0x39, 0x01, 0x0a, 0x20, 0xfe, 0xc2, 0x0f, 0x23, 0x28, 0xfe, 0xe9, 0x09, 0x58, 0x18, + 0xfe, 0x94, 0x12, 0x58, 0x0c, 0x50, 0x02, 0x4c, 0x2c, 0xfe, 0x4a, 0x11, 0x1f, 0x31, 0x20, 0xfe, + 0xc2, 0x0f, 0x23, 0x28, 0x93, 0x05, 0x18, 0x27, 0x4c, 0x01, 0x0a, 0x20, 0xfe, 0xc2, 0x0f, 0x23, + 0x28, 0xfe, 0xe8, 0x09, 0x56, 0x04, 0xfe, 0x9c, 0x00, 0x2a, 0x2f, 0xfe, 0xbb, 0x45, 0x58, 0x00, + 0x48, 0x34, 0x06, 0x9f, 0x4f, 0xfe, 0xc0, 0x14, 0xfe, 0xf8, 0x14, 0xa8, 0x3d, 0x05, 0xbe, 0xfe, + 0x16, 0x13, 0x04, 0xf4, 0x2a, 0xce, 0x04, 0x4d, 0x2a, 0x2f, 0x59, 0x02, 0x78, 0xfe, 0xc0, 0x5d, + 0xfe, 0xe4, 0x14, 0xfe, 0x03, 0x17, 0x04, 0x52, 0xb9, 0x0f, 0x52, 0x59, 0x39, 0x01, 0x0a, 0x24, + 0x97, 0x01, 0xfe, 0xf0, 0x13, 0x02, 0x97, 0x2c, 0xfe, 0xd4, 0x11, 0x1f, 0x31, 0x20, 0x4c, 0x23, + 0x28, 0x93, 0x05, 0x06, 0x27, 0x4c, 0xfe, 0xf6, 0x14, 0xfe, 0x42, 0x58, 0xfe, 0x70, 0x14, 0xfe, + 0x92, 0x14, 0xa8, 0xfe, 0x4a, 0xf4, 0x0c, 0x1b, 0x4c, 0xfe, 0x4a, 0xf4, 0x06, 0xd2, 0x3d, 0x05, + 0xbe, 0xc7, 0x02, 0x78, 0x04, 0x4d, 0xb9, 0x0f, 0x4d, 0x59, 0x39, 0x01, 0x0a, 0x24, 0x97, 0x01, + 0xfe, 0x1e, 0x14, 0x02, 0x97, 0x24, 0xfe, 0x3c, 0x12, 0x71, 0xef, 0x71, 0x03, 0x33, 0x8d, 0x69, + 0x8d, 0x59, 0x39, 0x01, 0x0a, 0xfe, 0xe3, 0x10, 0x08, 0x61, 0xff, 0x02, 0x00, 0x57, 0x64, 0x7e, + 0x1a, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x61, 0xff, 0x02, 0x00, + 0x57, 0x64, 0x7e, 0x1a, 0x4f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x61, 0xff, 0x02, + 0x00, 0x57, 0x64, 0x7e, 0x03, 0x08, 0x61, 0xff, 0x02, 0x00, 0x57, 0x64, 0x7e, 0xfe, 0x0b, 0x58, + 0x03, 0x0e, 0x52, 0x01, 0x9a, 0x0e, 0x4d, 0x01, 0x9a, 0x03, 0xc6, 0x1a, 0x10, 0xff, 0x03, 0x00, + 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x64, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, + 0x03, 0x7c, 0x62, 0x2d, 0x0f, 0x5a, 0x13, 0x5b, 0x9b, 0x5e, 0x9c, 0x5f, 0x03, 0xfe, 0x62, 0x18, + 0xfe, 0x82, 0x5a, 0xfe, 0xe1, 0x1a, 0xb4, 0xfe, 0x02, 0x58, 0x03, 0x01, 0xfe, 0x60, 0x18, 0xfe, + 0x42, 0x48, 0x79, 0x56, 0x7a, 0x01, 0x0a, 0x20, 0xfe, 0xe8, 0x13, 0x23, 0x28, 0xfe, 0xe9, 0x09, + 0xfe, 0xc1, 0x59, 0x01, 0x0a, 0x20, 0xfe, 0xe8, 0x13, 0x23, 0x28, 0xfe, 0xe8, 0x0a, 0x04, 0xf4, + 0x2a, 0xfe, 0xc2, 0x12, 0x29, 0xad, 0x1e, 0xde, 0x58, 0xcd, 0x72, 0xfe, 0x38, 0x13, 0x50, 0x08, + 0x06, 0x07, 0xcd, 0x9f, 0xfe, 0x00, 0x10, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa4, 0xff, + 0x02, 0x83, 0x55, 0xad, 0x18, 0xfe, 0x12, 0x13, 0x70, 0xfe, 0x30, 0x00, 0x91, 0xf0, 0x07, 0x84, + 0x08, 0x06, 0xfe, 0x56, 0x10, 0xad, 0x0c, 0xfe, 0x16, 0x13, 0x70, 0xfe, 0x64, 0x00, 0x91, 0xf0, + 0x0e, 0xfe, 0x64, 0x00, 0x07, 0x88, 0x08, 0x06, 0xfe, 0x28, 0x10, 0xad, 0x06, 0xfe, 0x5e, 0x13, + 0x70, 0xfe, 0xc8, 0x00, 0x91, 0xf0, 0x0e, 0xfe, 0xc8, 0x00, 0x07, 0x54, 0x08, 0x06, 0xd1, 0x70, + 0xfe, 0x90, 0x01, 0xea, 0xfe, 0x9e, 0x13, 0x7a, 0xa7, 0xfe, 0x43, 0xf4, 0xa9, 0xfe, 0x56, 0xf0, + 0xfe, 0xb0, 0x13, 0xfe, 0x04, 0xf4, 0x61, 0xfe, 0x43, 0xf4, 0x88, 0xfe, 0xf3, 0x10, 0xac, 0x01, + 0xfe, 0x7a, 0x12, 0x1a, 0x4f, 0xd3, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x87, 0xea, 0xfe, 0xe2, + 0x13, 0x7a, 0xfe, 0x14, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xea, 0xfe, 0xe2, 0x13, + 0xc8, 0x19, 0x9d, 0x56, 0x7a, 0x08, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x03, 0x56, 0x08, + 0x0c, 0x03, 0x15, 0x06, 0x01, 0x0a, 0x24, 0xdc, 0x15, 0x0c, 0x01, 0x0a, 0x24, 0xdc, 0x15, 0x18, + 0x01, 0x0a, 0x24, 0xdc, 0x71, 0xfe, 0x89, 0x49, 0x01, 0x0a, 0x03, 0x15, 0x06, 0x01, 0x0a, 0x24, + 0x90, 0x15, 0x18, 0x01, 0x0a, 0x24, 0x90, 0x15, 0x06, 0x01, 0x0a, 0x24, 0x90, 0xfe, 0x89, 0x49, + 0x01, 0x0a, 0x24, 0x90, 0x71, 0xfe, 0x89, 0x4a, 0x01, 0x0a, 0x03, 0x56, 0x03, 0x22, 0xe2, 0x05, + 0x06, 0xfe, 0x44, 0x13, 0xab, 0x16, 0xe2, 0xfe, 0x49, 0xf4, 0x00, 0x50, 0x71, 0xc4, 0x59, 0xfe, + 0x01, 0xec, 0xfe, 0x27, 0x01, 0xef, 0x01, 0x0a, 0x3d, 0x05, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, + 0x20, 0xfe, 0xa0, 0x14, 0x29, 0x16, 0xf1, 0x01, 0x4a, 0x22, 0xf1, 0x05, 0x06, 0x48, 0x0b, 0x49, + 0x06, 0x37, 0x03, 0x0f, 0x53, 0x13, 0x8a, 0xfe, 0x43, 0x58, 0x01, 0x14, 0x05, 0x10, 0xfe, 0x1e, + 0x12, 0x45, 0xe6, 0x8f, 0x01, 0x44, 0xfe, 0x90, 0x4d, 0xe0, 0x10, 0xfe, 0xc5, 0x59, 0x01, 0x44, + 0xfe, 0x8d, 0x56, 0xb4, 0x45, 0x03, 0x45, 0x30, 0x8a, 0x01, 0x14, 0x45, 0x8f, 0x01, 0x44, 0xe4, + 0x10, 0xe0, 0x10, 0x30, 0x53, 0x70, 0x1c, 0x83, 0x0e, 0x55, 0x01, 0xc0, 0x03, 0x0f, 0x53, 0x13, + 0x8a, 0xfe, 0xc3, 0x58, 0x01, 0x14, 0x05, 0x10, 0xfe, 0x1a, 0x12, 0x45, 0xe6, 0x8f, 0x01, 0x44, + 0xe4, 0x10, 0xfe, 0x80, 0x4d, 0xfe, 0xc5, 0x59, 0x01, 0x44, 0x45, 0x03, 0x45, 0x30, 0x53, 0x01, + 0x14, 0x45, 0x8f, 0x01, 0x44, 0xe4, 0x10, 0xe0, 0x10, 0x30, 0x53, 0x70, 0x1c, 0x83, 0x0e, 0x55, + 0x01, 0xc0, 0x03, 0x0f, 0x53, 0x13, 0x8a, 0xfe, 0x43, 0x58, 0x01, 0x14, 0xfe, 0x42, 0x48, 0x8f, + 0x01, 0x44, 0xfe, 0xc0, 0x5a, 0xac, 0xfe, 0x00, 0xcd, 0xfe, 0x01, 0xcc, 0xfe, 0x4a, 0x46, 0xde, + 0x94, 0x7d, 0x05, 0x10, 0xfe, 0x2e, 0x13, 0x67, 0x53, 0xfe, 0x4d, 0xf4, 0x1c, 0xfe, 0x1c, 0x13, + 0x0e, 0x55, 0x01, 0x9a, 0xa7, 0xfe, 0x40, 0x4c, 0xfe, 0xc5, 0x58, 0x01, 0x44, 0xfe, 0x00, 0x07, + 0x7d, 0x05, 0x10, 0x83, 0x67, 0x8a, 0xfe, 0x05, 0x57, 0xfe, 0x08, 0x10, 0xfe, 0x45, 0x58, 0x01, + 0x44, 0xfe, 0x8d, 0x56, 0xb4, 0xfe, 0x80, 0x4c, 0xfe, 0x05, 0x17, 0x03, 0x07, 0x10, 0x6e, 0x65, + 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xdd, 0x36, 0x96, 0xfe, + 0xe4, 0x15, 0x01, 0xfe, 0xea, 0x16, 0xfe, 0x0c, 0x13, 0x86, 0x36, 0x65, 0xfe, 0x2c, 0x01, 0xfe, + 0x2f, 0x19, 0x03, 0xb5, 0x27, 0xfe, 0xd4, 0x15, 0xfe, 0xda, 0x10, 0x07, 0x10, 0x6e, 0x04, 0xfe, + 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58, 0x04, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, + 0x86, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x65, 0xfe, 0x38, 0x00, + 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x96, 0xfe, 0x2e, 0x16, 0xfe, 0xb6, 0x14, 0x2f, 0x03, + 0xb5, 0x27, 0xfe, 0x06, 0x16, 0xfe, 0x9c, 0x10, 0x07, 0x10, 0x6e, 0xb4, 0xfe, 0x18, 0xdf, 0xfe, + 0x19, 0xdf, 0xdd, 0x3e, 0x96, 0xfe, 0x50, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10, 0x13, 0x86, 0x3e, + 0x65, 0x1e, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x03, 0xb5, 0x27, 0xfe, 0x44, 0x16, 0xfe, + 0x6c, 0x10, 0x07, 0x10, 0x6e, 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x86, 0xda, 0x65, 0x1e, 0xfe, + 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xda, 0x96, 0xfe, 0x88, 0x16, 0xfe, 0x5c, 0x14, 0x2f, 0x03, 0xb5, + 0x27, 0xfe, 0x74, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x10, 0x6e, 0xfe, 0x18, 0xfe, 0x5c, + 0xfe, 0x19, 0xfe, 0x5d, 0xc6, 0xdd, 0x74, 0x96, 0xfe, 0xae, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, + 0x13, 0x86, 0x74, 0x4e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, + 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x62, 0x2d, 0x03, 0x62, 0x2d, 0xfe, 0x12, 0x45, 0x27, 0xfe, + 0x9e, 0x16, 0x17, 0x06, 0x47, 0xf2, 0xdf, 0x02, 0x26, 0xfe, 0x39, 0xf0, 0xfe, 0xf2, 0x16, 0x29, + 0x03, 0xfe, 0x7e, 0x18, 0x1a, 0x18, 0x82, 0x08, 0x0d, 0x03, 0x6e, 0x04, 0xe1, 0x1a, 0x06, 0xfe, + 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x1d, 0x0e, 0x1c, 0x01, 0x14, 0x05, 0x10, 0x48, 0x3c, 0xfe, 0x78, + 0x14, 0xfe, 0x34, 0x12, 0x4f, 0x85, 0x34, 0x36, 0xbc, 0xfe, 0xe9, 0x13, 0x1d, 0x0e, 0x3b, 0x01, + 0x14, 0x05, 0x10, 0x48, 0x3c, 0x90, 0xe3, 0x4f, 0x85, 0x34, 0x36, 0xbc, 0xfe, 0xe9, 0x13, 0x07, + 0x0c, 0x03, 0xfe, 0x9c, 0xe7, 0x0c, 0x12, 0xfe, 0x15, 0x00, 0x92, 0x9e, 0x2d, 0x01, 0xd7, 0x07, + 0x06, 0x03, 0x0b, 0x49, 0x36, 0x37, 0x08, 0x3b, 0x07, 0x99, 0x01, 0x40, 0x11, 0x43, 0x08, 0x1c, + 0x07, 0x3f, 0x01, 0x76, 0x07, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x63, 0xf5, 0x30, + 0x75, 0xfe, 0x48, 0x55, 0x2f, 0xfe, 0xc9, 0x55, 0x03, 0x22, 0xbb, 0x6b, 0x16, 0xbb, 0x03, 0x0e, + 0xbd, 0x01, 0x14, 0xe5, 0x0e, 0x7c, 0x01, 0x14, 0xfe, 0x49, 0x44, 0x27, 0xfe, 0xe8, 0x17, 0x0e, + 0x1c, 0x01, 0x14, 0x05, 0x10, 0x48, 0x0e, 0x55, 0x01, 0xc0, 0x0e, 0x7c, 0x01, 0x14, 0x6b, 0x7d, + 0x03, 0xfe, 0x40, 0x5e, 0xfe, 0xe2, 0x08, 0xfe, 0xc0, 0x4c, 0x22, 0x3a, 0x05, 0x10, 0xfe, 0x52, + 0x12, 0x3c, 0x05, 0x00, 0xfe, 0x18, 0x12, 0xfe, 0xe1, 0x18, 0xfe, 0x19, 0xf4, 0xfe, 0x7f, 0x00, + 0xfe, 0x10, 0x13, 0xfe, 0xe2, 0x08, 0x6b, 0x3c, 0x3d, 0x05, 0x75, 0xa3, 0xfe, 0x82, 0x48, 0xfe, + 0x01, 0x80, 0xfe, 0xd7, 0x10, 0xfe, 0xc4, 0x48, 0x08, 0x2b, 0x07, 0x3a, 0xfe, 0x40, 0x5f, 0x1d, + 0x01, 0x40, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x14, 0x46, 0x08, 0x2b, 0x07, 0x3a, 0x01, 0x40, 0x11, + 0xfe, 0xdd, 0x00, 0xfe, 0x40, 0x4a, 0x68, 0xfe, 0x06, 0x17, 0xfe, 0x01, 0x07, 0xfe, 0x82, 0x48, + 0xfe, 0x04, 0x17, 0x03, 0xe9, 0x18, 0x72, 0xfe, 0x70, 0x18, 0x04, 0xfe, 0x90, 0x00, 0xfe, 0x3a, + 0x45, 0xfe, 0x2c, 0x10, 0xe9, 0xcc, 0x72, 0xfe, 0x82, 0x18, 0x04, 0xfe, 0x92, 0x00, 0xc5, 0x1e, + 0xd9, 0xe9, 0xfe, 0x0b, 0x00, 0x72, 0xfe, 0x94, 0x18, 0x04, 0xfe, 0x94, 0x00, 0xc5, 0x19, 0xfe, + 0x08, 0x10, 0x04, 0xfe, 0x96, 0x00, 0xc5, 0x84, 0xfe, 0x4e, 0x45, 0xd2, 0xfe, 0x0a, 0x45, 0xff, + 0x04, 0x68, 0x54, 0xfe, 0xf1, 0x10, 0x1a, 0x87, 0x03, 0x05, 0xa1, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, + 0x18, 0x21, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, 0x05, 0x1e, 0xfe, 0x5a, 0xf0, 0xfe, 0xce, 0x18, + 0x21, 0xcd, 0xfe, 0x26, 0x10, 0x05, 0x18, 0x82, 0x21, 0x84, 0xd9, 0x05, 0x0c, 0x82, 0x21, 0x88, + 0xfe, 0x0e, 0x10, 0x05, 0x06, 0x82, 0x21, 0x54, 0xc4, 0xab, 0x03, 0x17, 0xfe, 0x09, 0x00, 0x01, + 0x38, 0x2c, 0xfe, 0xfe, 0x18, 0x04, 0x6d, 0xac, 0x03, 0x1f, 0xfe, 0x16, 0x19, 0xfe, 0x14, 0xf0, + 0x0a, 0x2c, 0xfe, 0x12, 0x19, 0x03, 0xff, 0x34, 0x00, 0x00,}; + +STATIC unsigned short _adv_asc3550_size = + sizeof(_adv_asc3550_buf); /* 0x13AA */ +STATIC unsigned long _adv_asc3550_chksum = + 0x04F4788EUL; /* Expanded checksum. */ + +STATIC unsigned char _adv_asc38C0800_buf[] = { + 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x00, 0xfc, 0x48, 0xe4, 0x01, 0x00, 0x00, 0xf6, + 0x18, 0xe4, 0x01, 0xf6, 0x18, 0x80, 0x02, 0x00, 0x02, 0x1a, 0xff, 0xff, 0x00, 0xfa, 0x03, 0xf6, + 0xff, 0x00, 0x82, 0xe7, 0x01, 0xfa, 0x9e, 0xe7, 0x09, 0xe7, 0xe6, 0x0e, 0x00, 0xea, 0x01, 0xe6, + 0x03, 0x00, 0x1e, 0xf0, 0x55, 0xf0, 0x18, 0xf4, 0x3e, 0x57, 0x04, 0x00, 0x3e, 0x01, 0x85, 0xf0, + 0x00, 0xe6, 0x03, 0xfc, 0x08, 0x00, 0x32, 0xf0, 0x38, 0x54, 0x84, 0x0d, 0x86, 0xf0, 0xd4, 0x01, + 0xd5, 0xf0, 0xee, 0x19, 0x00, 0xec, 0x01, 0xfc, 0x98, 0x57, 0xbc, 0x00, 0x10, 0x13, 0xb1, 0xf0, + 0x02, 0x13, 0x3c, 0x00, 0x7e, 0x0d, 0xb4, 0x00, 0x00, 0x57, 0x01, 0xf0, 0x02, 0xfc, 0x03, 0xe6, + 0x0c, 0x1c, 0x10, 0x00, 0x18, 0x40, 0x3e, 0x1c, 0xbd, 0x00, 0xe0, 0x00, 0x02, 0x80, 0x3e, 0x00, + 0x46, 0x16, 0x4a, 0x10, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54, 0xba, 0x13, + 0xbb, 0x00, 0x00, 0x4e, 0x01, 0x01, 0x01, 0xea, 0x02, 0x48, 0x02, 0xfa, 0x08, 0x12, 0x30, 0xe4, + 0x3c, 0x56, 0x4e, 0x01, 0x5d, 0xf0, 0x7a, 0x01, 0x88, 0x0d, 0x8e, 0x10, 0xb6, 0x00, 0xc4, 0x08, + 0x00, 0x80, 0x04, 0x12, 0x05, 0xfc, 0x24, 0x01, 0x28, 0x01, 0x32, 0x00, 0x3c, 0x01, 0x40, 0x00, + 0x4b, 0xe4, 0x4b, 0xf4, 0x4c, 0x1c, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, + 0x7c, 0x01, 0xbb, 0x55, 0x00, 0x01, 0x02, 0xee, 0x03, 0x58, 0x03, 0xf7, 0x03, 0xfa, 0x04, 0x80, + 0x08, 0x44, 0x09, 0xf0, 0x10, 0x44, 0x1b, 0x80, 0x20, 0x01, 0x38, 0x1c, 0x4e, 0x1c, 0x5b, 0xf0, + 0x80, 0x00, 0x8a, 0x15, 0x98, 0x10, 0xaa, 0x00, 0xbd, 0x56, 0xbe, 0x00, 0xc0, 0x00, 0x00, 0x4c, + 0x00, 0xdc, 0x02, 0x4a, 0x04, 0xfc, 0x05, 0xf0, 0x05, 0xf8, 0x06, 0x13, 0x06, 0xf7, 0x08, 0x13, + 0x0c, 0x00, 0x0e, 0x47, 0x0e, 0xf7, 0x0f, 0x00, 0x1c, 0x0c, 0x20, 0x00, 0x2a, 0x01, 0x32, 0x1c, + 0x36, 0x00, 0x42, 0x54, 0x44, 0x0b, 0x44, 0x55, 0x45, 0x5a, 0x59, 0xf0, 0x5c, 0xf0, 0x62, 0x0a, + 0x69, 0x08, 0x78, 0x13, 0x83, 0x59, 0x8e, 0x18, 0x9a, 0x10, 0x9a, 0x18, 0xb8, 0xf0, 0xd6, 0x0e, + 0xea, 0x15, 0xf0, 0x00, 0x04, 0x10, 0x04, 0xea, 0x04, 0xf6, 0x05, 0x00, 0x06, 0x00, 0x06, 0x12, + 0x0a, 0x10, 0x0a, 0x12, 0x0b, 0xf0, 0x0c, 0x10, 0x0c, 0xf0, 0x12, 0x10, 0x19, 0x00, 0x19, 0xe4, + 0x2a, 0x12, 0x30, 0x1c, 0x33, 0x00, 0x34, 0x00, 0x36, 0x15, 0x38, 0x44, 0x3a, 0x15, 0x40, 0x5c, + 0x4a, 0xe4, 0x62, 0x1a, 0x68, 0x08, 0x68, 0x54, 0x7a, 0x17, 0x83, 0x55, 0x83, 0x5a, 0x91, 0x44, + 0xa2, 0x10, 0xa4, 0x00, 0xb0, 0x57, 0xb5, 0x00, 0xba, 0x00, 0xcc, 0x0e, 0xce, 0x45, 0xd0, 0x00, + 0xe1, 0x00, 0xe5, 0x55, 0xe7, 0x00, 0x00, 0x54, 0x01, 0x48, 0x01, 0x58, 0x02, 0x10, 0x02, 0xe6, + 0x03, 0xa1, 0x04, 0x13, 0x05, 0xe6, 0x06, 0x83, 0x06, 0xf0, 0x07, 0x00, 0x0a, 0x00, 0x0a, 0xf0, + 0x0c, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x04, 0x10, 0x10, 0x12, 0x1c, 0x19, 0x81, 0x1a, 0x10, + 0x1c, 0x00, 0x1c, 0x12, 0x1c, 0x13, 0x1d, 0xf7, 0x1e, 0x13, 0x20, 0x1c, 0x20, 0xe7, 0x22, 0x01, + 0x26, 0x01, 0x30, 0xe7, 0x38, 0x12, 0x3a, 0x55, 0x3f, 0x00, 0x41, 0x58, 0x43, 0x48, 0x46, 0x1c, + 0x4e, 0xe4, 0x5a, 0x13, 0x68, 0x13, 0x72, 0x14, 0x76, 0x02, 0x77, 0x57, 0x78, 0x03, 0x89, 0x48, + 0x8a, 0x13, 0x98, 0x80, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x32, 0xfe, 0x9c, 0xf0, 0x27, 0x02, 0xfe, + 0xa6, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xfe, 0xc6, 0x01, 0xfe, 0x18, 0x1a, 0x00, 0xfe, 0xc4, 0x01, + 0xfe, 0x84, 0x01, 0xff, 0x03, 0x00, 0x00, 0x30, 0xfe, 0x01, 0x05, 0xff, 0x40, 0x00, 0x00, 0x0d, + 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x10, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0xff, 0x10, 0xff, 0xff, 0xff, 0x11, 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, + 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xfe, 0xc4, 0x01, 0x38, 0x86, 0x0b, 0x01, 0xfe, 0x96, 0x0f, 0xfe, + 0x04, 0xf7, 0xfe, 0xc4, 0x01, 0x86, 0x0b, 0x1c, 0x38, 0xfe, 0x3d, 0xf0, 0xfe, 0xfc, 0x01, 0xfe, + 0x20, 0xf0, 0xdb, 0x04, 0x5e, 0x59, 0x02, 0xfe, 0xc2, 0x0d, 0x01, 0xfe, 0x22, 0x0e, 0xfe, 0xe9, + 0x12, 0x02, 0xfe, 0x08, 0x03, 0xfe, 0x28, 0x1c, 0x04, 0xfe, 0xa6, 0x00, 0xfe, 0xdd, 0x12, 0x46, + 0x12, 0xfe, 0xa6, 0x00, 0xcd, 0xfe, 0x48, 0xf0, 0xfe, 0x80, 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0x9a, + 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xb8, 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x4a, 0x02, 0xfe, 0x47, 0xf0, + 0xfe, 0x50, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x3e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x42, 0x02, 0xfe, + 0x45, 0xf0, 0xfe, 0x46, 0x02, 0x09, 0x0b, 0xa2, 0x09, 0x06, 0x12, 0xc1, 0x02, 0x27, 0xfe, 0x00, + 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, 0x1c, 0xfe, 0xed, 0x10, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, + 0x01, 0xfe, 0xee, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xfe, 0xa8, 0x00, 0x0f, 0x7d, 0x01, + 0xc5, 0x02, 0x27, 0x17, 0x5d, 0x4b, 0xc3, 0x01, 0xab, 0x0f, 0x7d, 0x01, 0x9f, 0xfe, 0xbd, 0x10, + 0x0f, 0x7d, 0x01, 0x9f, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x09, 0x06, 0x12, + 0xc1, 0x38, 0x19, 0x27, 0xfe, 0x3d, 0xf0, 0xfe, 0xfc, 0x01, 0x28, 0xfe, 0x8e, 0x02, 0xfe, 0x5a, + 0x1c, 0xdd, 0xfe, 0x14, 0x1c, 0x17, 0xfe, 0x30, 0x00, 0x4b, 0xc3, 0x01, 0xfe, 0xfc, 0x0f, 0x09, + 0x06, 0x12, 0xc1, 0x02, 0xfe, 0xc6, 0x01, 0x2a, 0x2d, 0x05, 0x10, 0x30, 0xfe, 0x69, 0x10, 0x09, + 0x06, 0x12, 0xc1, 0xfe, 0x04, 0xec, 0x2d, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x01, 0x40, 0x81, 0xfe, + 0x05, 0xf6, 0xfe, 0xa8, 0x00, 0x01, 0xfe, 0x20, 0x17, 0x0a, 0x4f, 0x8d, 0x3a, 0x11, 0x48, 0x1c, + 0xd3, 0x07, 0x1e, 0x09, 0x51, 0x01, 0xa0, 0x02, 0x27, 0x0f, 0x3d, 0x01, 0x15, 0x05, 0x10, 0xda, + 0x07, 0x1e, 0x09, 0x51, 0x01, 0x79, 0xfe, 0x28, 0x10, 0x0f, 0xc7, 0x01, 0x15, 0xed, 0x0f, 0x7e, + 0x01, 0x15, 0xfe, 0x49, 0x54, 0x77, 0xfe, 0x16, 0x03, 0x07, 0x1e, 0x09, 0x51, 0x01, 0xa0, 0x02, + 0x27, 0x38, 0x81, 0xfe, 0x02, 0xe8, 0x33, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xf5, 0xfe, 0x07, + 0x4b, 0xfe, 0x20, 0xf0, 0xdb, 0xfe, 0x40, 0x1c, 0x19, 0xf6, 0xfe, 0x26, 0xf0, 0xfe, 0x74, 0x03, + 0xfe, 0xa0, 0xf0, 0xfe, 0x62, 0x03, 0xfe, 0x11, 0xf0, 0xdb, 0xfe, 0x0e, 0x10, 0xfe, 0x9f, 0xf0, + 0xfe, 0x82, 0x03, 0xef, 0x13, 0xfe, 0x11, 0x00, 0x02, 0x54, 0x38, 0xfe, 0x48, 0x1c, 0xef, 0x19, + 0xf6, 0x35, 0xf6, 0xfe, 0x82, 0xf0, 0xfe, 0x88, 0x03, 0x24, 0x2a, 0xc4, 0x70, 0x16, 0xc4, 0x0f, + 0x7e, 0x01, 0x15, 0x70, 0x7f, 0x07, 0x1e, 0x09, 0x51, 0x01, 0x40, 0x11, 0x3d, 0x07, 0x3d, 0x09, + 0xa1, 0x01, 0xa0, 0xfc, 0x11, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xce, 0x03, 0x19, 0x32, 0x1f, 0xfe, + 0xde, 0x03, 0x01, 0x41, 0xd4, 0xfe, 0xee, 0x03, 0x71, 0x8c, 0xd7, 0xfe, 0xae, 0x06, 0x02, 0x25, + 0x04, 0x7d, 0x2c, 0x1a, 0xfe, 0x20, 0x05, 0x17, 0x88, 0x01, 0x2e, 0x01, 0x9b, 0x01, 0x9d, 0x35, + 0xfe, 0x60, 0x02, 0x02, 0xf4, 0xef, 0x38, 0x86, 0x18, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xf5, + 0xfe, 0x48, 0x1c, 0x8f, 0x01, 0xf2, 0xb1, 0xfe, 0x96, 0xf0, 0xfe, 0x28, 0x04, 0x2f, 0xfe, 0x2c, + 0x04, 0x35, 0x27, 0x0f, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x1a, 0xfe, 0x0c, 0x05, 0x4c, 0x97, 0xa3, + 0x33, 0x84, 0x74, 0x19, 0x32, 0x1f, 0x25, 0x04, 0x7d, 0x2c, 0xfe, 0x10, 0x12, 0x17, 0x88, 0x01, + 0x2e, 0x35, 0xfe, 0x60, 0x02, 0x02, 0xf4, 0x21, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x5e, + 0x12, 0x0a, 0x08, 0x06, 0xfe, 0x56, 0x12, 0x23, 0x29, 0x98, 0x01, 0x0c, 0x84, 0x74, 0x1f, 0xfe, + 0xdc, 0x04, 0x23, 0x29, 0x98, 0x01, 0x0c, 0x1f, 0x25, 0x23, 0x29, 0xba, 0xfe, 0x4c, 0x44, 0xfe, + 0x32, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x07, 0xfe, 0x93, 0x00, 0xfe, 0x4c, 0x54, 0x77, 0xfe, 0x0c, + 0x05, 0x81, 0xa3, 0x33, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x48, 0x13, 0x3e, 0x05, 0xfe, + 0xcc, 0x00, 0xfe, 0x40, 0x13, 0x0a, 0x08, 0x06, 0xea, 0xfe, 0x06, 0x10, 0x23, 0x29, 0xba, 0x0a, + 0x08, 0x39, 0xe1, 0x17, 0xa6, 0x0a, 0x08, 0x06, 0x59, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x2e, 0x35, + 0xfe, 0x66, 0x0d, 0x02, 0x25, 0x3b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xb7, 0x03, 0x17, + 0xa6, 0x01, 0x2e, 0x35, 0x27, 0x19, 0x27, 0x02, 0xfe, 0x14, 0x05, 0xfe, 0x42, 0x5b, 0x86, 0x18, + 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xf5, 0x17, 0x78, 0xfe, 0x07, 0x80, 0xfe, 0x31, 0x44, 0x0a, + 0x08, 0x0b, 0x99, 0xfe, 0x20, 0x80, 0x05, 0x18, 0xfe, 0x70, 0x12, 0x73, 0x08, 0x06, 0xfe, 0x60, + 0x13, 0x04, 0xfe, 0xa2, 0x00, 0x2c, 0x1a, 0xfe, 0xac, 0x05, 0xfe, 0x31, 0xe4, 0x5f, 0x73, 0x08, + 0x0b, 0xfe, 0x4a, 0x13, 0x04, 0xfe, 0xa0, 0x00, 0x2c, 0xfe, 0x42, 0x12, 0x62, 0x2f, 0xfe, 0x6c, + 0x05, 0x19, 0x32, 0xf7, 0x01, 0x0c, 0x26, 0xfe, 0xc4, 0x05, 0x11, 0xfe, 0xe3, 0x00, 0x24, 0x73, + 0xfe, 0x4a, 0xf0, 0xfe, 0x96, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x90, 0x05, 0xab, 0x20, 0xfe, 0x21, + 0x00, 0xa8, 0x20, 0xfe, 0x22, 0x00, 0xa2, 0x20, 0x8d, 0xfe, 0x09, 0x48, 0x01, 0x0c, 0x26, 0xfe, + 0xc4, 0x05, 0xfe, 0xe2, 0x08, 0x73, 0x08, 0xe0, 0x59, 0x01, 0x99, 0x20, 0x06, 0x16, 0xe8, 0x4b, + 0xfe, 0x27, 0x01, 0x0a, 0x08, 0x39, 0xb0, 0x46, 0x01, 0xb6, 0x17, 0xa6, 0x0a, 0x08, 0x06, 0x59, + 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x2e, 0x01, 0x9b, 0x01, 0x9d, 0x35, 0xfe, 0x66, 0x0d, 0x02, 0x25, + 0x04, 0xfe, 0x9c, 0x00, 0x2c, 0xfe, 0x3e, 0x12, 0x04, 0x5b, 0x2c, 0xfe, 0x36, 0x13, 0x46, 0x01, + 0xb6, 0x26, 0xfe, 0x3c, 0x06, 0x0f, 0x06, 0x73, 0x08, 0x22, 0xfe, 0x02, 0x12, 0x69, 0x01, 0xfe, + 0xd0, 0x14, 0x1f, 0xfe, 0x32, 0x06, 0x11, 0xc8, 0x01, 0x41, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x5b, + 0xc2, 0x0e, 0x5b, 0x04, 0xfe, 0x9e, 0x00, 0x2c, 0xfe, 0x62, 0x12, 0x04, 0x56, 0x2c, 0xf1, 0x01, + 0xfe, 0x40, 0x19, 0x01, 0xfe, 0xaa, 0x19, 0xee, 0xd2, 0xec, 0x07, 0x6a, 0xff, 0x02, 0x00, 0x57, + 0x6c, 0x80, 0x1b, 0x58, 0xd1, 0xd2, 0x8b, 0x46, 0x01, 0xb6, 0x26, 0xfe, 0xa6, 0x06, 0x73, 0x08, + 0x1d, 0xa7, 0x7c, 0x0f, 0x5d, 0x01, 0xfe, 0xfe, 0x14, 0x1f, 0xfe, 0x9c, 0x06, 0x11, 0xc8, 0x01, + 0x41, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x56, 0xc2, 0x0e, 0x56, 0x09, 0x06, 0x01, 0xb6, 0xfc, 0x76, + 0x8f, 0x01, 0xf2, 0xb1, 0x11, 0xfe, 0xe2, 0x00, 0x2f, 0xfe, 0xbe, 0x06, 0x19, 0x32, 0xd7, 0xfe, + 0xda, 0x06, 0x83, 0xfe, 0x78, 0x07, 0xd4, 0xfe, 0x80, 0x07, 0x71, 0x8c, 0x02, 0x25, 0x0a, 0x08, + 0x0b, 0xfe, 0x2e, 0x12, 0x14, 0x18, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, + 0x14, 0x00, 0x01, 0x0c, 0xfe, 0x99, 0xa4, 0x01, 0x0c, 0x14, 0x00, 0x02, 0xfe, 0x3e, 0x08, 0x6f, + 0x08, 0x1d, 0xea, 0x0a, 0x08, 0x1d, 0xfe, 0x30, 0x13, 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x0c, 0x14, + 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x06, 0x01, 0x0c, 0x14, + 0x00, 0x02, 0xfe, 0xe6, 0x0b, 0x69, 0xfe, 0x9a, 0x81, 0x6d, 0x8d, 0xfe, 0x09, 0x6f, 0xfe, 0x93, + 0x45, 0x1a, 0xfe, 0x88, 0x07, 0x2f, 0xfe, 0x60, 0x07, 0x19, 0x32, 0xd7, 0xfe, 0x58, 0x07, 0x71, + 0x8c, 0x83, 0xfe, 0x78, 0x07, 0x02, 0x25, 0x01, 0x41, 0x02, 0xfe, 0xbe, 0x06, 0x14, 0x22, 0x02, + 0xfe, 0xbe, 0x06, 0xfe, 0x9c, 0xf7, 0xfe, 0xf4, 0x07, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x52, + 0xfe, 0xd6, 0x07, 0x0e, 0x65, 0x12, 0x66, 0x0a, 0x4f, 0x5f, 0x3a, 0x01, 0xfe, 0xd6, 0x18, 0x05, + 0x10, 0x85, 0xfe, 0x83, 0xe7, 0xfe, 0x95, 0x00, 0xa8, 0xfe, 0x03, 0x40, 0x0a, 0x4f, 0x78, 0x3a, + 0x01, 0xbc, 0xb5, 0xfe, 0x1f, 0x40, 0x16, 0x67, 0x01, 0xf8, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, + 0xfe, 0x34, 0x51, 0xfe, 0xb6, 0x51, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0e, 0x63, 0x12, 0x64, + 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x0e, 0x42, 0x12, 0x43, + 0x41, 0x0a, 0x08, 0x5f, 0xb0, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0e, 0x65, 0x12, 0x66, 0x0a, + 0x08, 0x78, 0xd1, 0x01, 0xbc, 0xfe, 0x1f, 0x80, 0x16, 0x67, 0xfe, 0x34, 0x90, 0xfe, 0xb6, 0x90, + 0x0e, 0x44, 0x12, 0x45, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0e, 0x63, 0x12, 0x64, 0xfe, 0x28, + 0x90, 0xfe, 0xaa, 0x90, 0x0e, 0x42, 0x12, 0x43, 0x0e, 0x31, 0x12, 0x3f, 0x24, 0x0e, 0x53, 0x0e, + 0x68, 0x0a, 0x4f, 0x22, 0x3a, 0x38, 0x07, 0xa5, 0x2f, 0xfe, 0x5e, 0x08, 0xfe, 0x9e, 0xf0, 0xfe, + 0x72, 0x08, 0xcc, 0x1a, 0x32, 0x38, 0x72, 0xfe, 0xed, 0x10, 0xaa, 0xfe, 0x96, 0x08, 0xac, 0xfe, + 0xb2, 0x08, 0x83, 0xfe, 0x8a, 0x08, 0xd4, 0xfe, 0x90, 0x08, 0x71, 0x8c, 0x02, 0x25, 0x01, 0x41, + 0xfe, 0xc9, 0x10, 0x14, 0x22, 0xfe, 0xc9, 0x10, 0x6f, 0x08, 0x06, 0xfe, 0x10, 0x12, 0x6f, 0x08, + 0x0b, 0x4e, 0x0a, 0x08, 0x0b, 0xfe, 0x8e, 0x12, 0xfe, 0x2e, 0x1c, 0xad, 0x6f, 0x08, 0x06, 0x4e, + 0x6f, 0x08, 0x0b, 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xcc, 0x09, 0xfe, + 0xac, 0xf0, 0xfe, 0xfa, 0x08, 0x02, 0xfe, 0xd8, 0x09, 0xfe, 0xb7, 0xf0, 0xfe, 0xf6, 0x08, 0xfe, + 0x02, 0xf6, 0x1d, 0x69, 0xfe, 0x70, 0x18, 0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, + 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x19, 0x92, 0xfe, 0x8c, + 0xf0, 0xfe, 0xf6, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xea, 0x08, 0xfe, 0x34, 0x1c, 0xfe, 0xcb, 0x10, + 0xfe, 0xad, 0xf0, 0xfe, 0x06, 0x09, 0x02, 0xfe, 0x12, 0x0b, 0xfe, 0x36, 0x1c, 0xfe, 0xbf, 0x10, + 0xfe, 0x2b, 0xf0, 0x92, 0xfe, 0x6b, 0x18, 0x1b, 0xfe, 0x00, 0xfe, 0xe1, 0xcd, 0xfe, 0xd2, 0xf0, + 0x92, 0xfe, 0x76, 0x18, 0x1b, 0x18, 0x1a, 0x92, 0x04, 0xe7, 0x1b, 0x06, 0x1a, 0x92, 0xaa, 0x57, + 0xac, 0x57, 0xfe, 0x34, 0x1c, 0xfe, 0x36, 0x1c, 0xfe, 0x89, 0x10, 0x8f, 0x62, 0x3b, 0x17, 0xa6, + 0x01, 0x2e, 0x13, 0xfe, 0x35, 0x00, 0x35, 0x54, 0x13, 0x90, 0x02, 0x54, 0xf9, 0xaf, 0x0b, 0xfe, + 0x1a, 0x12, 0x50, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xeb, 0xde, 0xfe, 0x74, + 0x18, 0x91, 0x93, 0x1a, 0xfe, 0xc8, 0x08, 0x02, 0x57, 0x0a, 0x08, 0x5f, 0x2e, 0x04, 0x31, 0x2b, + 0x3f, 0x0e, 0x44, 0x12, 0x45, 0x82, 0x31, 0x5a, 0x3f, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18, 0xfe, + 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x36, 0x44, 0x21, 0x45, 0x04, 0x53, 0x2b, 0x68, 0x91, 0xfe, 0xe3, + 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18, 0x91, 0xfe, 0xe3, 0x54, 0x93, 0xc9, 0x52, 0xfe, 0xc8, + 0x08, 0x02, 0x57, 0xfe, 0x37, 0xf0, 0xfe, 0xd4, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x5a, 0x09, 0x02, + 0x57, 0xf9, 0xaf, 0x0b, 0x28, 0xfe, 0xf4, 0x0a, 0x36, 0x53, 0x21, 0x68, 0x52, 0xfe, 0x38, 0x0a, + 0x07, 0xfe, 0xc0, 0x07, 0x46, 0x61, 0x00, 0xd9, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x06, + 0x0a, 0x91, 0x96, 0xfe, 0x1e, 0x0a, 0x36, 0x53, 0x91, 0xfe, 0xe3, 0x54, 0x4d, 0x53, 0x6e, 0x68, + 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x57, 0x36, 0x53, 0x21, 0x68, 0xfe, 0x14, 0x59, 0xfe, + 0x95, 0x59, 0xeb, 0x4d, 0x53, 0x4d, 0x68, 0x02, 0x57, 0x0a, 0x08, 0x5f, 0xfe, 0x82, 0x12, 0x0a, + 0x08, 0x22, 0xfe, 0x66, 0x13, 0x2a, 0x67, 0x70, 0xd0, 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, + 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6b, 0x33, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, + 0x52, 0xfe, 0xd0, 0x08, 0x04, 0x65, 0x2b, 0x66, 0x0e, 0xb3, 0x12, 0x90, 0x4d, 0x65, 0x6e, 0x66, + 0x01, 0xbc, 0xb5, 0x6b, 0x33, 0x16, 0x67, 0x82, 0x31, 0x5a, 0x3f, 0x36, 0x44, 0x21, 0x45, 0x93, + 0xc9, 0xfe, 0x04, 0xfa, 0x31, 0xfe, 0x05, 0xfa, 0x3f, 0x01, 0xf8, 0xfe, 0x36, 0x10, 0x24, 0x0e, + 0xb3, 0x0e, 0x90, 0x36, 0x44, 0x21, 0x45, 0xad, 0x0a, 0x08, 0x22, 0x1a, 0xfe, 0xd0, 0x08, 0x36, + 0x42, 0x21, 0x43, 0x0a, 0x08, 0xfe, 0xf7, 0x00, 0x3a, 0x04, 0x63, 0x2b, 0x64, 0xfe, 0x10, 0x58, + 0xfe, 0x91, 0x58, 0x4d, 0x53, 0x6e, 0x68, 0x02, 0xfe, 0xee, 0x09, 0x0a, 0x08, 0x22, 0x1a, 0xfe, + 0xd0, 0x08, 0x0a, 0x08, 0xfe, 0xf7, 0x00, 0x3a, 0xeb, 0xde, 0x69, 0xfe, 0x10, 0x90, 0xfe, 0x92, + 0x90, 0xfe, 0xd3, 0x10, 0x3e, 0x05, 0xca, 0x1a, 0xfe, 0x02, 0x09, 0x11, 0xca, 0xf9, 0xaf, 0x0b, + 0xfe, 0x14, 0x13, 0x04, 0x42, 0x2b, 0x43, 0x52, 0xfe, 0x02, 0x09, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, + 0x58, 0x02, 0x57, 0x24, 0x46, 0xfe, 0x19, 0x80, 0xfe, 0xf1, 0x10, 0x0a, 0x08, 0x0b, 0xa7, 0xfe, + 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x94, 0x10, 0xfe, 0x6c, 0x19, 0x4d, 0x42, 0xfe, 0xed, 0x19, + 0x6e, 0x43, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x1b, 0xfe, 0x00, 0xff, 0x30, + 0xfe, 0x7a, 0x10, 0xcd, 0xfe, 0xd2, 0xf0, 0xfe, 0x8c, 0x0b, 0xfe, 0x76, 0x18, 0x1b, 0x18, 0xa9, + 0x04, 0xe7, 0x1b, 0x06, 0x87, 0x13, 0xfe, 0x16, 0x00, 0x02, 0x54, 0xfe, 0xd1, 0xf0, 0xfe, 0xc2, + 0x0b, 0x17, 0xa5, 0x01, 0x2e, 0x13, 0xfe, 0x17, 0x00, 0xfe, 0x48, 0x10, 0xfe, 0xce, 0xf0, 0xfe, + 0xaa, 0x0b, 0x13, 0xfe, 0x21, 0x00, 0x02, 0x54, 0xfe, 0xcd, 0xf0, 0xfe, 0xb6, 0x0b, 0x13, 0xfe, + 0x22, 0x00, 0x02, 0x54, 0xfe, 0xcb, 0xf0, 0xfe, 0xc2, 0x0b, 0x13, 0xfe, 0x24, 0x00, 0x02, 0x54, + 0xfe, 0xd0, 0xf0, 0xfe, 0xcc, 0x0b, 0x13, 0xae, 0xdf, 0xfe, 0xcf, 0xf0, 0xfe, 0xd6, 0x0b, 0x13, + 0x8d, 0xdc, 0xfe, 0xcc, 0xf0, 0xfe, 0xe6, 0x0b, 0xfe, 0x84, 0x80, 0xaf, 0x22, 0xfe, 0xd5, 0x12, + 0x13, 0xfe, 0x12, 0x00, 0x2f, 0xfe, 0xe6, 0x0b, 0x19, 0x32, 0xaa, 0x25, 0xac, 0x25, 0x38, 0xfc, + 0x2f, 0xfe, 0xfa, 0x0b, 0x19, 0x32, 0x83, 0xfe, 0x16, 0x0c, 0x71, 0x8c, 0xaa, 0xfe, 0xf4, 0x07, + 0xac, 0xfe, 0xf4, 0x07, 0x02, 0x25, 0x01, 0x41, 0xfe, 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0x8f, + 0x84, 0x74, 0xfe, 0x89, 0xf0, 0x25, 0x23, 0x29, 0xfe, 0xe9, 0x09, 0x01, 0x0c, 0x84, 0x74, 0x1f, + 0x25, 0x23, 0x29, 0x98, 0x35, 0xfe, 0x4e, 0x0c, 0x19, 0x32, 0x02, 0xfe, 0x42, 0x0c, 0xcc, 0x4e, + 0x13, 0xfe, 0x42, 0x00, 0x02, 0x54, 0xa4, 0x06, 0xfe, 0x81, 0x49, 0xfe, 0xcc, 0x12, 0x0a, 0x08, + 0x0b, 0xf1, 0x13, 0x00, 0x60, 0x0b, 0xfe, 0x6a, 0x12, 0x60, 0xfe, 0x28, 0x00, 0x28, 0xfe, 0x94, + 0x0d, 0x0f, 0x7e, 0x01, 0x15, 0x05, 0x00, 0x87, 0x37, 0xfe, 0x28, 0x00, 0x02, 0xfe, 0x94, 0x0d, + 0x01, 0x9b, 0x01, 0x9d, 0x0f, 0xc7, 0x01, 0xfe, 0xf0, 0x0e, 0xb9, 0x07, 0x3d, 0x09, 0xa1, 0x01, + 0x40, 0x11, 0x48, 0x07, 0x1e, 0x09, 0x51, 0x01, 0x79, 0x02, 0x27, 0x13, 0xfe, 0x44, 0x00, 0x60, + 0x0b, 0xa7, 0x37, 0x0b, 0xfe, 0xc0, 0x10, 0x01, 0x99, 0x37, 0x0b, 0xfe, 0xb6, 0x10, 0x01, 0x99, + 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xfe, 0x0a, 0x13, 0x37, 0x0b, 0x13, 0xfe, 0x43, 0x00, 0xc0, + 0x0a, 0x4f, 0x0b, 0x3a, 0x01, 0x9b, 0x01, 0x9d, 0xb9, 0x07, 0x3d, 0x09, 0xa1, 0x01, 0x40, 0x11, + 0x48, 0x07, 0x1e, 0x09, 0x51, 0x01, 0x79, 0x86, 0x0b, 0xb9, 0x1c, 0xd3, 0x02, 0xfe, 0x4c, 0x03, + 0x0a, 0x08, 0x0b, 0xa9, 0x37, 0x0b, 0x13, 0x00, 0xfe, 0x54, 0x10, 0x6f, 0x08, 0x1d, 0xfe, 0x50, + 0x12, 0x0a, 0x08, 0x1d, 0xfe, 0x48, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x52, 0x0d, + 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x58, 0x0d, 0x0a, 0x4f, 0x1d, 0x3a, 0xfe, 0x95, 0x10, + 0x13, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x69, 0xfe, 0x26, 0x10, 0x13, 0xfe, 0x13, 0x00, + 0xdc, 0x13, 0xfe, 0x47, 0x00, 0xa8, 0x13, 0xfe, 0x41, 0x00, 0xa2, 0x13, 0xfe, 0x24, 0x00, 0x04, + 0x7d, 0x2c, 0x28, 0xf4, 0x69, 0xfe, 0x04, 0xe6, 0x1d, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0xb9, + 0x01, 0xfe, 0xf8, 0x0e, 0x02, 0x27, 0xdd, 0x17, 0x0b, 0x4b, 0xfb, 0xe5, 0x17, 0xfe, 0x31, 0x00, + 0x4b, 0xc3, 0x01, 0xfe, 0xfc, 0x0f, 0x02, 0xfe, 0xc6, 0x01, 0x1c, 0xfe, 0x06, 0xec, 0xfe, 0xb9, + 0x00, 0x89, 0x37, 0x39, 0xc6, 0x30, 0x1c, 0xfe, 0x06, 0xea, 0xfe, 0xb9, 0x00, 0xfe, 0x47, 0x4b, + 0x7c, 0xfe, 0x75, 0x57, 0x04, 0x5e, 0xfe, 0x98, 0x56, 0xfe, 0x28, 0x12, 0x0f, 0x7e, 0xfe, 0xfa, + 0x14, 0x46, 0xed, 0x0f, 0xc7, 0xfe, 0xf0, 0x14, 0xfe, 0x49, 0x54, 0x95, 0xfe, 0x08, 0x0e, 0x0f, + 0x1e, 0xfe, 0xe4, 0x14, 0xfe, 0x44, 0x48, 0x02, 0xfe, 0x4c, 0x03, 0x0f, 0x5e, 0xfe, 0xc8, 0x14, + 0x89, 0x37, 0x39, 0xc6, 0x30, 0x1c, 0xfe, 0xce, 0x47, 0xfe, 0xbd, 0x13, 0x02, 0x27, 0x2a, 0x2d, + 0x05, 0x10, 0xfe, 0x78, 0x12, 0x24, 0x16, 0x5d, 0x16, 0xb2, 0x2a, 0x48, 0x46, 0x4b, 0x48, 0xcc, + 0xd9, 0xfe, 0xbc, 0xf0, 0xfe, 0xa4, 0x0e, 0x07, 0x06, 0x16, 0x5d, 0x01, 0xfe, 0xb0, 0x16, 0x04, + 0xfe, 0x38, 0x01, 0x2b, 0xfe, 0x3a, 0x01, 0x52, 0xfe, 0xa8, 0x0e, 0x04, 0xfe, 0x38, 0x01, 0x1b, + 0xfe, 0xf0, 0xff, 0x0e, 0xfe, 0x60, 0x01, 0x04, 0xfe, 0x3a, 0x01, 0x0e, 0xfe, 0x62, 0x01, 0x20, + 0x06, 0x16, 0x48, 0xfe, 0x04, 0xec, 0x2d, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x01, 0x40, 0x81, 0xfe, + 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x20, 0x17, 0x11, 0x48, 0xd3, 0x07, 0x06, 0x03, 0x24, + 0x03, 0x2a, 0x5d, 0xfe, 0xf7, 0x12, 0x2a, 0xb2, 0x70, 0x16, 0xb2, 0x05, 0xa5, 0xfe, 0x93, 0x13, + 0xfe, 0x24, 0x1c, 0x17, 0x18, 0x4b, 0xfb, 0xe5, 0xfe, 0xd9, 0x10, 0x9a, 0xfe, 0x03, 0xdc, 0xfe, + 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0x9a, 0xfe, 0x03, 0xdc, 0x24, 0xfe, 0x70, 0x57, 0xfe, 0x33, + 0x54, 0xfe, 0x3b, 0x54, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0x9a, 0x24, 0xfe, 0x00, 0xcc, + 0x03, 0xfe, 0x03, 0x57, 0x9a, 0x7f, 0x03, 0x01, 0xfe, 0x50, 0x17, 0x3e, 0x05, 0x48, 0xfe, 0x0a, + 0x13, 0x07, 0x1e, 0x09, 0x51, 0xdc, 0x01, 0x9b, 0x01, 0x9d, 0x07, 0x3d, 0x09, 0xa1, 0x01, 0x40, + 0x11, 0xfe, 0xe9, 0x00, 0x0a, 0x08, 0x8d, 0xfe, 0x52, 0x13, 0x01, 0xfe, 0xe2, 0x16, 0xfe, 0x1e, + 0x1c, 0xfe, 0x14, 0x90, 0x0e, 0xfe, 0x64, 0x01, 0xfe, 0x16, 0x90, 0x0e, 0xfe, 0x66, 0x01, 0x0a, + 0x08, 0x78, 0xea, 0xfe, 0x03, 0x80, 0x72, 0x4c, 0x11, 0x7b, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x97, + 0x01, 0xa0, 0xfe, 0x62, 0x08, 0x70, 0x4c, 0x11, 0x7b, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x97, 0x01, + 0xa0, 0x6b, 0x33, 0x11, 0x7b, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x97, 0x01, 0x79, 0x03, 0xfe, 0x08, + 0x1c, 0x04, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x04, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x04, + 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x04, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, + 0x20, 0x8b, 0x16, 0xfe, 0xb9, 0x00, 0x24, 0x0e, 0x5b, 0x0e, 0x56, 0x20, 0x10, 0x16, 0x2d, 0x16, + 0x3c, 0x50, 0xa4, 0xfe, 0x93, 0x00, 0x07, 0x2d, 0x09, 0x3c, 0x1c, 0x01, 0x79, 0x81, 0x11, 0x7b, + 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xd6, 0x0f, 0xdd, 0x8f, 0xfe, 0x14, 0x1c, 0xfe, 0x10, + 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x1c, 0xfe, 0x0c, 0x14, 0x89, 0xfe, 0x07, 0xe6, 0x39, 0xfe, 0xce, + 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x99, 0x0f, 0x3d, 0x01, 0x15, 0x05, 0x10, 0xda, 0x0f, 0x1e, + 0x01, 0x15, 0x05, 0x10, 0xe1, 0xfe, 0x44, 0x58, 0x4c, 0xfe, 0x01, 0xec, 0xc3, 0xfe, 0x9e, 0x40, + 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1d, 0xa3, 0x33, 0x01, 0xfe, 0xf8, 0x0e, 0xfe, 0xc9, + 0x10, 0x03, 0x38, 0x84, 0x74, 0x23, 0x29, 0xba, 0x05, 0x1d, 0xfe, 0x48, 0x12, 0x05, 0x0b, 0xfe, + 0x4c, 0x12, 0x05, 0x18, 0xfe, 0x30, 0x12, 0x05, 0xd5, 0x1a, 0xfe, 0xa0, 0x11, 0x05, 0xfe, 0x23, + 0x00, 0x1a, 0xfe, 0xac, 0x11, 0x05, 0x06, 0x1a, 0xa9, 0x05, 0x22, 0xfe, 0x12, 0x12, 0x05, 0x00, + 0x1a, 0x25, 0x17, 0xd5, 0x01, 0x2e, 0xce, 0x3b, 0x01, 0x0c, 0x83, 0x41, 0x03, 0x3b, 0x11, 0xfe, + 0xcc, 0x00, 0x02, 0x27, 0x3b, 0x3e, 0x05, 0xca, 0xfe, 0xe3, 0x13, 0x36, 0x42, 0x21, 0x43, 0x52, + 0xfe, 0x5e, 0x11, 0x0a, 0x08, 0x5f, 0xfe, 0x72, 0x12, 0x82, 0x31, 0x5a, 0x3f, 0x93, 0xc9, 0x95, + 0xfe, 0x28, 0x11, 0x2a, 0x67, 0xfe, 0x26, 0x13, 0x04, 0xb3, 0x2b, 0x90, 0x52, 0xfe, 0x78, 0x0d, + 0x0e, 0x65, 0x12, 0x66, 0x24, 0x0e, 0xb3, 0x0e, 0x90, 0x01, 0xbc, 0x20, 0x8b, 0x72, 0x16, 0x67, + 0x01, 0xf8, 0x82, 0x31, 0x5a, 0x3f, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x31, + 0xfe, 0x05, 0xfa, 0x3f, 0xfe, 0x91, 0x10, 0x04, 0x44, 0x2b, 0x45, 0xfe, 0x40, 0x56, 0xfe, 0xe1, + 0x56, 0x0e, 0x44, 0x12, 0x45, 0xab, 0x82, 0x31, 0x5a, 0x3f, 0x93, 0xc9, 0x04, 0x63, 0x2b, 0x64, + 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0e, 0x63, 0x12, 0x64, 0x0a, 0x08, 0x5f, 0xfe, 0x1e, 0x12, + 0x2a, 0x67, 0xfe, 0x1f, 0x40, 0x04, 0x65, 0x2b, 0x66, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x04, + 0x44, 0x2b, 0x45, 0xfe, 0x34, 0x50, 0xfe, 0xb6, 0x50, 0x04, 0x63, 0x2b, 0x64, 0xfe, 0x08, 0x50, + 0xfe, 0x8a, 0x50, 0x04, 0x42, 0x2b, 0x43, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x02, 0x9c, 0x20, + 0x06, 0x16, 0xfa, 0x02, 0x7a, 0x3b, 0x01, 0x0c, 0x1f, 0x55, 0x23, 0x29, 0xba, 0x05, 0x06, 0x28, + 0x55, 0x3e, 0x05, 0xca, 0x28, 0x7a, 0x01, 0xf2, 0x1b, 0x58, 0x1a, 0x55, 0x0a, 0x08, 0x0b, 0xe4, + 0x36, 0x42, 0x21, 0x43, 0xfe, 0x0a, 0x55, 0x30, 0xfe, 0x8b, 0x55, 0x4d, 0x42, 0x6e, 0x43, 0xfe, + 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x7a, 0xde, 0xfe, 0x0a, 0x45, 0xfe, 0x19, 0x41, 0x02, 0x7a, + 0x3b, 0x01, 0x0c, 0x1f, 0xc0, 0x23, 0x29, 0xfe, 0xe9, 0x09, 0x60, 0x18, 0xfe, 0x94, 0x12, 0x60, + 0x0b, 0x59, 0x02, 0x55, 0x2f, 0xb0, 0x19, 0x32, 0x1f, 0xc0, 0x23, 0x29, 0x98, 0x05, 0x18, 0x28, + 0x55, 0x01, 0x0c, 0x1f, 0xc0, 0x23, 0x29, 0xfe, 0xe8, 0x09, 0x50, 0x04, 0xfe, 0x9c, 0x00, 0x2c, + 0x30, 0xfe, 0xbb, 0x45, 0x60, 0x00, 0x4e, 0x37, 0x06, 0xa4, 0x58, 0xfe, 0xc0, 0x14, 0xfe, 0xf8, + 0x14, 0xb1, 0x3e, 0x05, 0xc8, 0xfe, 0x16, 0x13, 0x04, 0xfe, 0x9e, 0x00, 0x2c, 0xa9, 0x04, 0x56, + 0x2c, 0x30, 0x62, 0x02, 0x7a, 0xfe, 0xc0, 0x5d, 0xfe, 0xe4, 0x14, 0xfe, 0x03, 0x17, 0x04, 0x5b, + 0xc2, 0x0e, 0x5b, 0x62, 0x3b, 0x01, 0x0c, 0x26, 0x9c, 0x01, 0xfe, 0xd0, 0x14, 0x02, 0x9c, 0x2f, + 0xfe, 0xb4, 0x12, 0x19, 0x32, 0x1f, 0x55, 0x23, 0x29, 0x98, 0x05, 0x06, 0x28, 0x55, 0xfe, 0xf6, + 0x14, 0xfe, 0x42, 0x58, 0xfe, 0x70, 0x14, 0xfe, 0x92, 0x14, 0xb1, 0xfe, 0x4a, 0xf4, 0x0b, 0x1a, + 0x55, 0xfe, 0x4a, 0xf4, 0x06, 0xd8, 0x3e, 0x05, 0xc8, 0xd1, 0x02, 0x7a, 0x04, 0x56, 0xc2, 0x0e, + 0x56, 0x62, 0x3b, 0x01, 0x0c, 0x26, 0x9c, 0x01, 0xfe, 0xfe, 0x14, 0x02, 0x9c, 0x26, 0xe2, 0x76, + 0xf7, 0x76, 0x03, 0x35, 0xfe, 0x18, 0x13, 0x71, 0xfe, 0x18, 0x13, 0x62, 0x3b, 0x01, 0x0c, 0xfe, + 0xe3, 0x10, 0x07, 0x6a, 0xff, 0x02, 0x00, 0x57, 0x6c, 0x80, 0x1b, 0xfe, 0xff, 0x7f, 0xfe, 0x30, + 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x07, 0x6a, 0xff, 0x02, 0x00, 0x57, 0x6c, 0x80, 0x1b, 0x58, 0xfe, + 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x07, 0x6a, 0xff, 0x02, 0x00, 0x57, 0x6c, 0x80, 0x03, 0x07, + 0x6a, 0xff, 0x02, 0x00, 0x57, 0x6c, 0x80, 0xfe, 0x0b, 0x58, 0x03, 0x0f, 0x5b, 0x01, 0x9f, 0x0f, + 0x56, 0x01, 0x9f, 0x03, 0xd0, 0x1b, 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x22, 0x6c, + 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6b, 0x33, 0x0e, 0x63, + 0x12, 0x64, 0x4d, 0x44, 0x6e, 0x45, 0x03, 0xfe, 0x62, 0x18, 0xfe, 0x82, 0x5a, 0xfe, 0xe1, 0x1a, + 0xbe, 0xfe, 0x02, 0x58, 0x03, 0x01, 0xfe, 0x40, 0x19, 0xfe, 0x42, 0x48, 0x69, 0x50, 0x7c, 0x01, + 0x0c, 0x1f, 0xfe, 0xc8, 0x14, 0x23, 0x29, 0xfe, 0xe9, 0x09, 0xfe, 0xc1, 0x59, 0x01, 0x0c, 0x1f, + 0xfe, 0xc8, 0x14, 0x23, 0x29, 0xfe, 0xe8, 0x0a, 0x04, 0xfe, 0x9e, 0x00, 0x2c, 0xfe, 0xc2, 0x12, + 0x24, 0xb8, 0x1d, 0xe4, 0x60, 0xd6, 0x77, 0xfe, 0x18, 0x14, 0x59, 0x07, 0x06, 0x09, 0xd6, 0xa4, + 0xfe, 0x00, 0x10, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa8, 0xff, 0x02, 0x83, 0x55, 0xb8, + 0x18, 0xfe, 0x12, 0x13, 0x61, 0xfe, 0x30, 0x00, 0x95, 0xf3, 0x09, 0x88, 0x07, 0x06, 0xfe, 0x56, + 0x10, 0xb8, 0x0b, 0xfe, 0x16, 0x13, 0x61, 0xfe, 0x64, 0x00, 0x95, 0xf3, 0x0f, 0xfe, 0x64, 0x00, + 0x09, 0xae, 0x07, 0x06, 0xfe, 0x28, 0x10, 0xb8, 0x06, 0xfe, 0x5e, 0x13, 0x61, 0xfe, 0xc8, 0x00, + 0x95, 0xf3, 0x0f, 0xfe, 0xc8, 0x00, 0x09, 0x5d, 0x07, 0x06, 0xab, 0x61, 0xfe, 0x90, 0x01, 0x96, + 0xfe, 0x7e, 0x14, 0x7c, 0xad, 0xfe, 0x43, 0xf4, 0xb2, 0xfe, 0x56, 0xf0, 0xfe, 0x90, 0x14, 0xfe, + 0x04, 0xf4, 0x6a, 0xfe, 0x43, 0xf4, 0xae, 0xfe, 0xf3, 0x10, 0xb7, 0x01, 0xf1, 0x1b, 0x58, 0xda, + 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x8b, 0x96, 0xfe, 0xc2, 0x14, 0x7c, 0xfe, 0x14, 0x10, 0xfe, + 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0xec, 0x96, 0xfe, 0xc2, 0x14, 0xd2, 0xec, 0xa2, 0x50, 0x7c, 0x07, + 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x03, 0x50, 0x07, 0x0b, 0x03, 0x14, 0x06, 0x01, 0x0c, + 0x26, 0xfe, 0xfc, 0x14, 0x14, 0x0b, 0x01, 0x0c, 0x26, 0xfe, 0xfc, 0x14, 0x14, 0x18, 0x01, 0x0c, + 0x26, 0xfe, 0xfc, 0x14, 0x76, 0xfe, 0x89, 0x49, 0x01, 0x0c, 0x03, 0x14, 0x06, 0x01, 0x0c, 0x26, + 0xb4, 0x14, 0x18, 0x01, 0x0c, 0x26, 0xb4, 0x14, 0x06, 0x01, 0x0c, 0x26, 0xb4, 0xfe, 0x89, 0x49, + 0x01, 0x0c, 0x26, 0xb4, 0x76, 0xfe, 0x89, 0x4a, 0x01, 0x0c, 0x03, 0x50, 0x03, 0x2a, 0xe8, 0x05, + 0x06, 0xfe, 0x44, 0x13, 0xb5, 0x16, 0xe8, 0xfe, 0x49, 0xf4, 0x00, 0x59, 0x76, 0xce, 0x62, 0xfe, + 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf7, 0x01, 0x0c, 0x3e, 0x05, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, + 0x1f, 0xfe, 0x80, 0x15, 0x24, 0x16, 0xfa, 0x01, 0x41, 0x2a, 0xfa, 0x05, 0x06, 0x4e, 0x0a, 0x4f, + 0x06, 0x3a, 0x03, 0x0e, 0x5c, 0x12, 0x8e, 0xfe, 0x43, 0x58, 0x01, 0x15, 0x05, 0x10, 0xfe, 0x1e, + 0x12, 0x49, 0xee, 0x94, 0x01, 0x47, 0xfe, 0x90, 0x4d, 0xe6, 0x10, 0xfe, 0xc5, 0x59, 0x01, 0x47, + 0xfe, 0x8d, 0x56, 0xbe, 0x49, 0x03, 0x49, 0x21, 0x8e, 0x01, 0x15, 0x49, 0x94, 0x01, 0x47, 0xe9, + 0x10, 0xe6, 0x10, 0x21, 0x5c, 0x61, 0x1e, 0x87, 0x0f, 0x5e, 0x01, 0xc5, 0x03, 0x0e, 0x5c, 0x12, + 0x8e, 0xfe, 0xc3, 0x58, 0x01, 0x15, 0x05, 0x10, 0xfe, 0x1a, 0x12, 0x49, 0xee, 0x94, 0x01, 0x47, + 0xe9, 0x10, 0xfe, 0x80, 0x4d, 0xfe, 0xc5, 0x59, 0x01, 0x47, 0x49, 0x03, 0x49, 0x21, 0x5c, 0x01, + 0x15, 0x49, 0x94, 0x01, 0x47, 0xe9, 0x10, 0xe6, 0x10, 0x21, 0x5c, 0x61, 0x1e, 0x87, 0x0f, 0x5e, + 0x01, 0xc5, 0x03, 0x0e, 0x5c, 0x12, 0x8e, 0xfe, 0x43, 0x58, 0x01, 0x15, 0xfe, 0x42, 0x48, 0x94, + 0x01, 0x47, 0xfe, 0xc0, 0x5a, 0xb7, 0xfe, 0x00, 0xcd, 0xfe, 0x01, 0xcc, 0xfe, 0x4a, 0x46, 0xe4, + 0x9a, 0x7f, 0x05, 0x10, 0xfe, 0x2e, 0x13, 0x5a, 0x5c, 0xfe, 0x4d, 0xf4, 0x1e, 0xe2, 0x0f, 0x5e, + 0x01, 0x9f, 0xad, 0xfe, 0x40, 0x4c, 0xfe, 0xc5, 0x58, 0x01, 0x47, 0xfe, 0x00, 0x07, 0x7f, 0x05, + 0x10, 0x87, 0x5a, 0x8e, 0xfe, 0x05, 0x57, 0xfe, 0x08, 0x10, 0xfe, 0x45, 0x58, 0x01, 0x47, 0xfe, + 0x8d, 0x56, 0xbe, 0xfe, 0x80, 0x4c, 0xfe, 0x05, 0x17, 0x03, 0x09, 0x10, 0x75, 0x6d, 0xfe, 0x60, + 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xe3, 0x39, 0x9e, 0xfe, 0xc4, 0x16, + 0x01, 0xfe, 0xca, 0x17, 0xd9, 0x8a, 0x39, 0x6d, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xbf, + 0x28, 0xfe, 0xb4, 0x16, 0xfe, 0xda, 0x10, 0x09, 0x10, 0x75, 0x04, 0xfe, 0x64, 0x01, 0xfe, 0x00, + 0xf4, 0x22, 0xfe, 0x18, 0x58, 0x04, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x8a, 0x22, 0xfe, 0x3c, + 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6d, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, + 0x1c, 0xf7, 0x22, 0x9e, 0xfe, 0x0e, 0x17, 0xfe, 0xb6, 0x14, 0x30, 0x03, 0xbf, 0x28, 0xfe, 0xe6, + 0x16, 0xfe, 0x9c, 0x10, 0x09, 0x10, 0x75, 0xbe, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xdf, 0xe3, 0x31, + 0x9e, 0xfe, 0x30, 0x17, 0xfe, 0x94, 0x14, 0x2e, 0x8a, 0x31, 0x6d, 0x1d, 0xfe, 0xaf, 0x19, 0xfe, + 0x98, 0xe7, 0x00, 0x03, 0xbf, 0x28, 0xfe, 0x24, 0x17, 0xfe, 0x6c, 0x10, 0x09, 0x10, 0x75, 0xfe, + 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x8a, 0xe0, 0x6d, 0x1d, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xe0, + 0x9e, 0xfe, 0x68, 0x17, 0xfe, 0x5c, 0x14, 0x30, 0x03, 0xbf, 0x28, 0xfe, 0x54, 0x17, 0xfe, 0x42, + 0x10, 0xfe, 0x02, 0xf6, 0x10, 0x75, 0xfe, 0x18, 0xfe, 0x65, 0xfe, 0x19, 0xfe, 0x66, 0xd0, 0xe3, + 0x78, 0x9e, 0xfe, 0x8e, 0x17, 0xfe, 0x36, 0x14, 0xe2, 0x8a, 0x78, 0x46, 0xfe, 0x83, 0x58, 0xfe, + 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x6b, 0x33, + 0x03, 0x6b, 0x33, 0xfe, 0x12, 0x45, 0x28, 0xfe, 0x7e, 0x17, 0x17, 0x06, 0x4b, 0xfb, 0xe5, 0x02, + 0x27, 0xfe, 0x39, 0xf0, 0xfe, 0xd2, 0x17, 0x24, 0x03, 0xfe, 0x7e, 0x18, 0x1b, 0x18, 0x85, 0x07, + 0x0d, 0x03, 0x75, 0x04, 0xe7, 0x1b, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x1c, 0x0f, 0x1e, + 0x01, 0x15, 0x05, 0x10, 0x4e, 0x4c, 0xfe, 0x78, 0x14, 0xfe, 0x34, 0x12, 0x58, 0x89, 0x37, 0x39, + 0xc6, 0xfe, 0xe9, 0x13, 0x1c, 0x0f, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x4e, 0x4c, 0xfe, 0x56, 0x14, + 0xb0, 0x58, 0x89, 0x37, 0x39, 0xc6, 0xfe, 0xe9, 0x13, 0x09, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, + 0x13, 0xfe, 0x15, 0x00, 0x97, 0xa3, 0x33, 0x01, 0xfe, 0xf8, 0x0e, 0x09, 0x06, 0x03, 0x0a, 0x4f, + 0x39, 0x3a, 0x07, 0x3d, 0x09, 0xa1, 0x01, 0x40, 0x11, 0x48, 0x07, 0x1e, 0x09, 0x51, 0x01, 0x79, + 0x09, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x36, 0xfe, 0xa8, 0x00, 0x21, 0x7b, 0xfe, + 0x48, 0x55, 0x30, 0xfe, 0xc9, 0x55, 0x03, 0x2a, 0xc4, 0x72, 0x16, 0xc4, 0x03, 0x0f, 0xc7, 0x01, + 0x15, 0xed, 0x0f, 0x7e, 0x01, 0x15, 0xfe, 0x49, 0x44, 0x28, 0xfe, 0xc8, 0x18, 0x0f, 0x1e, 0x01, + 0x15, 0x05, 0x10, 0x4e, 0x0f, 0x5e, 0x01, 0xc5, 0x0f, 0x7e, 0x01, 0x15, 0x72, 0x7f, 0x03, 0xfe, + 0x40, 0x5e, 0xfe, 0xe2, 0x08, 0xfe, 0xc0, 0x4c, 0x2a, 0x3c, 0x05, 0x10, 0xfe, 0x52, 0x12, 0x4c, + 0x05, 0x00, 0xfe, 0x18, 0x12, 0xfe, 0xe1, 0x18, 0xfe, 0x19, 0xf4, 0xfe, 0x7f, 0x00, 0x2e, 0xfe, + 0xe2, 0x08, 0x72, 0x4c, 0x3e, 0x05, 0x7b, 0xa7, 0xfe, 0x82, 0x48, 0xfe, 0x01, 0x80, 0xfe, 0xd7, + 0x10, 0xfe, 0xc4, 0x48, 0x07, 0x2d, 0x09, 0x3c, 0xfe, 0x40, 0x5f, 0x1c, 0x01, 0x40, 0x11, 0xfe, + 0xdd, 0x00, 0xfe, 0x14, 0x46, 0x07, 0x2d, 0x09, 0x3c, 0x01, 0x40, 0x11, 0xfe, 0xdd, 0x00, 0xfe, + 0x40, 0x4a, 0x70, 0xfe, 0x06, 0x17, 0xfe, 0x01, 0x07, 0xfe, 0x82, 0x48, 0xfe, 0x04, 0x17, 0x03, + 0xf0, 0x18, 0x77, 0xfe, 0x50, 0x19, 0x04, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, + 0xf0, 0xd5, 0x77, 0xfe, 0x62, 0x19, 0x04, 0xfe, 0x92, 0x00, 0xcf, 0x1d, 0xdf, 0xf0, 0xfe, 0x0b, + 0x00, 0x77, 0xfe, 0x74, 0x19, 0x04, 0xfe, 0x94, 0x00, 0xcf, 0x22, 0xfe, 0x08, 0x10, 0x04, 0xfe, + 0x96, 0x00, 0xcf, 0x88, 0xfe, 0x4e, 0x45, 0xd8, 0xfe, 0x0a, 0x45, 0xff, 0x04, 0x68, 0x54, 0xfe, + 0xf1, 0x10, 0x1b, 0x8b, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, + 0xfe, 0x00, 0x04, 0xd8, 0xfe, 0x48, 0xf4, 0x18, 0x96, 0xfe, 0xa8, 0x19, 0x07, 0x18, 0x03, 0x05, + 0xa5, 0xfe, 0x5a, 0xf0, 0xfe, 0xb8, 0x19, 0x20, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, 0x05, 0x1d, + 0xfe, 0x5a, 0xf0, 0xfe, 0xc6, 0x19, 0x20, 0xd6, 0xfe, 0x26, 0x10, 0x05, 0x18, 0x85, 0x20, 0x88, + 0xdf, 0x05, 0x0b, 0x85, 0x20, 0xae, 0xfe, 0x0e, 0x10, 0x05, 0x06, 0x85, 0x20, 0x5d, 0xce, 0xb5, + 0x03, 0x17, 0xfe, 0x09, 0x00, 0x01, 0x2e, 0x2f, 0xfe, 0xf6, 0x19, 0x04, 0x74, 0xb7, 0x03, 0x19, + 0xfe, 0x16, 0x1a, 0xfe, 0x14, 0xf0, 0x0c, 0x2f, 0xfe, 0x0a, 0x1a, 0x19, 0xfe, 0x16, 0x1a, 0xfe, + 0x82, 0xf0, 0xfe, 0x0e, 0x1a, 0x03, 0xff, 0x34, 0x00, 0x00,}; + +STATIC unsigned short _adv_asc38C0800_size = + sizeof(_adv_asc38C0800_buf); /* 0x14AA */ +STATIC unsigned long _adv_asc38C0800_chksum = + 0x05297A65UL; /* Expanded checksum. */ /* a_init.c */ /* @@ -14021,8 +15382,8 @@ * Additional structure information can be found in a_condor.h where * the structure is defined. */ -STATIC ADVEEP_CONFIG -Default_EEPROM_Config ASC_INITDATA = { +STATIC ADVEEP_3550_CONFIG +Default_3550_EEPROM_Config ASC_INITDATA = { ADV_EEPROM_BIOS_ENABLE, /* cfg_msw */ 0x0000, /* cfg_lsw */ 0xFFFF, /* disc_enable */ @@ -14038,7 +15399,7 @@ 0, /* bios_id_lun */ 0, /* termination */ 0, /* reserved1 */ - 0xFFEF, /* bios_ctrl */ + 0xFFE7, /* bios_ctrl */ 0xFFFF, /* ultra_able */ 0, /* reserved2 */ ASC_DEF_MAX_HOST_QNG, /* max_host_qng */ @@ -14059,6 +15420,71 @@ 0 /* num_of_err */ }; +STATIC ADVEEP_38C0800_CONFIG +Default_38C0800_EEPROM_Config ASC_INITDATA = { + ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_msw */ + 0x0000, /* 01 cfg_lsw */ + 0xFFFF, /* 02 disc_enable */ + 0xFFFF, /* 03 wdtr_able */ + 0x4444, /* 04 sdtr_speed1 */ + 0xFFFF, /* 05 start_motor */ + 0xFFFF, /* 06 tagqng_able */ + 0xFFFF, /* 07 bios_scan */ + 0, /* 08 scam_tolerant */ + 7, /* 09 adapter_scsi_id */ + 0, /* bios_boot_delay */ + 3, /* 10 scsi_reset_delay */ + 0, /* bios_id_lun */ + 0, /* 11 termination_se */ + 0, /* termination_lvd */ + 0xFFE7, /* 12 bios_ctrl */ + 0x4444, /* 13 sdtr_speed2 */ + 0x4444, /* 14 sdtr_speed3 */ + ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */ + ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */ + 0, /* 16 dvc_cntl */ + 0x4444, /* 17 sdtr_speed4 */ + 0, /* 18 serial_number_word1 */ + 0, /* 19 serial_number_word2 */ + 0, /* 20 serial_number_word3 */ + 0, /* 21 check_sum */ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */ + 0, /* 30 dvc_err_code */ + 0, /* 31 adv_err_code */ + 0, /* 32 adv_err_addr */ + 0, /* 33 saved_dvc_err_code */ + 0, /* 34 saved_adv_err_code */ + 0, /* 35 saved_adv_err_addr */ + 0, /* 36 reserved */ + 0, /* 37 reserved */ + 0, /* 38 reserved */ + 0, /* 39 reserved */ + 0, /* 40 reserved */ + 0, /* 41 reserved */ + 0, /* 42 reserved */ + 0, /* 43 reserved */ + 0, /* 44 reserved */ + 0, /* 45 reserved */ + 0, /* 46 reserved */ + 0, /* 47 reserved */ + 0, /* 48 reserved */ + 0, /* 49 reserved */ + 0, /* 50 reserved */ + 0, /* 51 reserved */ + 0, /* 52 reserved */ + 0, /* 53 reserved */ + 0, /* 54 reserved */ + 0, /* 55 reserved */ + 0, /* 56 cisptr_lsw */ + 0, /* 57 cisprt_msw */ + ADV_PCI_VENDOR_ID, /* 58 subsysvid */ + ADV_PCI_DEVID_38C0800_REV1, /* 59 subsysid */ + 0, /* 60 reserved */ + 0, /* 61 reserved */ + 0, /* 62 reserved */ + 0 /* 63 reserved */ +}; + /* * Initialize the ADV_DVC_VAR structure. * @@ -14067,8 +15493,10 @@ * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. */ -int ASC_INIT +ASC_INITFUNC( +STATIC int, AdvInitGetConfig(ADV_DVC_VAR *asc_dvc) +) { ushort warn_code; AdvPortAddr iop_base; @@ -14119,8 +15547,8 @@ /* * Save the state of the PCI Configuration Command Register * "Parity Error Response Control" Bit. If the bit is clear (0), - * in AdvInitAsc3550Driver() tell the microcode to ignore DMA - * parity errors. + * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore + * DMA parity errors. */ asc_dvc->cfg->control_flag = 0; if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister) @@ -14129,13 +15557,19 @@ asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR; } - asc_dvc->cur_host_qng = 0; - asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) | ADV_LIB_VERSION_MINOR; asc_dvc->cfg->chip_version = AdvGetChipVersion(iop_base, asc_dvc->bus_type); + ASC_DBG2(1, "iopb_chip_id_1: %x %x\n", + (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1), + (ushort) ADV_CHIP_ID_BYTE); + + ASC_DBG2(1, "iopw_chip_id_0: %x %x\n", + (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0), + (ushort) ADV_CHIP_ID_WORD); + /* * Reset the chip to start and allow register writes. */ @@ -14145,37 +15579,54 @@ return ADV_ERROR; } else { - - AdvResetChip(asc_dvc); - - if ((status = AdvInitFromEEP(asc_dvc)) == ADV_ERROR) + /* + * The caller must set 'chip_type' to a valid setting. + */ + if (asc_dvc->chip_type != ADV_CHIP_ASC3550 && + asc_dvc->chip_type != ADV_CHIP_ASC38C0800 && + asc_dvc->chip_type != ADV_CHIP_ASC38C1600) { + asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE; return ADV_ERROR; } - warn_code |= status; /* - * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus - * Resets should be performed. + * Reset Chip. */ - if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, + ADV_CTRL_REG_CMD_RESET); + DvcSleepMilliSecond(100); + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, + ADV_CTRL_REG_CMD_WR_IO_REG); + + if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) + { + if ((status = AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) + { + return ADV_ERROR; + } + } else { - AdvResetSCSIBus(asc_dvc); + if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) + { + return ADV_ERROR; + } } + warn_code |= status; } return warn_code; } /* - * Initialize the ASC3550. + * Initialize the ASC-3550. * * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. */ -int ASC_INIT +STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) { AdvPortAddr iop_base; @@ -14183,12 +15634,20 @@ ulong sum; int begin_addr; int end_addr; - int code_sum; + ushort code_sum; int word; - int rql_addr; /* RISC Queue List address */ + int j; + int adv_asc3550_expanded_size; + ADV_CARR_T *carrp; + ulong contig_len; + long buf_size; + ulong carr_paddr; int i; ushort scsi_cfg1; - uchar biosmem[ASC_MC_BIOSLEN]; /* BIOS RISC Memory 0x40-0x8F. */ + uchar tid; + ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */ + ushort wdtr_able = 0, sdtr_able, tagqng_able; + uchar max_cmd[ADV_MAX_TID + 1]; /* If there is already an error, don't continue. */ if (asc_dvc->err_code != 0) @@ -14196,6 +15655,15 @@ return ADV_ERROR; } + /* + * The caller must set 'chip_type' to ADV_CHIP_ASC3550. + */ + if (asc_dvc->chip_type != ADV_CHIP_ASC3550) + { + asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE; + return ADV_ERROR; + } + warn_code = 0; iop_base = asc_dvc->iop_base; @@ -14207,9 +15675,36 @@ * Note: This code makes the assumption, which is currently true, * that a chip reset does not clear RISC LRAM. */ - for (i = 0; i < ASC_MC_BIOSLEN; i++) + for (i = 0; i < ASC_MC_BIOSLEN/2; i++) + { + AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); + } + + /* + * Save current per TID negotiated values. + */ + if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA) + { + ushort bios_version, major, minor; + + bios_version = bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM)/2]; + major = (bios_version >> 12) & 0xF; + minor = (bios_version >> 8) & 0xF; + if (major <= 3 || (major == 3 && minor == 1)) + { + /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */ + AdvReadWordLram(iop_base, 0x120, wdtr_able); + } else + { + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + } + } + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvReadByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]); + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); } /* @@ -14218,16 +15713,58 @@ * Write the microcode image to RISC memory starting at address 0. */ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - for (word = 0; word < _adv_mcode_size; word += 2) + /* Assume the following compressed format of the microcode buffer: + * + * 254 word (508 byte) table indexed by byte code followed + * by the following byte codes: + * + * 1-Byte Code: + * 00: Emit word 0 in table. + * 01: Emit word 1 in table. + * . + * FD: Emit word 253 in table. + * + * Multi-Byte Code: + * FE WW WW: (3 byte code) Word to emit is the next word WW WW. + * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. + */ + word = 0; + for (i = 253 * 2; i < _adv_asc3550_size; i++) { - AdvWriteWordAutoIncLram(iop_base, - *((ushort *) (&_adv_mcode_buf[word]))); + if (_adv_asc3550_buf[i] == 0xff) + { + for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) + { + AdvWriteWordAutoIncLram(iop_base, + *((ushort *) (&_adv_asc3550_buf[i + 2]))); + word++; + } + i += 3; + } else if (_adv_asc3550_buf[i] == 0xfe) + { + AdvWriteWordAutoIncLram(iop_base, + *((ushort *) (&_adv_asc3550_buf[i + 1]))); + i += 2; + word++; + } else + { + AdvWriteWordAutoIncLram(iop_base, + *((ushort *) &_adv_asc3550_buf[_adv_asc3550_buf[i] * 2])); + word++; + } } /* - * Clear the rest of Condor's Internal RAM (8KB). + * Set 'word' for later use to clear the rest of memory and save + * the expanded mcode size. + */ + word *= 2; + adv_asc3550_expanded_size = word; + + /* + * Clear the rest of ASC-3550 Internal RAM (8KB). */ - for (; word < ADV_CONDOR_MEMSIZE; word += 2) + for (; word < ADV_3550_MEMSIZE; word += 2) { AdvWriteWordAutoIncLram(iop_base, 0); } @@ -14237,12 +15774,13 @@ */ sum = 0; AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - for (word = 0; word < _adv_mcode_size; word += 2) + + for (word = 0; word < adv_asc3550_expanded_size; word += 2) { sum += AdvReadWordAutoIncLram(iop_base); } - if (sum != _adv_mcode_chksum) + if (sum != _adv_asc3550_chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return ADV_ERROR; @@ -14251,35 +15789,35 @@ /* * Restore the RISC memory BIOS region. */ - for (i = 0; i < ASC_MC_BIOSLEN; i++) + for (i = 0; i < ASC_MC_BIOSLEN/2; i++) { - AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]); + AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); } /* * Calculate and write the microcode code checksum to the microcode - * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). + * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). */ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); code_sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); for (word = begin_addr; word < end_addr; word += 2) { - code_sum += *((ushort *) (&_adv_mcode_buf[word])); + code_sum += AdvReadWordAutoIncLram(iop_base); } AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); /* - * Read microcode version and date. + * Read and save microcode version and date. */ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date); AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version); /* - * Initialize microcode operating variables + * Set the chip type to indicate the ASC3550. */ - AdvWriteWordLram(iop_base, ASC_MC_ADAPTER_SCSI_ID, - asc_dvc->chip_scsi_id); + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550); /* * If the PCI Configuration Command Register "Parity Error Response @@ -14289,7 +15827,7 @@ */ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - /* + /* * Note: Don't remove the use of a temporary variable in * the following code, otherwise the Microsoft C compiler * will turn the following lines into a no-op. @@ -14300,27 +15838,86 @@ } /* - * Set default microcode operating variables for WDTR, SDTR, and - * command tag queuing based on the EEPROM configuration values. + * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO + * threshold of 128 bytes. This register is only accessible to the host. + */ + AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, + START_CTL_EMFU | READ_CMD_MRM); + + /* + * Microcode operating variables for WDTR, SDTR, and command tag + * queuing will be set in AdvInquiryHandling() based on what a + * device reports it is capable of in Inquiry byte 7. * - * These ADV_DVC_VAR fields and the microcode variables will be - * changed in AdvInquiryHandling() if it is found a device is - * incapable of a particular feature. + * If SCSI Bus Resets haev been disabled, then directly set + * SDTR and WDTR from the EEPROM configuration. This will allow + * the BIOS and warm boot to work without a SCSI bus hang on + * the Inquiry caused by host and target mismatched DTR values. + * Without the SCSI Bus Reset, before an Inquiry a device can't + * be assumed to be in Asynchronous, Narrow mode. */ + if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) + { + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able); + } /* - * Set the microcode ULTRA target mask from EEPROM value. The - * SDTR target mask overrides the ULTRA target mask in the - * microcode so it is safe to set this value without determining - * whether the device supports SDTR. - * - * Note: There is no way to know whether a device supports ULTRA - * speed without attempting a SDTR ULTRA speed negotiation with - * the device. The device will reject the speed if it does not - * support it by responding with an SDTR message containing a - * slower speed. + * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID + * bitmask. These values determine the maximum SDTR speed negotiated + * with a device. + * + * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them + * without determining here whether the device supports SDTR. + * + * 4-bit speed SDTR speed name + * =========== =============== + * 0000b (0x0) SDTR disabled + * 0001b (0x1) 5 Mhz + * 0010b (0x2) 10 Mhz + * 0011b (0x3) 20 Mhz (Ultra) + * 0100b (0x4) 40 Mhz (LVD/Ultra2) + * 0101b (0x5) 80 Mhz (LVD2/Ultra3) + * 0110b (0x6) Undefined + * . + * 1111b (0xF) Undefined + */ + word = 0; + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) + { + /* Set Ultra speed for TID 'tid'. */ + word |= (0x3 << (4 * (tid % 4))); + } else + { + /* Set Fast speed for TID 'tid'. */ + word |= (0x2 << (4 * (tid % 4))); + } + if (tid == 3) /* Check if done with sdtr_speed1. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word); + word = 0; + } else if (tid == 7) /* Check if done with sdtr_speed2. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word); + word = 0; + } else if (tid == 11) /* Check if done with sdtr_speed3. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word); + word = 0; + } else if (tid == 15) /* Check if done with sdtr_speed4. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word); + /* End of loop. */ + } + } + + /* + * Set microcode operating variable for the disconnect per TID bitmask. */ - AdvWriteWordLram(iop_base, ASC_MC_ULTRA_ABLE, asc_dvc->ultra_able); AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable); @@ -14332,7 +15929,7 @@ */ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id); - + /* * Determine SCSI_CFG1 Microcode Default Value. * @@ -14349,8 +15946,8 @@ if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 || (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) { - asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; - return ADV_ERROR; + asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; + return ADV_ERROR; } /* @@ -14379,7 +15976,7 @@ * termination value based on a table listed in a_condor.h. * * If manual termination was specified with an EEPROM setting - * then 'termination' was set-up in AdvInitFromEEP() and + * then 'termination' was set-up in AdvInitFrom3550EEPROM() and * is ready to be 'ored' into SCSI_CFG1. */ if (asc_dvc->cfg->termination == 0) @@ -14431,7 +16028,21 @@ * after it is started below. */ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, - FLTR_11_TO_20NS | scsi_cfg1); + FLTR_11_TO_20NS | scsi_cfg1); + + /* + * Set MEM_CFG Microcode Default Value + * + * The microcode will set the MEM_CFG register using this value + * after it is started below. + * + * MEM_CFG may be accessed as a word or byte, but only bits 0-7 + * are defined. + * + * ASC-3550 has 8KB internal memory. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, + BIOS_EN | RAM_SZ_8KB); /* * Set SEL_MASK Microcode Default Value @@ -14440,59 +16051,1007 @@ * after it is started below. */ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, - ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); + ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); /* - * Link all the RISC Queue Lists together in a doubly-linked - * NULL terminated list. + * Build carrier freelist. * - * Skip the NULL (0) queue which is not used. + * Driver must have already allocated memory and set 'carrier_buf'. */ - for (i = 1, rql_addr = ASC_MC_RISC_Q_LIST_BASE + ASC_MC_RISC_Q_LIST_SIZE; - i < ASC_MC_RISC_Q_TOTAL_CNT; - i++, rql_addr += ASC_MC_RISC_Q_LIST_SIZE) + ADV_ASSERT(asc_dvc->carrier_buf != NULL); + + carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); + asc_dvc->carr_freelist = NULL; + if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) { + buf_size = ADV_CARRIER_BUFSIZE; + } else + { + buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T); + } + + do { + /* + * Get physical address of the carrier 'carrp'. + */ + contig_len = sizeof(ADV_CARR_T); + carr_paddr = DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp, + (long *) &contig_len, ADV_IS_CARRIER_FLAG); + + buf_size -= sizeof(ADV_CARR_T); + + /* + * If the current carrier is not physically contiguous, then + * maybe there was a page crossing. Try the next carrier aligned + * start address. + */ + if (contig_len < sizeof(ADV_CARR_T)) + { + carrp++; + continue; + } + + carrp->carr_pa = carr_paddr; + carrp->carr_va = (ulong) carrp; + /* - * Set the current RISC Queue List's RQL_FWD and RQL_BWD pointers - * in a one word write and set the state (RQL_STATE) to free. + * Insert the carrier at the beginning of the freelist. */ - AdvWriteWordLram(iop_base, rql_addr, ((i + 1) + ((i - 1) << 8))); - AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE); + carrp->next_vpa = (ulong) asc_dvc->carr_freelist; + asc_dvc->carr_freelist = carrp; + + carrp++; } + while (buf_size > 0); /* - * Set the Host and RISC Queue List pointers. - * - * Both sets of pointers are initialized with the same values: - * ASC_MC_RISC_Q_FIRST(0x01) and ASC_MC_RISC_Q_LAST (0xFF). + * Set-up the Host->RISC Initiator Command Queue (ICQ). */ - AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, ASC_MC_RISC_Q_FIRST); - AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, ASC_MC_RISC_Q_LAST); - AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_READY, ASC_MC_RISC_Q_FIRST); - AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_DONE, ASC_MC_RISC_Q_LAST); + if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) + { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->icq_sp->next_vpa; /* - * Finally, set up the last RISC Queue List (255) with - * a NULL forward pointer. + * The first command issued will be placed in the stopper carrier. */ - AdvWriteWordLram(iop_base, rql_addr, (ASC_MC_NULL_Q + ((i - 1) << 8))); - AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE); + asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER; - AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, - (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); + /* + * Set RISC ICQ physical address start value. + */ + AdvWriteDWordLram(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); - /* - * Note: Don't remove the use of a temporary variable in - * the following code, otherwise the Microsoft C compiler - * will turn the following lines into a no-op. + /* + * Set-up the RISC->Host Initiator Response Queue (IRQ). */ - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); - AdvWriteWordRegister(iop_base, IOPW_PC, word); + if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) + { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->irq_sp->next_vpa; + + /* + * The first command completed by the RISC will be placed in + * the stopper. + * + * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is + * completed the RISC will set the ASC_RQ_STOPPER bit. + */ + asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER; + + /* + * Set RISC IRQ physical address start value. + */ + AdvWriteDWordLram(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); + asc_dvc->carr_pending_cnt = 0; + + AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, + (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); + + /* + * Note: Don't remove the use of a temporary variable in + * the following code, otherwise the Microsoft C compiler + * will turn the following lines into a no-op. + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); + AdvWriteWordRegister(iop_base, IOPW_PC, word); + + /* finally, finally, gentlemen, start your engine */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + + /* + * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus + * Resets should be performed. The RISC has to be running + * to issue a SCSI Bus Reset. + */ + if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) + { + /* + * If the BIOS Signature is present in memory, restore the + * BIOS Handshake Configuration Table and do not perform + * a SCSI Bus Reset. + */ + if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA) + { + /* + * Restore per TID negotiated values. + */ + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + } else + { + if (AdvResetSB(asc_dvc) != ADV_TRUE) + { + warn_code = ASC_WARN_BUSRESET_ERROR; + } + } + } + + return warn_code; +} + +/* + * Initialize the ASC-38C0800. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + */ +STATIC int +AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) +{ + AdvPortAddr iop_base; + ushort warn_code; + ulong sum; + int begin_addr; + int end_addr; + ushort code_sum; + int word; + int j; + int adv_asc38C0800_expanded_size; + ADV_CARR_T *carrp; + ulong contig_len; + long buf_size; + ulong carr_paddr; + int i; + ushort scsi_cfg1; + uchar byte; + uchar tid; + ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */ + ushort wdtr_able, sdtr_able, tagqng_able; + uchar max_cmd[ADV_MAX_TID + 1]; + + /* If there is already an error, don't continue. */ + if (asc_dvc->err_code != 0) + { + return ADV_ERROR; + } + + /* + * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800. + */ + if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) + { + asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; + return ADV_ERROR; + } + + warn_code = 0; + iop_base = asc_dvc->iop_base; + + /* + * Save the RISC memory BIOS region before writing the microcode. + * The BIOS may already be loaded and using its RISC LRAM region + * so its region must be saved and restored. + * + * Note: This code makes the assumption, which is currently true, + * that a chip reset does not clear RISC LRAM. + */ + for (i = 0; i < ASC_MC_BIOSLEN/2; i++) + { + AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); + } + + /* + * Save current per TID negotiated values. + */ + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + + /* + * RAM BIST (RAM Built-In Self Test) + * + * Address : I/O base + offset 0x38h register (byte). + * Function: Bit 7-6(RW) : RAM mode + * Normal Mode : 0x00 + * Pre-test Mode : 0x40 + * RAM Test Mode : 0x80 + * Bit 5 : unused + * Bit 4(RO) : Done bit + * Bit 3-0(RO) : Status + * Host Error : 0x08 + * Int_RAM Error : 0x04 + * RISC Error : 0x02 + * SCSI Error : 0x01 + * No Error : 0x00 + * + * Note: RAM BIST code should be put right here, before loading the + * microcode and after saving the RISC memory BIOS region. + */ + + /* + * LRAM Pre-test + * + * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. + * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return + * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset + * to NORMAL_MODE, return an error too. + */ + for (i = 0; i < 2; i++) + { + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE); + DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */ + byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); + if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE) + { + asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST; + return ADV_ERROR; + } + + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); + DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */ + if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST) + != NORMAL_VALUE) + { + asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST; + return ADV_ERROR; + } + } + + /* + * LRAM Test - It takes about 1.5 ms to run through the test. + * + * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. + * If Done bit not set or Status not 0, save register byte, set the + * err_code, and return an error. + */ + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE); + DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */ + + byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); + if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) + { + /* Get here if Done bit not set or Status not 0. */ + asc_dvc->bist_err_code = byte; /* for BIOS display message */ + asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST; + return ADV_ERROR; + } + + /* We need to reset back to normal mode after LRAM test passes. */ + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); + + /* + * Load the Microcode + * + * Write the microcode image to RISC memory starting at address 0. + * + */ + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + + /* Assume the following compressed format of the microcode buffer: + * + * 254 word (508 byte) table indexed by byte code followed + * by the following byte codes: + * + * 1-Byte Code: + * 00: Emit word 0 in table. + * 01: Emit word 1 in table. + * . + * FD: Emit word 253 in table. + * + * Multi-Byte Code: + * FE WW WW: (3 byte code) Word to emit is the next word WW WW. + * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. + */ + word = 0; + for (i = 253 * 2; i < _adv_asc38C0800_size; i++) + { + if (_adv_asc38C0800_buf[i] == 0xff) + { + for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) + { + AdvWriteWordAutoIncLram(iop_base, + *((ushort *) (&_adv_asc38C0800_buf[i + 2]))); + word++; + } + i += 3; + } else if (_adv_asc38C0800_buf[i] == 0xfe) + { + AdvWriteWordAutoIncLram(iop_base, + *((ushort *) (&_adv_asc38C0800_buf[i + 1]))); + i += 2; + word++; + } else + { + AdvWriteWordAutoIncLram(iop_base, *((ushort *) + &_adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2])); + word++; + } + } + + /* + * Set 'word' for later use to clear the rest of memory and save + * the expanded mcode size. + */ + word *= 2; + adv_asc38C0800_expanded_size = word; + + /* + * Clear the rest of ASC-38C0800 Internal RAM (16KB). + */ + for (; word < ADV_38C0800_MEMSIZE; word += 2) + { + AdvWriteWordAutoIncLram(iop_base, 0); + } + + /* + * Verify the microcode checksum. + */ + sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + + for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) + { + sum += AdvReadWordAutoIncLram(iop_base); + } + + if (sum != _adv_asc38C0800_chksum) + { + asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; + return ADV_ERROR; + } + + /* + * Restore the RISC memory BIOS region. + */ + for (i = 0; i < ASC_MC_BIOSLEN/2; i++) + { + AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); + } + + /* + * Calculate and write the microcode code checksum to the microcode + * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); + AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); + code_sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); + for (word = begin_addr; word < end_addr; word += 2) + { + code_sum += AdvReadWordAutoIncLram(iop_base); + } + AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); + + /* + * Read microcode version and date. + */ + AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date); + AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version); + + /* + * Set the chip type to indicate the ASC38C0800. + */ + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800); + + /* + * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. + * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current + * cable detection and then we are able to read C_DET[3:0]. + * + * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 + * Microcode Default Value' section below. + */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV); + + /* + * If the PCI Configuration Command Register "Parity Error Response + * Control" Bit was clear (0), then set the microcode variable + * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode + * to ignore DMA parity errors. + */ + if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) + { + /* + * Note: Don't remove the use of a temporary variable in + * the following code, otherwise the Microsoft C compiler + * will turn the following lines into a no-op. + */ + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_IGNORE_PERR; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + } + + /* + * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2] + * bits for the default FIFO threshold. + * + * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes. + * + * For DMA Errata #4 set the BC_THRESH_ENB bit. + */ + AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, + BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM); + + /* + * Microcode operating variables for WDTR, SDTR, and command tag + * queuing will be set in AdvInquiryHandling() based on what a + * device reports it is capable of in Inquiry byte 7. + * + * If SCSI Bus Resets have been disabled, then directly set + * SDTR and WDTR from the EEPROM configuration. This will allow + * the BIOS and warm boot to work without a SCSI bus hang on + * the Inquiry caused by host and target mismatched DTR values. + * Without the SCSI Bus Reset, before an Inquiry a device can't + * be assumed to be in Asynchronous, Narrow mode. + */ + if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) + { + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able); + } + + /* + * Set microcode operating variables for DISC and SDTR_SPEED1, + * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM + * configuration values. + * + * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them + * without determining here whether the device supports SDTR. + */ + AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4); + + /* + * Set SCSI_CFG0 Microcode Default Value. + * + * The microcode will set the SCSI_CFG0 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, + PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id); + + /* + * Determine SCSI_CFG1 Microcode Default Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + + /* Read current SCSI_CFG1 Register value. */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + + /* + * If the internal narrow cable is reversed all of the SCSI_CTRL + * register signals will be set. Check for and return an error if + * this condition is found. + */ + if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) + { + asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; + return ADV_ERROR; + } + + /* + * All kind of combinations of devices attached to one of four connectors + * are acceptable except HVD device attached. For example, LVD device can + * be attached to SE connector while SE device attached to LVD connector. + * If LVD device attached to SE connector, it only runs up to Ultra speed. + * + * If an HVD device is attached to one of LVD connectors, return an error. + * However, there is no way to detect HVD device attached to SE connectors. + */ + if (scsi_cfg1 & HVD) + { + asc_dvc->err_code |= ASC_IERR_HVD_DEVICE; + return ADV_ERROR; + } + + /* + * If either SE or LVD automatic termination control is enabled, then + * set the termination value based on a table listed in a_condor.h. + * + * If manual termination was specified with an EEPROM setting then + * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to + * be 'ored' into SCSI_CFG1. + */ + if ((asc_dvc->cfg->termination & TERM_SE) == 0) + { + /* SE automatic termination control is enabled. */ + switch(scsi_cfg1 & C_DET_SE) + { + /* TERM_SE_HI: on, TERM_SE_LO: on */ + case 0x1: case 0x2: case 0x3: + asc_dvc->cfg->termination |= TERM_SE; + break; + + /* TERM_SE_HI: on, TERM_SE_LO: off */ + case 0x0: + asc_dvc->cfg->termination |= TERM_SE_HI; + break; + } + } + + if ((asc_dvc->cfg->termination & TERM_LVD) == 0) + { + /* LVD automatic termination control is enabled. */ + switch(scsi_cfg1 & C_DET_LVD) + { + /* TERM_LVD_HI: on, TERM_LVD_LO: on */ + case 0x4: case 0x8: case 0xC: + asc_dvc->cfg->termination |= TERM_LVD; + break; + + /* TERM_LVD_HI: off, TERM_LVD_LO: off */ + case 0x0: + break; + } + } + + /* + * Clear any set TERM_SE and TERM_LVD bits. + */ + scsi_cfg1 &= (~TERM_SE & ~TERM_LVD); + + /* + * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'. + */ + scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0); + + /* + * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits + * and set possibly modified termination control bits in the Microcode + * SCSI_CFG1 Register Value. + */ + scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE); + + /* + * Set SCSI_CFG1 Microcode Default Value + * + * Set possibly modified termination control and reset DIS_TERM_DRV + * bits in the Microcode SCSI_CFG1 Register Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1); + + /* + * Set MEM_CFG Microcode Default Value + * + * The microcode will set the MEM_CFG register using this value + * after it is started below. + * + * MEM_CFG may be accessed as a word or byte, but only bits 0-7 + * are defined. + * + * ASC-38C0800 has 16KB internal memory. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, + BIOS_EN | RAM_SZ_16KB); + + /* + * Set SEL_MASK Microcode Default Value + * + * The microcode will set the SEL_MASK register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, + ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); + + /* + * Build the carrier freelist. + * + * Driver must have already allocated memory and set 'carrier_buf'. + */ + + ADV_ASSERT(asc_dvc->carrier_buf != NULL); + + carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); + asc_dvc->carr_freelist = NULL; + if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) + { + buf_size = ADV_CARRIER_BUFSIZE; + } else + { + buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T); + } + + do { + /* + * Get physical address for the carrier 'carrp'. + */ + contig_len = sizeof(ADV_CARR_T); + carr_paddr = DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp, + (long *) &contig_len, ADV_IS_CARRIER_FLAG); + + buf_size -= sizeof(ADV_CARR_T); + + /* + * If the current carrier is not physically contiguous, then + * maybe there was a page crossing. Try the next carrier aligned + * start address. + */ + if (contig_len < sizeof(ADV_CARR_T)) + { + carrp++; + continue; + } + + carrp->carr_pa = carr_paddr; + carrp->carr_va = (ulong) carrp; + + /* + * Insert the carrier at the beginning of the freelist. + */ + carrp->next_vpa = (ulong) asc_dvc->carr_freelist; + asc_dvc->carr_freelist = carrp; + + carrp++; + } + while (buf_size > 0); + + /* + * Set-up the Host->RISC Initiator Command Queue (ICQ). + */ + + if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) + { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->icq_sp->next_vpa; + + /* + * The first command issued will be placed in the stopper carrier. + */ + asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER; + + /* + * Set RISC ICQ physical address start value. + */ + AdvWriteDWordLram(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); + + /* + * Set-up the RISC->Host Initiator Response Queue (IRQ). + */ + if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) + { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->irq_sp->next_vpa; + + /* + * The first command completed by the RISC will be placed in + * the stopper. + * + * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is + * completed the RISC will set the ASC_RQ_STOPPER bit. + */ + asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER; + + /* + * Set RISC IRQ physical address start value. + */ + AdvWriteDWordLram(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); + asc_dvc->carr_pending_cnt = 0; + + AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, + (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); + /* + * Note: Don't remove the use of a temporary variable in + * the following code, otherwise the Microsoft C compiler + * will turn the following lines into a no-op. + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); + AdvWriteWordRegister(iop_base, IOPW_PC, word); + + /* finally, finally, gentlemen, start your engine */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + + /* + * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus + * Resets should be performed. The RISC has to be running + * to issue a SCSI Bus Reset. + */ + if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) + { + /* + * If the BIOS Signature is present in memory, restore the + * BIOS Handshake Configuration Table and do not perform + * a SCSI Bus Reset. + */ + if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA) + { + /* + * Restore per TID negotiated values. + */ + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + } else + { + if (AdvResetSB(asc_dvc) != ADV_TRUE) + { + warn_code = ASC_WARN_BUSRESET_ERROR; + } + } + } + + return warn_code; +} + +/* + * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and + * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while + * all of this is done. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + * + * Note: Chip is stopped on entry. + */ +ASC_INITFUNC( +STATIC int, +AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc) +) +{ + AdvPortAddr iop_base; + ushort warn_code; + ADVEEP_38C0800_CONFIG eep_config; + int i; + uchar tid, termination; + ushort sdtr_speed = 0; + + iop_base = asc_dvc->iop_base; + + warn_code = 0; + + /* + * Read the board's EEPROM configuration. + * + * Set default values if a bad checksum is found. + */ + if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum) + { + warn_code |= ASC_WARN_EEPROM_CHKSUM; + + /* + * Set EEPROM default values. + */ + for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) + { + *((uchar *) &eep_config + i) = + *((uchar *) &Default_38C0800_EEPROM_Config + i); + } + + /* + * Assume the 6 byte board serial number that was read + * from EEPROM is correct even if the EEPROM checksum + * failed. + */ + eep_config.serial_number_word3 = + AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1); + + eep_config.serial_number_word2 = + AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2); + + eep_config.serial_number_word1 = + AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3); + + AdvSet38C0800EEPConfig(iop_base, &eep_config); + } + /* + * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the + * EEPROM configuration that was read. + * + * This is the mapping of EEPROM fields to Adv Library fields. + */ + asc_dvc->wdtr_able = eep_config.wdtr_able; + asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1; + asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2; + asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3; + asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4; + asc_dvc->tagqng_able = eep_config.tagqng_able; + asc_dvc->cfg->disc_enable = eep_config.disc_enable; + asc_dvc->max_host_qng = eep_config.max_host_qng; + asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; + asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID); + asc_dvc->start_motor = eep_config.start_motor; + asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; + asc_dvc->bios_ctrl = eep_config.bios_ctrl; + asc_dvc->no_scam = eep_config.scam_tolerant; + asc_dvc->cfg->serial1 = eep_config.serial_number_word1; + asc_dvc->cfg->serial2 = eep_config.serial_number_word2; + asc_dvc->cfg->serial3 = eep_config.serial_number_word3; + + /* + * For every Target ID if any of its 'sdtr_speed[1234]' bits + * are set, then set an 'sdtr_able' bit for it. + */ + asc_dvc->sdtr_able = 0; + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + if (tid == 0) + { + sdtr_speed = asc_dvc->sdtr_speed1; + } else if (tid == 4) + { + sdtr_speed = asc_dvc->sdtr_speed2; + } else if (tid == 8) + { + sdtr_speed = asc_dvc->sdtr_speed3; + } else if (tid == 12) + { + sdtr_speed = asc_dvc->sdtr_speed4; + } + if (sdtr_speed & ADV_MAX_TID) + { + asc_dvc->sdtr_able |= (1 << tid); + } + sdtr_speed >>= 4; + } + + /* + * Set the host maximum queuing (max. 253, min. 16) and the per device + * maximum queuing (max. 63, min. 4). + */ + if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) + { + eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; + } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) + { + /* If the value is zero, assume it is uninitialized. */ + if (eep_config.max_host_qng == 0) + { + eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; + } else + { + eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG; + } + } + + if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) + { + eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; + } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) + { + /* If the value is zero, assume it is uninitialized. */ + if (eep_config.max_dvc_qng == 0) + { + eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; + } else + { + eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG; + } + } + + /* + * If 'max_dvc_qng' is greater than 'max_host_qng', then + * set 'max_dvc_qng' to 'max_host_qng'. + */ + if (eep_config.max_dvc_qng > eep_config.max_host_qng) + { + eep_config.max_dvc_qng = eep_config.max_host_qng; + } + + /* + * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng' + * values based on possibly adjusted EEPROM values. + */ + asc_dvc->max_host_qng = eep_config.max_host_qng; + asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; + + /* + * If the EEPROM 'termination' field is set to automatic (0), then set + * the ADV_DVC_CFG 'termination' field to automatic also. + * + * If the termination is specified with a non-zero 'termination' + * value check that a legal value is set and set the ADV_DVC_CFG + * 'termination' field appropriately. + */ + if (eep_config.termination_se == 0) + { + termination = 0; /* auto termination for SE */ + } else + { + /* Enable manual control with low off / high off. */ + if (eep_config.termination_se == 1) + { + termination = 0; + + /* Enable manual control with low off / high on. */ + } else if (eep_config.termination_se == 2) + { + termination = TERM_SE_HI; + + /* Enable manual control with low on / high on. */ + } else if (eep_config.termination_se == 3) + { + termination = TERM_SE; + } else + { + /* + * The EEPROM 'termination_se' field contains a bad value. + * Use automatic termination instead. + */ + termination = 0; + warn_code |= ASC_WARN_EEPROM_TERMINATION; + } + } + + if (eep_config.termination_lvd == 0) + { + asc_dvc->cfg->termination = termination; /* auto termination for LVD */ + } else + { + /* Enable manual control with low off / high off. */ + if (eep_config.termination_lvd == 1) + { + asc_dvc->cfg->termination = termination; + + /* Enable manual control with low off / high on. */ + } else if (eep_config.termination_lvd == 2) + { + asc_dvc->cfg->termination = termination | TERM_LVD_HI; + + /* Enable manual control with low on / high on. */ + } else if (eep_config.termination_lvd == 3) + { + asc_dvc->cfg->termination = + termination | TERM_LVD; + } else + { + /* + * The EEPROM 'termination_lvd' field contains a bad value. + * Use automatic termination instead. + */ + asc_dvc->cfg->termination = termination; + warn_code |= ASC_WARN_EEPROM_TERMINATION; + } + } - /* finally, finally, gentlemen, start your engine */ - AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); - return warn_code; } @@ -14508,12 +17067,14 @@ * * Note: Chip is stopped on entry. */ -STATIC int ASC_INIT -AdvInitFromEEP(ADV_DVC_VAR *asc_dvc) +ASC_INITFUNC( +STATIC int, +AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc) +) { AdvPortAddr iop_base; ushort warn_code; - ADVEEP_CONFIG eep_config; + ADVEEP_3550_CONFIG eep_config; int i; iop_base = asc_dvc->iop_base; @@ -14525,17 +17086,17 @@ * * Set default values if a bad checksum is found. */ - if (AdvGetEEPConfig(iop_base, &eep_config) != eep_config.check_sum) + if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) { warn_code |= ASC_WARN_EEPROM_CHKSUM; /* * Set EEPROM default values. */ - for (i = 0; i < sizeof(ADVEEP_CONFIG); i++) + for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) { *((uchar *) &eep_config + i) = - *((uchar *) &Default_EEPROM_Config + i); + *((uchar *) &Default_3550_EEPROM_Config + i); } /* @@ -14545,15 +17106,17 @@ */ eep_config.serial_number_word3 = AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1); + eep_config.serial_number_word2 = AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2); + eep_config.serial_number_word1 = AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3); - AdvSetEEPConfig(iop_base, &eep_config); - } + AdvSet3550EEPConfig(iop_base, &eep_config); + } /* - * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the + * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the * EEPROM configuration that was read. * * This is the mapping of EEPROM fields to Adv Library fields. @@ -14568,7 +17131,6 @@ asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID); asc_dvc->start_motor = eep_config.start_motor; asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; - asc_dvc->cfg->bios_boot_wait = eep_config.bios_boot_delay; asc_dvc->bios_ctrl = eep_config.bios_ctrl; asc_dvc->no_scam = eep_config.scam_tolerant; asc_dvc->cfg->serial1 = eep_config.serial_number_word1; @@ -14619,7 +17181,7 @@ } /* - * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_CFG 'max_dvc_qng' + * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng' * values based on possibly adjusted EEPROM values. */ asc_dvc->max_host_qng = eep_config.max_host_qng; @@ -14672,8 +17234,48 @@ * * Return a checksum based on the EEPROM configuration read. */ -STATIC ushort ASC_INIT -AdvGetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf) +ASC_INITFUNC( +STATIC ushort, +AdvGet38C0800EEPConfig(AdvPortAddr iop_base, + ADVEEP_38C0800_CONFIG *cfg_buf) +) +{ + ushort wval, chksum; + ushort *wbuf; + int eep_addr; + + wbuf = (ushort *) cfg_buf; + chksum = 0; + + for (eep_addr = ASC_EEP_DVC_CFG_BEGIN; + eep_addr < ASC_EEP_DVC_CFG_END; + eep_addr++, wbuf++) + { + wval = AdvReadEEPWord(iop_base, eep_addr); + chksum += wval; + *wbuf = wval; + } + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + wbuf++; + for (eep_addr = ASC_EEP_DVC_CTL_BEGIN; + eep_addr < ASC_EEP_MAX_WORD_ADDR; + eep_addr++, wbuf++) + { + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + } + return chksum; +} + + +/* + * Read EEPROM configuration into the specified buffer. + * + * Return a checksum based on the EEPROM configuration read. + */ +ASC_INITFUNC( +STATIC ushort, +AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) +) { ushort wval, chksum; ushort *wbuf; @@ -14704,8 +17306,10 @@ /* * Read the EEPROM from specified location */ -STATIC ushort ASC_INIT +ASC_INITFUNC( +STATIC ushort, AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) +) { AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_READ | eep_word_addr); @@ -14716,8 +17320,10 @@ /* * Wait for EEPROM command to complete */ -STATIC void ASC_INIT +ASC_INITFUNC( +STATIC void, AdvWaitEEPCmd(AdvPortAddr iop_base) +) { int eep_delay_ms; @@ -14739,11 +17345,63 @@ /* * Write the EEPROM from 'cfg_buf'. */ -STATIC void ASC_INIT -AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf) +void +AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) +{ + ushort *wbuf; + ushort addr, chksum; + + wbuf = (ushort *) cfg_buf; + chksum = 0; + + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); + AdvWaitEEPCmd(iop_base); + + /* + * Write EEPROM from word 0 to word 20 + */ + for (addr = ASC_EEP_DVC_CFG_BEGIN; + addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++) + { + chksum += *wbuf; + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + DvcSleepMilliSecond(ASC_EEP_DELAY_MS); + } + + /* + * Write EEPROM checksum at word 21 + */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + wbuf++; /* skip over check_sum */ + + /* + * Write EEPROM OEM name at words 22 to 29 + */ + for (addr = ASC_EEP_DVC_CTL_BEGIN; + addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++) + { + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + } + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); + AdvWaitEEPCmd(iop_base); + return; +} + +/* + * Write the EEPROM from 'cfg_buf'. + */ +void +AdvSet38C0800EEPConfig(AdvPortAddr iop_base, + ADVEEP_38C0800_CONFIG *cfg_buf) { - ushort *wbuf; - ushort addr, chksum; + ushort *wbuf; + ushort addr, chksum; wbuf = (ushort *) cfg_buf; chksum = 0; @@ -14752,7 +17410,7 @@ AdvWaitEEPCmd(iop_base); /* - * Write EEPROM from word 0 to word 15 + * Write EEPROM from word 0 to word 20 */ for (addr = ASC_EEP_DVC_CFG_BEGIN; addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++) @@ -14765,7 +17423,7 @@ } /* - * Write EEPROM checksum at word 18 + * Write EEPROM checksum at word 21 */ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); @@ -14773,7 +17431,7 @@ wbuf++; /* skip over check_sum */ /* - * Write EEPROM OEM name at words 19 to 26 + * Write EEPROM OEM name at words 22 to 29 */ for (addr = ASC_EEP_DVC_CTL_BEGIN; addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++) @@ -14787,138 +17445,261 @@ return; } +/* a_advlib.c */ /* - * This function resets the chip and SCSI bus + * AdvExeScsiQueue() - Send a request to the RISC microcode program. * - * It is up to the caller to add a delay to let the bus settle after - * calling this function. + * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q, + * add the carrier to the ICQ (Initiator Command Queue), and tickle the + * RISC to notify it a new command is ready to be executed. * - * The SCSI_CFG0, SCSI_CFG1, and MEM_CFG registers are set-up in - * AdvInitAsc3550Driver(). Here when doing a write to one of these - * registers read first and then write. + * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be + * set to SCSI_MAX_RETRY. * - * Note: A SCSI Bus Reset can not be done until after the EEPROM - * configuration is read to determine whether SCSI Bus Resets - * should be performed. + * Return: + * ADV_SUCCESS(1) - The request was successfully queued. + * ADV_BUSY(0) - Resource unavailable; Retry again after pending + * request completes. + * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure + * host IC error. */ -STATIC void ASC_INIT -AdvResetChip(ADV_DVC_VAR *asc_dvc) +STATIC int +AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, + ADV_SCSI_REQ_Q *scsiq) { - AdvPortAddr iop_base; - ushort word; - uchar byte; + int last_int_level; + AdvPortAddr iop_base; + long req_size; + ulong req_paddr; + ADV_CARR_T *new_carrp; + + ADV_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */ + + /* + * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID. + */ + if (scsiq->target_id > ADV_MAX_TID) + { + scsiq->host_status = QHSTA_M_INVALID_DEVICE; + scsiq->done_status = QD_WITH_ERROR; + return ADV_ERROR; + } iop_base = asc_dvc->iop_base; + last_int_level = DvcEnterCritical(); + /* - * Reset Chip. + * Allocate a carrier ensuring at least one carrier always + * remains on the freelist and initialize fields. */ - AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET); - DvcSleepMilliSecond(100); - AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG); + if ((new_carrp = asc_dvc->carr_freelist) == NULL) + { + return ADV_BUSY; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) new_carrp->next_vpa; + asc_dvc->carr_pending_cnt++; /* - * Initialize Chip registers. - * - * Note: Don't remove the use of a temporary variable in the following - * code, otherwise the Microsoft C compiler will turn the following lines - * into a no-op. + * Set the carrier to be a stopper by setting 'next_vpa' + * to the stopper value. The current stopper will be changed + * below to point to the new stopper. + */ + new_carrp->next_vpa = ASC_CQ_STOPPER; + + /* + * Clear the ADV_SCSI_REQ_Q done flag. */ - byte = AdvReadByteRegister(iop_base, IOPB_MEM_CFG); - byte |= RAM_SZ_8KB; - AdvWriteByteRegister(iop_base, IOPB_MEM_CFG, byte); + scsiq->a_flag &= ~ADV_SCSIQ_DONE; + + req_size = sizeof(ADV_SCSI_REQ_Q); + req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq, + (long *) &req_size, ADV_IS_SCSIQ_FLAG); + + ADV_ASSERT(ADV_DWALIGN(req_paddr) == req_paddr); + ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q)); + + /* Save virtual and physical address of ADV_SCSI_REQ_Q and Carrier. */ + scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq; + scsiq->scsiq_rptr = req_paddr; - word = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - word &= ~BIG_ENDIAN; - AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, word); + /* XXX - Could have the RISC set these values. */ + scsiq->carr_va = (ulong) asc_dvc->icq_sp; + scsiq->carr_pa = asc_dvc->icq_sp->carr_pa; + + /* + * Use the current stopper to send the ADV_SCSI_REQ_Q command to + * the microcode. The newly allocated stopper will become the new + * stopper. + */ + asc_dvc->icq_sp->areq_vpa = (ulong) req_paddr; /* - * Setting the START_CTL_EMFU 3:2 bits sets a FIFO threshold - * of 128 bytes. This register is only accessible to the host. + * Set the 'next_vpa' pointer for the old stopper to be the + * physical address of the new stopper. The RISC can only + * follow physical addresses. */ - AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - START_CTL_EMFU | READ_CMD_MRM); -} + asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa; -/* a_advlib.c */ -/* - * Description: - * Send a SCSI request to the ASC3550 chip - * - * If there is no SG list for the request, set 'sg_entry_cnt' to 0. - * - * If 'sg_real_addr' is non-zero on entry, AscGetSGList() will not be - * called. It is assumed the caller has already initialized 'sg_real_addr'. - * - * Return: - * ADV_SUCCESS(1) - the request is in the mailbox - * ADV_BUSY(0) - total request count > 253, try later - * ADV_ERROR(-1) - invalid scsi request Q - */ -STATIC int -AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, - ADV_SCSI_REQ_Q *scsiq) -{ - if (scsiq == (ADV_SCSI_REQ_Q *) 0L) + /* + * Set the host adapter stopper pointer to point to the new carrier. + */ + asc_dvc->icq_sp = new_carrp; + + /* + * Tickle the RISC to tell it to read its Command Queue Head pointer. + */ + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { - /* 'scsiq' should never be NULL. */ - ADV_ASSERT(0); - return ADV_ERROR; + /* + * Clear the tickle value. In the ASC-3550 the RISC flag + * command 'clr_tickle_a' does not work unless the host + * value is cleared. + */ + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); } - return AdvSendScsiCmd(asc_dvc, scsiq); + DvcLeaveCritical(last_int_level); + + return ADV_SUCCESS; } /* * Reset SCSI Bus and purge all outstanding requests. * * Return Value: - * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset. - * - * Note: Should always return ADV_TRUE. + * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset. + * ADV_FALSE(0) - Microcode command failed. + * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC + * may be hung which requires driver recovery. */ STATIC int AdvResetSB(ADV_DVC_VAR *asc_dvc) { int status; - status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET, 0L, 0); + /* + * Send the SCSI Bus Reset idle start idle command which asserts + * the SCSI Bus Reset signal. + */ + status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_START, 0L); + if (status != ADV_TRUE) + { + return status; + } + + /* + * Delay for the specified SCSI Bus Reset hold time. + * + * The hold time delay is done on the host because the RISC has no + * microsecond accurate timer. + */ + DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US); + + /* + * Send the SCSI Bus Reset end idle command which de-asserts + * the SCSI Bus Reset signal and purges any pending requests. + */ + status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_END, 0L); + if (status != ADV_TRUE) + { + return status; + } - AdvResetSCSIBus(asc_dvc); + DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000); return status; } /* - * Reset SCSI Bus and delay. + * Reset chip and SCSI Bus. + * + * Return Value: + * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful. + * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure. */ -STATIC void -AdvResetSCSIBus(ADV_DVC_VAR *asc_dvc) +STATIC int +AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc) { - AdvPortAddr iop_base; - ushort scsi_ctrl; + int status; + ushort wdtr_able, sdtr_able, tagqng_able; + uchar tid, max_cmd[ADV_MAX_TID + 1]; + AdvPortAddr iop_base; + ushort bios_sig; iop_base = asc_dvc->iop_base; /* - * The microcode currently sets the SCSI Bus Reset signal while - * handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET command above. - * But the SCSI Bus Reset Hold Time in the microcode is not deterministic - * (it may in fact be for less than the SCSI Spec. minimum of 25 us). - * Therefore on return the Adv Library sets the SCSI Bus Reset signal - * for ASC_SCSI_RESET_HOLD_TIME_US, which is defined to be greater - * than 25 us. - */ - scsi_ctrl = AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL); - AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL, - scsi_ctrl | ADV_SCSI_CTRL_RSTOUT); - DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US); - AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL, - scsi_ctrl & ~ADV_SCSI_CTRL_RSTOUT); + * Save current per TID negotiated values. + */ + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } - DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000); -} + /* + * Force the AdvInitAsc3550/38C0800Driver() function to + * perform a SCSI Bus Reset by clearing the BIOS signature word. + * The initialization functions assumes a SCSI Bus Reset is not + * needed if the BIOS signature word is present. + */ + AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig); + AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0); + /* + * Stop chip and reset it. + */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP); + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET); + DvcSleepMilliSecond(100); + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG); + + /* + * Reset Adv Library error code, if any, and try + * re-initializing the chip. + */ + asc_dvc->err_code = 0; + if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) + { + status = AdvInitAsc38C0800Driver(asc_dvc); + } else + { + status = AdvInitAsc3550Driver(asc_dvc); + } + + /* Translate initialization return value to status value. */ + if (status == 0) + { + status = ADV_TRUE; + } else + { + status = ADV_FALSE; + } + + /* + * Restore the BIOS signature word. + */ + AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig); + + /* + * Restore per TID negotiated values. + */ + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + + return status; +} /* * Adv Library Interrupt Service Routine @@ -14944,79 +17725,76 @@ { AdvPortAddr iop_base; uchar int_stat; - ushort next_done_loc, target_bit; - int completed_q; + ushort target_bit; + ADV_CARR_T *free_carrp; + ulong irq_next_vpa; int flags; ADV_SCSI_REQ_Q *scsiq; - ASC_REQ_SENSE *sense_data; - int ret; flags = DvcEnterCritical(); - iop_base = asc_dvc->iop_base; - if (AdvIsIntPending(iop_base)) - { - ret = ADV_TRUE; - } else - { - ret = ADV_FALSE; - } + iop_base = asc_dvc->iop_base; /* Reading the register clears the interrupt. */ int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG); - if (int_stat & ADV_INTR_STATUS_INTRB) + if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB | + ADV_INTR_STATUS_INTRC)) == 0) { - asc_dvc->idle_cmd_done = ADV_TRUE; + return ADV_FALSE; } /* - * Notify the driver of a hardware detected SCSI Bus Reset. + * Notify the driver of an asynchronous microcode condition by + * calling the ADV_DVC_VAR.async_callback function. The function + * is passed the microcode ASC_MC_INTRB_CODE byte value. */ - if (int_stat & ADV_INTR_STATUS_INTRC) + if (int_stat & ADV_INTR_STATUS_INTRB) { - if (asc_dvc->sbreset_callback != 0) + uchar intrb_code; + + AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code); + if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE && + asc_dvc->carr_pending_cnt != 0) + { + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550) + { + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + } + } + + if (asc_dvc->async_callback != 0) { - (*(ADV_SBRESET_CALLBACK) asc_dvc->sbreset_callback)(asc_dvc); + (*asc_dvc->async_callback)(asc_dvc, intrb_code); } } /* - * ASC_MC_HOST_NEXT_DONE (0x129) is actually the last completed RISC - * Queue List request. Its forward pointer (RQL_FWD) points to the - * current completed RISC Queue List request. + * Check if the IRQ stopper carrier contains a completed request. */ - AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, next_done_loc); - next_done_loc = ASC_MC_RISC_Q_LIST_BASE + - (next_done_loc * ASC_MC_RISC_Q_LIST_SIZE) + RQL_FWD; - - AdvReadByteLram(iop_base, next_done_loc, completed_q); - - /* Loop until all completed Q's are processed. */ - while (completed_q != ASC_MC_NULL_Q) + while (((irq_next_vpa = asc_dvc->irq_sp->next_vpa) & ASC_RQ_DONE) != 0) { - AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, completed_q); - - next_done_loc = ASC_MC_RISC_Q_LIST_BASE + - (completed_q * ASC_MC_RISC_Q_LIST_SIZE); + /* + * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure. + * The RISC will have set 'areq_vpa' to a virtual address. + */ + scsiq = (ADV_SCSI_REQ_Q *) asc_dvc->irq_sp->areq_vpa; /* - * Read the ADV_SCSI_REQ_Q virtual address pointer from - * the RISC list entry. The microcode has changed the - * ADV_SCSI_REQ_Q physical address to its virtual address. - * - * Refer to comments at the end of AdvSendScsiCmd() for - * more information on the RISC list structure. + * Advance the stopper pointer to the next carrier + * ignoring the lower four bits. Free the previous + * stopper carrier. */ - { - ushort lsw, msw; - AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR, lsw); - AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR + 2, msw); + free_carrp = asc_dvc->irq_sp; + asc_dvc->irq_sp = ASC_GET_CARRP(irq_next_vpa); + + free_carrp->next_vpa = (ulong) asc_dvc->carr_freelist; + asc_dvc->carr_freelist = (ADV_CARR_T *) free_carrp; + asc_dvc->carr_pending_cnt--; - scsiq = (ADV_SCSI_REQ_Q *) (((ulong) msw << 16) | lsw); - } - ADV_ASSERT(scsiq != NULL); + ADV_ASSERT(scsiq != NULL); target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id); /* @@ -15028,14 +17806,9 @@ * Check Condition handling */ if ((scsiq->done_status == QD_WITH_ERROR) && - (scsiq->scsi_status == SS_CHK_CONDITION) && - (sense_data = (ASC_REQ_SENSE *) scsiq->vsense_addr) != 0 && - (scsiq->orig_sense_len - scsiq->sense_len) >= ASC_MIN_SENSE_LEN) + (scsiq->scsi_status == SS_CHK_CONDITION) + ) { - /* - * Command returned with a check condition and valid - * sense data. - */ } /* * If the command that completed was a SCSI INQUIRY and @@ -15043,27 +17816,18 @@ * command information for the device. */ else if (scsiq->done_status == QD_NO_ERROR && - scsiq->cdb[0] == SCSICMD_Inquiry && - scsiq->target_lun == 0) + scsiq->cdb[0] == SCSICMD_Inquiry && + scsiq->target_lun == 0) { AdvInquiryHandling(asc_dvc, scsiq); } - - /* Change the RISC Queue List state to free. */ - AdvWriteByteLram(iop_base, next_done_loc + RQL_STATE, ASC_MC_QS_FREE); - - /* Get the RISC Queue List forward pointer. */ - AdvReadByteLram(iop_base, next_done_loc + RQL_FWD, completed_q); - /* * Notify the driver of the completed request by passing * the ADV_SCSI_REQ_Q pointer to its callback function. */ - ADV_ASSERT(asc_dvc->cur_host_qng > 0); - asc_dvc->cur_host_qng--; scsiq->a_flag |= ADV_SCSIQ_DONE; - (*(ADV_ISR_CALLBACK) asc_dvc->isr_callback)(asc_dvc, scsiq); + (*asc_dvc->isr_callback)(asc_dvc, scsiq); /* * Note: After the driver callback function is called, 'scsiq' * can no longer be referenced. @@ -15083,231 +17847,107 @@ (void) DvcEnterCritical(); } DvcLeaveCritical(flags); - return ret; + return ADV_TRUE; } /* * Send an idle command to the chip and wait for completion. * - * Interrupts do not have to be enabled on entry. + * Command completion is polled for once per microsecond. + * + * The function can be called from anywhere including an interrupt handler. + * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical() + * functions to prevent reentrancy. * * Return Values: * ADV_TRUE - command completed successfully * ADV_FALSE - command failed + * ADV_ERROR - command timed out */ STATIC int AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc, ushort idle_cmd, - ulong idle_cmd_parameter, - int flags) + ulong idle_cmd_parameter) { int last_int_level; - ulong i; + int result; + ulong i, j; AdvPortAddr iop_base; - int ret; - - asc_dvc->idle_cmd_done = 0; last_int_level = DvcEnterCritical(); + iop_base = asc_dvc->iop_base; /* + * Clear the idle command status which is set by the microcode + * to a non-zero value to indicate when the command is completed. + * The non-zero result is one of the IDLE_CMD_STATUS_* values + * defined in a_advlib.h. + */ + AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort) 0); + + /* * Write the idle command value after the idle command parameter * has been written to avoid a race condition. If the order is not * followed, the microcode may process the idle command before the * parameters have been written to LRAM. */ - AdvWriteDWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, idle_cmd_parameter); + AdvWriteDWordLram(iop_base, ASC_MC_IDLE_CMD_PARAMETER, + idle_cmd_parameter); AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd); - DvcLeaveCritical(last_int_level); /* - * If the 'flags' argument contains the ADV_NOWAIT flag, then - * return with success. + * Tickle the RISC to tell it to process the idle command. */ - if (flags & ADV_NOWAIT) + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { - return ADV_TRUE; - } - - for (i = 0; i < SCSI_WAIT_10_SEC * SCSI_MS_PER_SEC; i++) - { - /* - * 'idle_cmd_done' is set by AdvISR(). - */ - if (asc_dvc->idle_cmd_done) - { - break; - } - DvcSleepMilliSecond(1); - /* - * If interrupts were disabled on entry to AdvSendIdleCmd(), - * then they will still be disabled here. Call AdvISR() to - * check for the idle command completion. + * Clear the tickle value. In the ASC-3550 the RISC flag + * command 'clr_tickle_b' does not work unless the host + * value is cleared. */ - (void) AdvISR(asc_dvc); - } - - last_int_level = DvcEnterCritical(); - - if (asc_dvc->idle_cmd_done == ADV_FALSE) - { - ADV_ASSERT(0); /* The idle command should never timeout. */ - return ADV_FALSE; - } else - { - AdvReadWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, ret); - return ret; - } -} - -/* - * Send the SCSI request block to the adapter - * - * Each of the 255 Adv Library/Microcode RISC Lists or mailboxes has the - * following structure: - * - * 0: RQL_FWD - RISC list forward pointer (1 byte) - * 1: RQL_BWD - RISC list backward pointer (1 byte) - * 2: RQL_STATE - RISC list state byte - free, ready, done, aborted (1 byte) - * 3: RQL_TID - request target id (1 byte) - * 4: RQL_PHYADDR - ADV_SCSI_REQ_Q physical pointer (4 bytes) - * - * Return: - * ADV_SUCCESS(1) - the request is in the mailbox - * ADV_BUSY(0) - total request count > 253, try later - */ -STATIC int -AdvSendScsiCmd( - ADV_DVC_VAR *asc_dvc, - ADV_SCSI_REQ_Q *scsiq) -{ - ushort next_ready_loc; - uchar next_ready_loc_fwd; - int last_int_level; - AdvPortAddr iop_base; - long req_size; - ulong q_phy_addr; - - /* - * The ADV_SCSI_REQ_Q 'target_id' field should never be equal - * to the host adapter ID or exceed ADV_MAX_TID. - */ - if (scsiq->target_id == asc_dvc->chip_scsi_id || - scsiq->target_id > ADV_MAX_TID) - { - scsiq->host_status = QHSTA_M_INVALID_DEVICE; - scsiq->done_status = QD_WITH_ERROR; - return ADV_ERROR; + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); } - iop_base = asc_dvc->iop_base; - - last_int_level = DvcEnterCritical(); - - if (asc_dvc->cur_host_qng >= asc_dvc->max_host_qng) - { - DvcLeaveCritical(last_int_level); - return ADV_BUSY; - } else + /* Wait for up to 100 millisecond for the idle command to timeout. */ + for (i = 0; i < SCSI_WAIT_100_MSEC; i++) { - ADV_ASSERT(asc_dvc->cur_host_qng < ASC_MC_RISC_Q_TOTAL_CNT); - asc_dvc->cur_host_qng++; + /* Poll once each microsecond for command completion. */ + for (j = 0; j < SCSI_US_PER_MSEC; j++) + { + AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, result); + if (result != 0) + { + DvcLeaveCritical(last_int_level); + return result; + } + DvcDelayMicroSecond(asc_dvc, (ushort) 1); + } } - /* - * Clear the ADV_SCSI_REQ_Q done flag. - */ - scsiq->a_flag &= ~ADV_SCSIQ_DONE; - - /* - * Save the original sense buffer length. - * - * After the request completes 'sense_len' will be set to the residual - * byte count of the Auto-Request Sense if a command returns CHECK - * CONDITION and the Sense Data is valid indicated by 'host_status' not - * being set to QHSTA_M_AUTO_REQ_SENSE_FAIL. To determine the valid - * Sense Data Length subtract 'sense_len' from 'orig_sense_len'. - */ - scsiq->orig_sense_len = scsiq->sense_len; - - AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc); - next_ready_loc = ASC_MC_RISC_Q_LIST_BASE + - (next_ready_loc * ASC_MC_RISC_Q_LIST_SIZE); - - /* - * Write the physical address of the Q to the mailbox. - * We need to skip the first four bytes, because the microcode - * uses them internally for linking Q's together. - */ - req_size = sizeof(ADV_SCSI_REQ_Q); - q_phy_addr = DvcGetPhyAddr(asc_dvc, scsiq, - (uchar *) scsiq, &req_size, - ADV_IS_SCSIQ_FLAG); - ADV_ASSERT(ADV_DWALIGN(q_phy_addr) == q_phy_addr); - ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q)); - - scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq; - - /* - * The RISC list structure, which 'next_ready_loc' is a pointer - * to in microcode LRAM, has the format detailed in the comment - * header for this function. - * - * Write the ADV_SCSI_REQ_Q physical pointer to 'next_ready_loc' request. - */ - AdvWriteDWordLram(iop_base, next_ready_loc + RQL_PHYADDR, q_phy_addr); - - /* Write target_id to 'next_ready_loc' request. */ - AdvWriteByteLram(iop_base, next_ready_loc + RQL_TID, scsiq->target_id); - - /* - * Set the ASC_MC_HOST_NEXT_READY (0x128) microcode variable to - * the 'next_ready_loc' request forward pointer. - * - * Do this *before* changing the 'next_ready_loc' queue to QS_READY. - * After the state is changed to QS_READY 'RQL_FWD' will be changed - * by the microcode. - * - * NOTE: The temporary variable 'next_ready_loc_fwd' is required to - * prevent some compilers from optimizing out 'AdvReadByteLram()' if - * it were used as the 3rd argument to 'AdvWriteByteLram()'. - */ - AdvReadByteLram(iop_base, next_ready_loc + RQL_FWD, next_ready_loc_fwd); - AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc_fwd); - - /* - * Change the state of 'next_ready_loc' request from QS_FREE to - * QS_READY which will cause the microcode to pick it up and - * execute it. - * - * Can't reference 'next_ready_loc' after changing the request - * state to QS_READY. The microcode now owns the request. - */ - AdvWriteByteLram(iop_base, next_ready_loc + RQL_STATE, ASC_MC_QS_READY); - + ADV_ASSERT(0); /* The idle command should never timeout. */ DvcLeaveCritical(last_int_level); - return ADV_SUCCESS; + return ADV_ERROR; } /* * Inquiry Information Byte 7 Handling * * Handle SCSI Inquiry Command information for a device by setting - * microcode operating variables that affect WDTR, SDTR, and Tag + * microcode operating variables that affect WDTR, SDTR, and Tag * Queuing. */ STATIC void AdvInquiryHandling( - ADV_DVC_VAR *asc_dvc, - ADV_SCSI_REQ_Q *scsiq) + ADV_DVC_VAR *asc_dvc, + ADV_SCSI_REQ_Q *scsiq) { - AdvPortAddr iop_base; - uchar tid; - ASC_SCSI_INQUIRY *inq; - ushort tidmask; - ushort cfg_word; + AdvPortAddr iop_base; + uchar tid; + ADV_SCSI_INQUIRY *inq; + ushort tidmask; + ushort cfg_word; /* * AdvInquiryHandling() requires up to INQUIRY information Byte 7 @@ -15318,6 +17958,7 @@ * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the * microcode to the transfer residual count. */ + if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8) { return; @@ -15325,12 +17966,13 @@ iop_base = asc_dvc->iop_base; tid = scsiq->target_id; - inq = (ASC_SCSI_INQUIRY *) scsiq->vdata_addr; + + inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr; /* * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices. */ - if (inq->byte3.rsp_data_fmt < 2 && inq->byte2.ansi_apr_ver < 2) + if (inq->rsp_data_fmt < 2 && inq->ansi_apr_ver < 2) { return; } else @@ -15354,7 +17996,7 @@ * device's 'wdtr_able' bit and write the new value to the * microcode. */ - if ((asc_dvc->wdtr_able & tidmask) && inq->byte7.WBus16) + if ((asc_dvc->wdtr_able & tidmask) && inq->WBus16) { AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); if ((cfg_word & tidmask) == 0) @@ -15363,10 +18005,15 @@ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); /* - * Clear the microcode "WDTR negotiation" done indicator - * for the target to cause it to negotiate with the new - * setting set above. + * Clear the microcode "SDTR negotiation" and "WDTR + * negotiation" done indicators for the target to cause + * it to negotiate with the new setting set above. + * WDTR when accepted causes the target to enter + * asynchronous mode, so SDTR must be negotiated. */ + AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); + cfg_word &= ~tidmask; + AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word); cfg_word &= ~tidmask; AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word); @@ -15380,7 +18027,7 @@ * supports synchronous transfers, then turn on the device's * 'sdtr_able' bit. Write the new value to the microcode. */ - if ((asc_dvc->sdtr_able & tidmask) && inq->byte7.Sync) + if ((asc_dvc->sdtr_able & tidmask) && inq->Sync) { AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); if ((cfg_word & tidmask) == 0) @@ -15400,8 +18047,8 @@ } /* - * If the EEPROM enabled Tag Queuing for device and the - * device supports Tag Queuing, then turn on the device's + * If the EEPROM enabled Tag Queuing for the device and the + * device supports Tag Queueing, then turn on the device's * 'tagqng_enable' bit in the microcode and set the microcode * maximum command count to the ADV_DVC_VAR 'max_dvc_qng' * value. @@ -15411,11 +18058,12 @@ * disabling Tag Queuing in the BIOS devices with Tag Queuing * bugs will at least work with the BIOS. */ - if ((asc_dvc->tagqng_able & tidmask) && inq->byte7.CmdQue) + if ((asc_dvc->tagqng_able & tidmask) && inq->CmdQue) { AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); cfg_word |= tidmask; AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); + AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, asc_dvc->max_dvc_qng); } diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.3.16/linux/drivers/scsi/hosts.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/scsi/hosts.c Tue Sep 7 10:20:11 1999 @@ -758,11 +758,11 @@ * Why is this a separate function? Because the kernel_thread code * effectively does a fork, and there is a builtin exit() call when * the child returns. The difficulty is that scsi_init() is - * marked __initfunc(), which means the memory is unmapped after bootup + * marked __init, which means the memory is unmapped after bootup * is complete, which means that the thread's exit() call gets wiped. * * The lesson is to *NEVER*, *NEVER* call kernel_thread() from an - * __initfunc() function, if that function could ever return. + * __init function, if that function could ever return. */ static void launch_error_handler_thread(struct Scsi_Host * shpnt) { diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/i60uscsi.c linux/drivers/scsi/i60uscsi.c --- v2.3.16/linux/drivers/scsi/i60uscsi.c Mon Jul 5 20:36:12 1999 +++ linux/drivers/scsi/i60uscsi.c Thu Sep 2 10:03:26 1999 @@ -64,16 +64,21 @@ * 09/24/98 hl - v1.01b Fixed reset. * 10/05/98 hl - v1.02 split the source code and release. * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up + * 01/31/99 bv - v1.02b Use mdelay instead of waitForPause + * 08/08/99 bv - v1.02c Use waitForPause again. **************************************************************************/ #ifndef CVT_LINUX_VERSION #define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S) #endif +#include #include #include #include "i60uscsi.h" +#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ) +#define MS_TO_JIFFIES(j) ((j * HZ) / 1000) /* ---- INTERNAL FUNCTIONS ---- */ static UCHAR waitChipReady(ORC_HCS * hcsp); @@ -155,7 +160,7 @@ /***************************************************************************/ static void waitForPause(unsigned amount) { - ULONG the_time = jiffies + amount; /* 0.01 seconds per jiffy */ + ULONG the_time = jiffies + MS_TO_JIFFIES(amount); #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) while (time_before_eq(jiffies, the_time)); @@ -169,10 +174,10 @@ { int i; - for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */ return (TRUE); - waitForPause(5); /* wait 500ms before try again */ + waitForPause(100); /* wait 100ms before try again */ } return (FALSE); } @@ -182,10 +187,10 @@ { int i; - for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) /* Wait READY set */ return (TRUE); - waitForPause(5); /* wait 500ms before try again */ + waitForPause(100); /* wait 100ms before try again */ } return (FALSE); } @@ -195,10 +200,10 @@ { int i; - for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */ return (TRUE); - waitForPause(5); /* wait 500ms before try again */ + waitForPause(100); /* wait 100ms before try again */ } return (FALSE); } @@ -208,10 +213,10 @@ { int i; - for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO)) /* Wait HDO off */ return (TRUE); - waitForPause(5); /* wait 500ms before try again */ + waitForPause(100); /* wait 100ms before try again */ } return (FALSE); } @@ -221,10 +226,10 @@ { int i; - for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI) return (TRUE); /* Wait HDI set */ - waitForPause(5); /* wait 500ms before try again */ + waitForPause(100); /* wait 100ms before try again */ } return (FALSE); } @@ -463,15 +468,9 @@ pVirEscb = (ESCB *) hcsp->HCS_virEscbArray; for (i = 0; i < orc_num_scb; i++) { -#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) - pPhysEscb = (PVOID) ((ULONG) hcsp->HCS_virEscbArray + (sizeof(ESCB) * i)); - pVirScb->SCB_SGPAddr = (U32) VIRT_TO_BUS(pPhysEscb); - pVirScb->SCB_SensePAddr = (U32) VIRT_TO_BUS(pPhysEscb); -#else pPhysEscb = (PVOID) (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i)); pVirScb->SCB_SGPAddr = (U32) pPhysEscb; pVirScb->SCB_SensePAddr = (U32) pPhysEscb; -#endif pVirScb->SCB_EScb = pVirEscb; pVirScb->SCB_ScbIdx = i; pVirScb++; diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/i60uscsi.h linux/drivers/scsi/i60uscsi.h --- v2.3.16/linux/drivers/scsi/i60uscsi.h Wed Feb 24 16:27:54 1999 +++ linux/drivers/scsi/i60uscsi.h Thu Sep 2 10:03:26 1999 @@ -60,8 +60,6 @@ * 12/19/98 bv, v1.02a Use spinlocks for 2.1.95 and up. **************************************************************************/ -#include - #define ULONG unsigned long #define PVOID void * #define USHORT unsigned short diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c --- v2.3.16/linux/drivers/scsi/in2000.c Thu Aug 27 16:41:29 1998 +++ linux/drivers/scsi/in2000.c Thu Sep 2 10:03:26 1999 @@ -1845,7 +1845,7 @@ static char setup_used[MAX_SETUP_ARGS]; static int done_setup = 0; -in2000__INITFUNC( void in2000_setup (char *str, int *ints) ) +void __init in2000_setup (char *str, int *ints) { int i; char *p1,*p2; @@ -1877,7 +1877,7 @@ /* check_setup_args() returns index if key found, 0 if not */ -in2000__INITFUNC( static int check_setup_args(char *key, int *flags, int *val, char *buf) ) +static int __init check_setup_args(char *key, int *flags, int *val, char *buf) { int x; char *cp; @@ -1931,7 +1931,7 @@ }; -in2000__INITFUNC( int in2000_detect(Scsi_Host_Template * tpnt) ) +int __init in2000_detect(Scsi_Host_Template * tpnt) { struct Scsi_Host *instance; struct IN2000_hostdata *hostdata; diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c --- v2.3.16/linux/drivers/scsi/inia100.c Mon Aug 9 10:25:01 1999 +++ linux/drivers/scsi/inia100.c Thu Sep 2 10:03:26 1999 @@ -73,13 +73,19 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) #include +#include #include +#include #include +#include +#include #include +#include #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92) #include #endif #include +#include #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23) #include #endif @@ -87,27 +93,34 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) #include #endif +#include "sd.h" +#include "scsi.h" +#include "hosts.h" +#include "inia100.h" #include +#include +#include + #else +#include #include #include -#include -#include "../block/blk.h" -#endif - -#include #include #include + #include #include +#include #include +#include "../block/blk.h" #include "scsi.h" #include "sd.h" #include "hosts.h" #include #include "inia100.h" +#endif #ifdef MODULE Scsi_Host_Template driver_template = INIA100; @@ -119,7 +132,7 @@ char *inia100_Copyright = "Copyright (C) 1998-99"; char *inia100_InitioName = "by Initio Corporation"; char *inia100_ProductName = "INI-A100U2W"; -char *inia100_Version = "v1.02a"; +char *inia100_Version = "v1.02c"; #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) struct proc_dir_entry proc_scsi_inia100 = diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/inia100.h linux/drivers/scsi/inia100.h --- v2.3.16/linux/drivers/scsi/inia100.h Wed Aug 18 16:44:58 1999 +++ linux/drivers/scsi/inia100.h Tue Sep 7 11:50:58 1999 @@ -83,7 +83,7 @@ extern int inia100_biosparam(Disk *, int, int *); /*for linux v1.13 */ #endif -#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02a" +#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02c" #if LINUX_VERSION_CODE < CVT_LINUX_VERSION(1, 3, 0) #define INIA100 { \ diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/mca_53c9x.c linux/drivers/scsi/mca_53c9x.c --- v2.3.16/linux/drivers/scsi/mca_53c9x.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/scsi/mca_53c9x.c Tue Sep 7 10:14:37 1999 @@ -157,7 +157,7 @@ { printk("Unable to request IRQ %d.\n", esp->irq); esp_deallocate(esp); - unregister_scsi(esp->ehost); + scsi_unregister(esp->ehost); return 0; } @@ -166,7 +166,7 @@ esp->dma); free_irq(esp->irq, esp_intr); esp_deallocate(esp); - unregister_scsi(esp->ehost); + scsi_unregister(esp->ehost); return 0; } diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.3.16/linux/drivers/scsi/scsi.c Mon Aug 9 19:21:33 1999 +++ linux/drivers/scsi/scsi.c Sat Sep 4 10:48:46 1999 @@ -71,8 +71,8 @@ #undef USE_STATIC_SCSI_MEMORY /* -static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $"; -*/ + static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $"; + */ /* * Definitions and constants. @@ -87,11 +87,11 @@ #define SECTORS_PER_PAGE (PAGE_SIZE/SECTOR_SIZE) #if SECTORS_PER_PAGE <= 8 - typedef unsigned char FreeSectorBitmap; +typedef unsigned char FreeSectorBitmap; #elif SECTORS_PER_PAGE <= 32 - typedef unsigned int FreeSectorBitmap; +typedef unsigned int FreeSectorBitmap; #else -# error You lose. +#error You lose. #endif #define MIN_RESET_DELAY (2*HZ) @@ -116,60 +116,63 @@ /* * Data declarations. */ -unsigned long scsi_pid = 0; -Scsi_Cmnd * last_cmnd = NULL; +unsigned long scsi_pid = 0; +Scsi_Cmnd *last_cmnd = NULL; /* Command groups 3 and 4 are reserved and should never be used. */ -const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, - 12, 12, 10, 10 }; -static unsigned long serial_number = 0; -static Scsi_Cmnd * scsi_bh_queue_head = NULL; -static Scsi_Cmnd * scsi_bh_queue_tail = NULL; -static FreeSectorBitmap * dma_malloc_freelist = NULL; -static int need_isa_bounce_buffers; -static unsigned int dma_sectors = 0; -unsigned int scsi_dma_free_sectors = 0; -unsigned int scsi_need_isa_buffer = 0; -static unsigned char ** dma_malloc_pages = NULL; +const unsigned char scsi_command_size[8] = { + 6, 10, 10, 12, + 12, 12, 10, 10 +}; +static unsigned long serial_number = 0; +static Scsi_Cmnd *scsi_bh_queue_head = NULL; +static Scsi_Cmnd *scsi_bh_queue_tail = NULL; +static FreeSectorBitmap *dma_malloc_freelist = NULL; +static int need_isa_bounce_buffers; +static unsigned int dma_sectors = 0; +unsigned int scsi_dma_free_sectors = 0; +unsigned int scsi_need_isa_buffer = 0; +static unsigned char **dma_malloc_pages = NULL; /* * Note - the initial logging level can be set here to log events at boot time. * After the system is up, you may enable logging via the /proc interface. */ -unsigned int scsi_logging_level = 0; +unsigned int scsi_logging_level = 0; -volatile struct Scsi_Host * host_active = NULL; +volatile struct Scsi_Host *host_active = NULL; #if CONFIG_PROC_FS /* * This is the pointer to the /proc/scsi code. * It is only initialized to !=0 if the scsi code is present */ -struct proc_dir_entry proc_scsi_scsi = { - PROC_SCSI_SCSI, 4, "scsi", - S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0, - NULL, - NULL, NULL, - NULL, NULL, NULL +struct proc_dir_entry proc_scsi_scsi = +{ + PROC_SCSI_SCSI, 4, "scsi", + S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0, + NULL, + NULL, NULL, + NULL, NULL, NULL }; #endif const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = { - "Direct-Access ", - "Sequential-Access", - "Printer ", - "Processor ", - "WORM ", - "CD-ROM ", - "Scanner ", - "Optical Device ", - "Medium Changer ", - "Communications ", - "Unknown ", - "Unknown ", - "Unknown ", - "Enclosure ", + "Direct-Access ", + "Sequential-Access", + "Printer ", + "Processor ", + "WORM ", + "CD-ROM ", + "Scanner ", + "Optical Device ", + "Medium Changer ", + "Communications ", + "Unknown ", + "Unknown ", + "Unknown ", + "Enclosure ", }; /* @@ -177,23 +180,23 @@ */ static void resize_dma_pool(void); static void print_inquiry(unsigned char *data); -extern void scsi_times_out (Scsi_Cmnd * SCpnt); -static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev , - int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt, - struct Scsi_Host *shpnt, char * scsi_result); -void scsi_build_commandblocks(Scsi_Device * SDpnt); -static int scsi_unregister_device(struct Scsi_Device_Template * tpnt); +extern void scsi_times_out(Scsi_Cmnd * SCpnt); +static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev, + int *sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt, + struct Scsi_Host *shpnt, char *scsi_result); +void scsi_build_commandblocks(Scsi_Device * SDpnt); +static int scsi_unregister_device(struct Scsi_Device_Template *tpnt); /* * These are the interface to the old error handling code. It should go away * someday soon. */ -extern void scsi_old_done (Scsi_Cmnd *SCpnt); -extern void scsi_old_times_out (Scsi_Cmnd * SCpnt); +extern void scsi_old_done(Scsi_Cmnd * SCpnt); +extern void scsi_old_times_out(Scsi_Cmnd * SCpnt); #if CONFIG_PROC_FS -extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start, - off_t offset, int length, int inout); +extern int (*dispatch_scsi_info_ptr) (int ino, char *buffer, char **start, + off_t offset, int length, int inout); extern int dispatch_scsi_info(int ino, char *buffer, char **start, off_t offset, int length, int inout); #endif @@ -207,11 +210,11 @@ static void scsi_dump_status(int level); -struct dev_info{ - const char * vendor; - const char * model; - const char * revision; /* Latest revision known to be bad. Not used yet */ - unsigned flags; +struct dev_info { + const char *vendor; + const char *model; + const char *revision; /* Latest revision known to be bad. Not used yet */ + unsigned flags; }; /* @@ -221,99 +224,106 @@ */ static struct dev_info device_list[] = { -{"Aashima","IMAGERY 2400SP","1.03",BLIST_NOLUN},/* Locks up if polled for lun != 0 */ -{"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ -{"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ -{"DENON","DRD-25X","V", BLIST_NOLUN}, /* Locks up if probed for lun != 0 */ -{"HITACHI","DK312C","CM81", BLIST_NOLUN}, /* Responds to all lun - dtg */ -{"HITACHI","DK314C","CR21" , BLIST_NOLUN}, /* responds to all lun */ -{"IMS", "CDD521/10","2.06", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ -{"MAXTOR","XT-3280","PR02", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ -{"MAXTOR","XT-4380S","B3C", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ -{"MAXTOR","MXT-1240S","I1.2", BLIST_NOLUN}, /* Locks up when LUN>0 polled */ -{"MAXTOR","XT-4170S","B5A", BLIST_NOLUN}, /* Locks-up sometimes when LUN>0 polled. */ -{"MAXTOR","XT-8760S","B7B", BLIST_NOLUN}, /* guess what? */ -{"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */ -{"MICROP", "4110", "*", BLIST_NOTQ}, /* Buggy Tagged Queuing */ -{"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ -{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* Responds to all lun */ -{"RODIME","RO3000S","2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ -{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for aha152x controller, which causes - * SCSI code to reset bus.*/ -{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for aha152x controller, which causes - * SCSI code to reset bus.*/ -{"SEAGATE", "ST296","921", BLIST_NOLUN}, /* Responds to all lun */ -{"SEAGATE","ST1581","6538",BLIST_NOLUN}, /* Responds to all lun */ -{"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN}, -{"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN}, -{"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN}, -{"SONY","CD-ROM CDU-8012","*", BLIST_NOLUN}, -{"TANDBERG","TDC 3600","U07", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ -{"TEAC","CD-R55S","1.0H", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ -{"TEAC","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for seagate controller, which causes - * SCSI code to reset bus.*/ -{"TEXEL","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for seagate controller, which causes - * SCSI code to reset bus.*/ -{"QUANTUM","LPS525S","3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ -{"QUANTUM","PD1225S","3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ -{"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ -{"SANKYO", "CP525","6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */ -{"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ -{"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ -{"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ -{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* extra reset */ -{"RELISYS", "Scorpio", "*", BLIST_NOLUN}, /* responds to all LUN */ + {"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ + {"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ + {"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ + {"DENON", "DRD-25X", "V", BLIST_NOLUN}, /* Locks up if probed for lun != 0 */ + {"HITACHI", "DK312C", "CM81", BLIST_NOLUN}, /* Responds to all lun - dtg */ + {"HITACHI", "DK314C", "CR21", BLIST_NOLUN}, /* responds to all lun */ + {"IMS", "CDD521/10", "2.06", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ + {"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ + {"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ + {"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN}, /* Locks up when LUN>0 polled */ + {"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN}, /* Locks-up sometimes when LUN>0 polled. */ + {"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN}, /* guess what? */ + {"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN}, /*Responds to all lun */ + {"MICROP", "4110", "*", BLIST_NOTQ}, /* Buggy Tagged Queuing */ + {"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ + {"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* Responds to all lun */ + {"RODIME", "RO3000S", "2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ + {"SANYO", "CRD-250S", "1.20", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for aha152x controller, which causes + * SCSI code to reset bus.*/ + {"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for aha152x controller, which causes + * SCSI code to reset bus.*/ + {"SEAGATE", "ST296", "921", BLIST_NOLUN}, /* Responds to all lun */ + {"SEAGATE", "ST1581", "6538", BLIST_NOLUN}, /* Responds to all lun */ + {"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN}, + {"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN}, + {"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN}, + {"SONY", "CD-ROM CDU-8012", "*", BLIST_NOLUN}, + {"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ + {"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ + {"TEAC", "CD-ROM", "1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for seagate controller, which causes + * SCSI code to reset bus.*/ + {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for seagate controller, which causes + * SCSI code to reset bus.*/ + {"QUANTUM", "LPS525S", "3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ + {"QUANTUM", "PD1225S", "3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ + {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ + {"SANKYO", "CP525", "6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */ + {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ + {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ + {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ + {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* extra reset */ + {"RELISYS", "Scorpio", "*", BLIST_NOLUN}, /* responds to all LUN */ /* * Other types of devices that have special flags. */ -{"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN}, -{"TEXEL","CD-ROM","1.06", BLIST_BORKEN}, -{"IOMEGA","Io20S *F","*", BLIST_KEY}, -{"INSITE","Floptical F*8I","*", BLIST_KEY}, -{"INSITE","I325VM","*", BLIST_KEY}, -{"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"REGAL","CDC-4X","*", BLIST_MAX5LUN | BLIST_SINGLELUN}, -{"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"NAKAMICH","MJ-5.16S","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"EMULEX","MD21/S2 ESDI","*", BLIST_SINGLELUN}, -{"CANON","IPUBJD","*", BLIST_SPARSELUN}, -{"nCipher","Fastness Crypto","*", BLIST_FORCELUN}, -{"NEC","PD-1 ODX654P","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"YAMAHA","CDR100","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ -{"YAMAHA","CDR102","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ -{"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN}, -/* - * Must be at end of list... - */ -{NULL, NULL, NULL} + {"SONY", "CD-ROM CDU-8001", "*", BLIST_BORKEN}, + {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, + {"IOMEGA", "Io20S *F", "*", BLIST_KEY}, + {"INSITE", "Floptical F*8I", "*", BLIST_KEY}, + {"INSITE", "I325VM", "*", BLIST_KEY}, + {"NRC", "MBR-7", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NRC", "MBR-7.4", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN}, + {"NAKAMICH", "MJ-4.8S", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NAKAMICH", "MJ-5.16S", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"EMULEX", "MD21/S2 ESDI", "*", BLIST_SINGLELUN}, + {"CANON", "IPUBJD", "*", BLIST_SPARSELUN}, + {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN}, + {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"MATSHITA", "PD", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ + {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ + {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, + + /* + * Must be at end of list... + */ + {NULL, NULL, NULL} }; -static int get_device_flags(unsigned char * response_data){ - int i = 0; - unsigned char * pnt; - for(i=0; 1; i++){ - if(device_list[i].vendor == NULL) return 0; - pnt = &response_data[8]; - while(*pnt && *pnt == ' ') pnt++; - if(memcmp(device_list[i].vendor, pnt, - strlen(device_list[i].vendor))) continue; - pnt = &response_data[16]; - while(*pnt && *pnt == ' ') pnt++; - if(memcmp(device_list[i].model, pnt, - strlen(device_list[i].model))) continue; - return device_list[i].flags; - } - return 0; +static int get_device_flags(unsigned char *response_data) +{ + int i = 0; + unsigned char *pnt; + for (i = 0; 1; i++) { + if (device_list[i].vendor == NULL) + return 0; + pnt = &response_data[8]; + while (*pnt && *pnt == ' ') + pnt++; + if (memcmp(device_list[i].vendor, pnt, + strlen(device_list[i].vendor))) + continue; + pnt = &response_data[16]; + while (*pnt && *pnt == ' ') + pnt++; + if (memcmp(device_list[i].model, pnt, + strlen(device_list[i].model))) + continue; + return device_list[i].flags; + } + return 0; } /* @@ -338,72 +348,74 @@ * I (ERY) would like to make this go away someday, but this would * require that we have a recursive mutex object. */ -void -scsi_make_blocked_list(void) + +void scsi_make_blocked_list(void) { - int block_count = 0, index; - struct Scsi_Host * sh[128], * shpnt; + int block_count = 0, index; + struct Scsi_Host *sh[128], *shpnt; - /* - * Create a circular linked list from the scsi hosts which have - * the "wish_block" field in the Scsi_Host structure set. - * The blocked list should include all the scsi hosts using ISA DMA. - * In some systems, using two dma channels simultaneously causes - * unpredictable results. - * Among the scsi hosts in the blocked list, only one host at a time - * is allowed to have active commands queued. The transition from - * one active host to the next one is allowed only when host_busy == 0 - * for the active host (which implies host_busy == 0 for all the hosts - * in the list). Moreover for block devices the transition to a new - * active host is allowed only when a request is completed, since a - * block device request can be divided into multiple scsi commands - * (when there are few sg lists or clustering is disabled). - * - * (DB, 4 Feb 1995) - */ + /* + * Create a circular linked list from the scsi hosts which have + * the "wish_block" field in the Scsi_Host structure set. + * The blocked list should include all the scsi hosts using ISA DMA. + * In some systems, using two dma channels simultaneously causes + * unpredictable results. + * Among the scsi hosts in the blocked list, only one host at a time + * is allowed to have active commands queued. The transition from + * one active host to the next one is allowed only when host_busy == 0 + * for the active host (which implies host_busy == 0 for all the hosts + * in the list). Moreover for block devices the transition to a new + * active host is allowed only when a request is completed, since a + * block device request can be divided into multiple scsi commands + * (when there are few sg lists or clustering is disabled). + * + * (DB, 4 Feb 1995) + */ - - host_active = NULL; - for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) { + host_active = NULL; + + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { #if 0 - /* - * Is this is a candidate for the blocked list? - * Useful to put into the blocked list all the hosts whose driver - * does not know about the host->block feature. - */ - if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1; + /* + * Is this is a candidate for the blocked list? + * Useful to put into the blocked list all the hosts whose driver + * does not know about the host->block feature. + */ + if (shpnt->unchecked_isa_dma) + shpnt->wish_block = 1; #endif - if (shpnt->wish_block) sh[block_count++] = shpnt; - } + if (shpnt->wish_block) + sh[block_count++] = shpnt; + } - if (block_count == 1) sh[0]->block = NULL; + if (block_count == 1) + sh[0]->block = NULL; - else if (block_count > 1) { - - for(index = 0; index < block_count - 1; index++) { - sh[index]->block = sh[index + 1]; - printk("scsi%d : added to blocked host list.\n", - sh[index]->host_no); - } + else if (block_count > 1) { - sh[block_count - 1]->block = sh[0]; - printk("scsi%d : added to blocked host list.\n", - sh[index]->host_no); - } + for (index = 0; index < block_count - 1; index++) { + sh[index]->block = sh[index + 1]; + printk("scsi%d : added to blocked host list.\n", + sh[index]->host_no); + } + sh[block_count - 1]->block = sh[0]; + printk("scsi%d : added to blocked host list.\n", + sh[index]->host_no); + } } -static void scan_scsis_done (Scsi_Cmnd * SCpnt) +static void scan_scsis_done(Scsi_Cmnd * SCpnt) { - SCSI_LOG_MLCOMPLETE(1,printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result)); - SCpnt->request.rq_status = RQ_SCSI_DONE; + SCSI_LOG_MLCOMPLETE(1, printk("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result)); + SCpnt->request.rq_status = RQ_SCSI_DONE; - if (SCpnt->request.sem != NULL) - up(SCpnt->request.sem); + if (SCpnt->request.sem != NULL) + up(SCpnt->request.sem); } MODULE_PARM(scsi_logging_level, "i"); @@ -411,18 +423,18 @@ #ifndef MODULE -static int __init scsi_logging_setup (char *str) +static int __init scsi_logging_setup(char *str) { int tmp; - if (get_option(&str, &tmp)==1) { - scsi_logging_level = (tmp ? ~0 : 0); + if (get_option(&str, &tmp) == 1) { + scsi_logging_level = (tmp ? ~0 : 0); return 1; } else { printk("scsi_logging_setup : usage scsi_logging_level=n " - "(n should be 0 or non-zero)\n"); + "(n should be 0 or non-zero)\n"); return 0; - } + } } __setup("scsi_logging=", scsi_logging_setup); @@ -440,18 +452,18 @@ #ifndef MODULE -static int __init scsi_luns_setup (char *str) +static int __init scsi_luns_setup(char *str) { int tmp; - if (get_option(&str, &tmp)==1) { + if (get_option(&str, &tmp) == 1) { max_scsi_luns = tmp; return 1; } else { printk("scsi_luns_setup : usage max_scsi_luns=n " - "(n should be between 1 and 8)\n"); + "(n should be between 1 and 8)\n"); return 0; - } + } } __setup("max_scsi_luns=", scsi_luns_setup); @@ -465,204 +477,196 @@ * lun address of all sequential devices to the tape driver, all random * devices to the disk driver. */ -static void scan_scsis (struct Scsi_Host *shpnt, - unchar hardcoded, - unchar hchannel, - unchar hid, - unchar hlun) -{ - int channel; - int dev; - int lun; - int max_dev_lun; - Scsi_Cmnd * SCpnt; - unsigned char * scsi_result; - unsigned char scsi_result0[256]; - Scsi_Device * SDpnt; - Scsi_Device * SDtail; - int sparse_lun; - - scsi_result = NULL; - SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), - GFP_ATOMIC | GFP_DMA); - if (SCpnt) { - SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), - GFP_ATOMIC); - if (SDpnt) { - /* Make sure we have something that is valid for DMA purposes */ - scsi_result = ( ( !shpnt->unchecked_isa_dma ) - ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA)); - } - } - - if (scsi_result == NULL) - { - printk ("Unable to obtain scsi_result buffer\n"); - goto leave; - } - - /* - * We must chain ourself in the host_queue, so commands can time out - */ - SCpnt->next = NULL; - SDpnt->device_queue = SCpnt; - SDpnt->host = shpnt; - SDpnt->online = TRUE; - - init_waitqueue_head(&SDpnt->device_wait); - - /* - * Next, hook the device to the host in question. - */ - SDpnt->prev = NULL; - SDpnt->next = NULL; - if( shpnt->host_queue != NULL ) - { - SDtail = shpnt->host_queue; - while( SDtail->next != NULL ) - SDtail = SDtail->next; - - SDtail->next = SDpnt; - SDpnt->prev = SDtail; - } - else - { - shpnt->host_queue = SDpnt; - } - - /* - * We need to increment the counter for this one device so we can track when - * things are quiet. - */ - atomic_inc(&shpnt->host_active); - - if (hardcoded == 1) { - Scsi_Device *oldSDpnt=SDpnt; - struct Scsi_Device_Template * sdtpnt; - channel = hchannel; - if(channel > shpnt->max_channel) goto leave; - dev = hid; - if(dev >= shpnt->max_id) goto leave; - lun = hlun; - if(lun >= shpnt->max_lun) goto leave; - scan_scsis_single (channel, dev, lun, &max_dev_lun, &sparse_lun, - &SDpnt, SCpnt, shpnt, scsi_result); - if(SDpnt!=oldSDpnt) { - - /* it could happen the blockdevice hasn't yet been inited */ - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); - - oldSDpnt->scsi_request_fn = NULL; - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { - if(sdtpnt->attach) { - (*sdtpnt->attach)(oldSDpnt); - if(oldSDpnt->attached) { - scsi_build_commandblocks(oldSDpnt); - if (0 == oldSDpnt->has_cmdblocks) { - printk("scan_scsis: DANGER, no command blocks\n"); - /* What to do now ?? */ - } +static void scan_scsis(struct Scsi_Host *shpnt, + unchar hardcoded, + unchar hchannel, + unchar hid, + unchar hlun) +{ + int channel; + int dev; + int lun; + int max_dev_lun; + Scsi_Cmnd *SCpnt; + unsigned char *scsi_result; + unsigned char scsi_result0[256]; + Scsi_Device *SDpnt; + Scsi_Device *SDtail; + int sparse_lun; + + scsi_result = NULL; + SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), + GFP_ATOMIC | GFP_DMA); + if (SCpnt) { + SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof(Scsi_Device), + GFP_ATOMIC); + if (SDpnt) { + /* Make sure we have something that is valid for DMA purposes */ + scsi_result = ((!shpnt->unchecked_isa_dma) + ? &scsi_result0[0] : scsi_init_malloc(512, GFP_DMA)); + } + } + if (scsi_result == NULL) { + printk("Unable to obtain scsi_result buffer\n"); + goto leave; + } + /* + * We must chain ourself in the host_queue, so commands can time out + */ + SCpnt->next = NULL; + SDpnt->device_queue = SCpnt; + SDpnt->host = shpnt; + SDpnt->online = TRUE; + + init_waitqueue_head(&SDpnt->device_wait); + + /* + * Next, hook the device to the host in question. + */ + SDpnt->prev = NULL; + SDpnt->next = NULL; + if (shpnt->host_queue != NULL) { + SDtail = shpnt->host_queue; + while (SDtail->next != NULL) + SDtail = SDtail->next; + + SDtail->next = SDpnt; + SDpnt->prev = SDtail; + } else { + shpnt->host_queue = SDpnt; + } + + /* + * We need to increment the counter for this one device so we can track when + * things are quiet. + */ + atomic_inc(&shpnt->host_active); + + if (hardcoded == 1) { + Scsi_Device *oldSDpnt = SDpnt; + struct Scsi_Device_Template *sdtpnt; + channel = hchannel; + if (channel > shpnt->max_channel) + goto leave; + dev = hid; + if (dev >= shpnt->max_id) + goto leave; + lun = hlun; + if (lun >= shpnt->max_lun) + goto leave; + scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun, + &SDpnt, SCpnt, shpnt, scsi_result); + if (SDpnt != oldSDpnt) { + + /* it could happen the blockdevice hasn't yet been inited */ + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if (sdtpnt->init && sdtpnt->dev_noticed) + (*sdtpnt->init) (); + + oldSDpnt->scsi_request_fn = NULL; + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { + if (sdtpnt->attach) { + (*sdtpnt->attach) (oldSDpnt); + if (oldSDpnt->attached) { + scsi_build_commandblocks(oldSDpnt); + if (0 == oldSDpnt->has_cmdblocks) { + printk("scan_scsis: DANGER, no command blocks\n"); + /* What to do now ?? */ + } + } + } + } + resize_dma_pool(); + + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { + if (sdtpnt->finish && sdtpnt->nr_dev) { + (*sdtpnt->finish) (); + } + } + } + } else { + /* Actual LUN. PC ordering is 0->n IBM/spec ordering is n->0 */ + int order_dev; + + for (channel = 0; channel <= shpnt->max_channel; channel++) { + for (dev = 0; dev < shpnt->max_id; ++dev) { + if (shpnt->reverse_ordering) + /* Shift to scanning 15,14,13... or 7,6,5,4, */ + order_dev = shpnt->max_id - dev - 1; + else + order_dev = dev; + + if (shpnt->this_id != order_dev) { + + /* + * We need the for so our continue, etc. work fine. We put this in + * a variable so that we can override it during the scan if we + * detect a device *KNOWN* to have multiple logical units. + */ + max_dev_lun = (max_scsi_luns < shpnt->max_lun ? + max_scsi_luns : shpnt->max_lun); + sparse_lun = 0; + for (lun = 0; lun < max_dev_lun; ++lun) { + if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun, + &sparse_lun, &SDpnt, SCpnt, shpnt, + scsi_result) + && !sparse_lun) + break; /* break means don't probe further for luns!=0 */ + } /* for lun ends */ + } /* if this_id != id ends */ + } /* for dev ends */ + } /* for channel ends */ + } /* if/else hardcoded */ + + /* + * We need to decrement the counter for this one device + * so we know when everything is quiet. + */ + atomic_dec(&shpnt->host_active); + + leave: + + { /* Unchain SCpnt from host_queue */ + Scsi_Device *prev, *next; + Scsi_Device *dqptr; + + for (dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next) + continue; + if (dqptr) { + prev = dqptr->prev; + next = dqptr->next; + if (prev) + prev->next = next; + else + shpnt->host_queue = next; + if (next) + next->prev = prev; } - } } - resize_dma_pool(); - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { - if(sdtpnt->finish && sdtpnt->nr_dev) - {(*sdtpnt->finish)();} - } - } - - } - else { - /* Actual LUN. PC ordering is 0->n IBM/spec ordering is n->0 */ - int order_dev; - - for (channel = 0; channel <= shpnt->max_channel; channel++) { - for (dev = 0; dev < shpnt->max_id; ++dev) { - if( shpnt->reverse_ordering) - /* Shift to scanning 15,14,13... or 7,6,5,4, */ - order_dev = shpnt->max_id-dev-1; - else - order_dev = dev; - - if (shpnt->this_id != order_dev) { - - /* - * We need the for so our continue, etc. work fine. We put this in - * a variable so that we can override it during the scan if we - * detect a device *KNOWN* to have multiple logical units. - */ - max_dev_lun = (max_scsi_luns < shpnt->max_lun ? - max_scsi_luns : shpnt->max_lun); - sparse_lun = 0; - for (lun = 0; lun < max_dev_lun; ++lun) { - if (!scan_scsis_single (channel, order_dev, lun, &max_dev_lun, - &sparse_lun, &SDpnt, SCpnt, shpnt, - scsi_result) - && !sparse_lun) - break; /* break means don't probe further for luns!=0 */ - } /* for lun ends */ - } /* if this_id != id ends */ - } /* for dev ends */ - } /* for channel ends */ - } /* if/else hardcoded */ - - /* - * We need to decrement the counter for this one device - * so we know when everything is quiet. - */ - atomic_dec(&shpnt->host_active); - - leave: - - {/* Unchain SCpnt from host_queue */ - Scsi_Device *prev, *next; - Scsi_Device * dqptr; - - for(dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next) - continue; - if(dqptr) - { - prev = dqptr->prev; - next = dqptr->next; - if(prev) - prev->next = next; - else - shpnt->host_queue = next; - if(next) next->prev = prev; - } - } - - /* Last device block does not exist. Free memory. */ - if (SDpnt != NULL) - scsi_init_free ((char *) SDpnt, sizeof (Scsi_Device)); - - if (SCpnt != NULL) - scsi_init_free ((char *) SCpnt, sizeof (Scsi_Cmnd)); - - /* If we allocated a buffer so we could do DMA, free it now */ - if (scsi_result != &scsi_result0[0] && scsi_result != NULL) - { - scsi_init_free (scsi_result, 512); - } - - { - Scsi_Device * sdev; - Scsi_Cmnd * scmd; - - SCSI_LOG_SCAN_BUS(4,printk("Host status for host %p:\n", shpnt)); - for(sdev = shpnt->host_queue; sdev; sdev = sdev->next) - { - SCSI_LOG_SCAN_BUS(4,printk("Device %d %p: ", sdev->id, sdev)); - for(scmd=sdev->device_queue; scmd; scmd = scmd->next) - { - SCSI_LOG_SCAN_BUS(4,printk("%p ", scmd)); - } - SCSI_LOG_SCAN_BUS(4,printk("\n")); - } - } + /* Last device block does not exist. Free memory. */ + if (SDpnt != NULL) + scsi_init_free((char *) SDpnt, sizeof(Scsi_Device)); + + if (SCpnt != NULL) + scsi_init_free((char *) SCpnt, sizeof(Scsi_Cmnd)); + + /* If we allocated a buffer so we could do DMA, free it now */ + if (scsi_result != &scsi_result0[0] && scsi_result != NULL) { + scsi_init_free(scsi_result, 512); + } { + Scsi_Device *sdev; + Scsi_Cmnd *scmd; + + SCSI_LOG_SCAN_BUS(4, printk("Host status for host %p:\n", shpnt)); + for (sdev = shpnt->host_queue; sdev; sdev = sdev->next) { + SCSI_LOG_SCAN_BUS(4, printk("Device %d %p: ", sdev->id, sdev)); + for (scmd = sdev->device_queue; scmd; scmd = scmd->next) { + SCSI_LOG_SCAN_BUS(4, printk("%p ", scmd)); + } + SCSI_LOG_SCAN_BUS(4, printk("\n")); + } + } } /* @@ -670,334 +674,321 @@ * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on. * Global variables used : scsi_devices(linked list) */ -int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, - int *sparse_lun, Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt, - struct Scsi_Host * shpnt, char *scsi_result) -{ - unsigned char scsi_cmd[12]; - struct Scsi_Device_Template *sdtpnt; - Scsi_Device * SDtail, *SDpnt=*SDpnt2; - int bflags, type=-1; - - SDpnt->host = shpnt; - SDpnt->id = dev; - SDpnt->lun = lun; - SDpnt->channel = channel; - SDpnt->online = TRUE; - - /* Some low level driver could use device->type (DB) */ - SDpnt->type = -1; - - /* - * Assume that the device will have handshaking problems, and then fix this - * field later if it turns out it doesn't - */ - SDpnt->borken = 1; - SDpnt->was_reset = 0; - SDpnt->expecting_cc_ua = 0; - - scsi_cmd[0] = TEST_UNIT_READY; - scsi_cmd[1] = lun << 5; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0; - - SCpnt->host = SDpnt->host; - SCpnt->device = SDpnt; - SCpnt->target = SDpnt->id; - SCpnt->lun = SDpnt->lun; - SCpnt->channel = SDpnt->channel; - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.sem = &sem; - SCpnt->request.rq_status = RQ_SCSI_BUSY; - spin_lock_irq(&io_request_lock); - scsi_do_cmd (SCpnt, (void *) scsi_cmd, - (void *) NULL, - 0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5); - spin_unlock_irq(&io_request_lock); - down (&sem); - SCpnt->request.sem = NULL; - } - - SCSI_LOG_SCAN_BUS(3, printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n", - dev, lun, SCpnt->result)); - SCSI_LOG_SCAN_BUS(3,print_driverbyte(SCpnt->result)); - SCSI_LOG_SCAN_BUS(3,print_hostbyte(SCpnt->result)); - SCSI_LOG_SCAN_BUS(3,printk("\n")); - - if (SCpnt->result) { - if (((driver_byte (SCpnt->result) & DRIVER_SENSE) || - (status_byte (SCpnt->result) & CHECK_CONDITION)) && - ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) { - if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) && - ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) && - ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0)) - return 1; - } - else - return 0; - } - - SCSI_LOG_SCAN_BUS(3,printk ("scsi: performing INQUIRY\n")); - /* - * Build an INQUIRY command block. - */ - scsi_cmd[0] = INQUIRY; - scsi_cmd[1] = (lun << 5) & 0xe0; - scsi_cmd[2] = 0; - scsi_cmd[3] = 0; - scsi_cmd[4] = 255; - scsi_cmd[5] = 0; - SCpnt->cmd_len = 0; - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.sem = &sem; - SCpnt->request.rq_status = RQ_SCSI_BUSY; - spin_lock_irq(&io_request_lock); - scsi_do_cmd (SCpnt, (void *) scsi_cmd, - (void *) scsi_result, - 256, scan_scsis_done, SCSI_TIMEOUT, 3); - spin_unlock_irq(&io_request_lock); - down (&sem); - SCpnt->request.sem = NULL; - } - - SCSI_LOG_SCAN_BUS(3,printk ("scsi: INQUIRY %s with code 0x%x\n", - SCpnt->result ? "failed" : "successful", SCpnt->result)); - - if (SCpnt->result) - return 0; /* assume no peripheral if any sort of error */ - - /* - * Check the peripheral qualifier field - this tells us whether LUNS - * are supported here or not. - */ - if( (scsi_result[0] >> 5) == 3 ) - { - return 0; /* assume no peripheral if any sort of error */ - } - - /* - * It would seem some TOSHIBA CDROM gets things wrong - */ - if (!strncmp (scsi_result + 8, "TOSHIBA", 7) && - !strncmp (scsi_result + 16, "CD-ROM", 6) && - scsi_result[0] == TYPE_DISK) { - scsi_result[0] = TYPE_ROM; - scsi_result[1] |= 0x80; /* removable */ - } - - memcpy (SDpnt->vendor, scsi_result + 8, 8); - memcpy (SDpnt->model, scsi_result + 16, 16); - memcpy (SDpnt->rev, scsi_result + 32, 4); - - SDpnt->removable = (0x80 & scsi_result[1]) >> 7; - SDpnt->online = TRUE; - SDpnt->lockable = SDpnt->removable; - SDpnt->changed = 0; - SDpnt->access_count = 0; - SDpnt->busy = 0; - SDpnt->has_cmdblocks = 0; - /* - * Currently, all sequential devices are assumed to be tapes, all random - * devices disk, with the appropriate read only flags set for ROM / WORM - * treated as RO. - */ - switch (type = (scsi_result[0] & 0x1f)) { - case TYPE_TAPE: - case TYPE_DISK: - case TYPE_MOD: - case TYPE_PROCESSOR: - case TYPE_SCANNER: - case TYPE_MEDIUM_CHANGER: - case TYPE_ENCLOSURE: - SDpnt->writeable = 1; - break; - case TYPE_WORM: - case TYPE_ROM: - SDpnt->writeable = 0; - break; - default: - printk ("scsi: unknown type %d\n", type); - } - - SDpnt->device_blocked = FALSE; - SDpnt->device_busy = 0; - SDpnt->single_lun = 0; - SDpnt->soft_reset = - (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2); - SDpnt->random = (type == TYPE_TAPE) ? 0 : 1; - SDpnt->type = (type & 0x1f); - - print_inquiry (scsi_result); - - for (sdtpnt = scsi_devicelist; sdtpnt; - sdtpnt = sdtpnt->next) - if (sdtpnt->detect) - SDpnt->attached += - (*sdtpnt->detect) (SDpnt); - - SDpnt->scsi_level = scsi_result[2] & 0x07; - if (SDpnt->scsi_level >= 2 || - (SDpnt->scsi_level == 1 && - (scsi_result[3] & 0x0f) == 1)) - SDpnt->scsi_level++; - - /* - * Accommodate drivers that want to sleep when they should be in a polling - * loop. - */ - SDpnt->disconnect = 0; - - /* - * Get any flags for this device. - */ - bflags = get_device_flags (scsi_result); - - /* - * Set the tagged_queue flag for SCSI-II devices that purport to support - * tagged queuing in the INQUIRY data. - */ - SDpnt->tagged_queue = 0; - if ((SDpnt->scsi_level >= SCSI_2) && - (scsi_result[7] & 2) && - !(bflags & BLIST_NOTQ)) { - SDpnt->tagged_supported = 1; - SDpnt->current_tag = 0; - } - - /* - * Some revisions of the Texel CD ROM drives have handshaking problems when - * used with the Seagate controllers. Before we know what type of device - * we're talking to, we assume it's borken and then change it here if it - * turns out that it isn't a TEXEL drive. - */ - if ((bflags & BLIST_BORKEN) == 0) - SDpnt->borken = 0; - - /* - * If we want to only allow I/O to one of the luns attached to this device - * at a time, then we set this flag. - */ - if (bflags & BLIST_SINGLELUN) - SDpnt->single_lun = 1; - - /* - * These devices need this "key" to unlock the devices so we can use it - */ - if ((bflags & BLIST_KEY) != 0) { - printk ("Unlocked floptical drive.\n"); - SDpnt->lockable = 0; - scsi_cmd[0] = MODE_SENSE; - scsi_cmd[1] = (lun << 5) & 0xe0; - scsi_cmd[2] = 0x2e; - scsi_cmd[3] = 0; - scsi_cmd[4] = 0x2a; - scsi_cmd[5] = 0; - SCpnt->cmd_len = 0; - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = &sem; - spin_lock_irq(&io_request_lock); - scsi_do_cmd (SCpnt, (void *) scsi_cmd, - (void *) scsi_result, 0x2a, - scan_scsis_done, SCSI_TIMEOUT, 3); - spin_unlock_irq(&io_request_lock); - down (&sem); - SCpnt->request.sem = NULL; - } - } - - /* - * Detach the command from the device. It was just a temporary to be used while - * scanning the bus - the real ones will be allocated later. - */ - SDpnt->device_queue = NULL; - - /* - * This device was already hooked up to the host in question, - * so at this point we just let go of it and it should be fine. We do need to - * allocate a new one and attach it to the host so that we can further scan the bus. - */ - SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC); - *SDpnt2=SDpnt; - if (!SDpnt) - { - printk ("scsi: scan_scsis_single: Cannot malloc\n"); - return 0; - } - - /* - * And hook up our command block to the new device we will be testing - * for. - */ - SDpnt->device_queue = SCpnt; - SDpnt->online = TRUE; - - init_waitqueue_head(&SDpnt->device_wait); - - /* - * Since we just found one device, there had damn well better be one in the list - * already. - */ - if( shpnt->host_queue == NULL ) - panic("scan_scsis_single: Host queue == NULL\n"); - - SDtail = shpnt->host_queue; - while (SDtail->next) - { - SDtail = SDtail->next; - } - - /* Add this device to the linked list at the end */ - SDtail->next = SDpnt; - SDpnt->prev = SDtail; - SDpnt->next = NULL; - - /* - * Some scsi devices cannot be polled for lun != 0 due to firmware bugs - */ - if (bflags & BLIST_NOLUN) - return 0; /* break; */ - - /* - * If this device is known to support sparse multiple units, override the - * other settings, and scan all of them. - */ - if (bflags & BLIST_SPARSELUN) { - *max_dev_lun = 8; - *sparse_lun = 1; - return 1; - } - - /* - * If this device is known to support multiple units, override the other - * settings, and scan all of them. - */ - if (bflags & BLIST_FORCELUN) { - *max_dev_lun = 8; - return 1; - } - - /* - * REGAL CDC-4X: avoid hang after LUN 4 - */ - if (bflags & BLIST_MAX5LUN) { - *max_dev_lun = 5; - return 1; - } - - /* - * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI - * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1 - * (ANSI SCSI Revision 1) and Response Data Format 0 - */ - if (((scsi_result[2] & 0x07) == 0) - || - ((scsi_result[2] & 0x07) == 1 && - (scsi_result[3] & 0x0f) == 0)) - return 0; - return 1; +int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun, + int *sparse_lun, Scsi_Device ** SDpnt2, Scsi_Cmnd * SCpnt, + struct Scsi_Host *shpnt, char *scsi_result) +{ + unsigned char scsi_cmd[12]; + struct Scsi_Device_Template *sdtpnt; + Scsi_Device *SDtail, *SDpnt = *SDpnt2; + int bflags, type = -1; + + SDpnt->host = shpnt; + SDpnt->id = dev; + SDpnt->lun = lun; + SDpnt->channel = channel; + SDpnt->online = TRUE; + + /* Some low level driver could use device->type (DB) */ + SDpnt->type = -1; + + /* + * Assume that the device will have handshaking problems, and then fix this + * field later if it turns out it doesn't + */ + SDpnt->borken = 1; + SDpnt->was_reset = 0; + SDpnt->expecting_cc_ua = 0; + + scsi_cmd[0] = TEST_UNIT_READY; + scsi_cmd[1] = lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0; + + SCpnt->host = SDpnt->host; + SCpnt->device = SDpnt; + SCpnt->target = SDpnt->id; + SCpnt->lun = SDpnt->lun; + SCpnt->channel = SDpnt->channel; + { + DECLARE_MUTEX_LOCKED(sem); + SCpnt->request.sem = &sem; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + spin_lock_irq(&io_request_lock); + scsi_do_cmd(SCpnt, (void *) scsi_cmd, + (void *) NULL, + 0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5); + spin_unlock_irq(&io_request_lock); + down(&sem); + SCpnt->request.sem = NULL; + } + + SCSI_LOG_SCAN_BUS(3, printk("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n", + dev, lun, SCpnt->result)); + SCSI_LOG_SCAN_BUS(3, print_driverbyte(SCpnt->result)); + SCSI_LOG_SCAN_BUS(3, print_hostbyte(SCpnt->result)); + SCSI_LOG_SCAN_BUS(3, printk("\n")); + + if (SCpnt->result) { + if (((driver_byte(SCpnt->result) & DRIVER_SENSE) || + (status_byte(SCpnt->result) & CHECK_CONDITION)) && + ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) { + if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) && + ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) && + ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0)) + return 1; + } else + return 0; + } + SCSI_LOG_SCAN_BUS(3, printk("scsi: performing INQUIRY\n")); + /* + * Build an INQUIRY command block. + */ + scsi_cmd[0] = INQUIRY; + scsi_cmd[1] = (lun << 5) & 0xe0; + scsi_cmd[2] = 0; + scsi_cmd[3] = 0; + scsi_cmd[4] = 255; + scsi_cmd[5] = 0; + SCpnt->cmd_len = 0; + { + DECLARE_MUTEX_LOCKED(sem); + SCpnt->request.sem = &sem; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + spin_lock_irq(&io_request_lock); + scsi_do_cmd(SCpnt, (void *) scsi_cmd, + (void *) scsi_result, + 256, scan_scsis_done, SCSI_TIMEOUT, 3); + spin_unlock_irq(&io_request_lock); + down(&sem); + SCpnt->request.sem = NULL; + } + + SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n", + SCpnt->result ? "failed" : "successful", SCpnt->result)); + + if (SCpnt->result) + return 0; /* assume no peripheral if any sort of error */ + + /* + * Check the peripheral qualifier field - this tells us whether LUNS + * are supported here or not. + */ + if ((scsi_result[0] >> 5) == 3) { + return 0; /* assume no peripheral if any sort of error */ + } + /* + * It would seem some TOSHIBA CDROM gets things wrong + */ + if (!strncmp(scsi_result + 8, "TOSHIBA", 7) && + !strncmp(scsi_result + 16, "CD-ROM", 6) && + scsi_result[0] == TYPE_DISK) { + scsi_result[0] = TYPE_ROM; + scsi_result[1] |= 0x80; /* removable */ + } + memcpy(SDpnt->vendor, scsi_result + 8, 8); + memcpy(SDpnt->model, scsi_result + 16, 16); + memcpy(SDpnt->rev, scsi_result + 32, 4); + + SDpnt->removable = (0x80 & scsi_result[1]) >> 7; + SDpnt->online = TRUE; + SDpnt->lockable = SDpnt->removable; + SDpnt->changed = 0; + SDpnt->access_count = 0; + SDpnt->busy = 0; + SDpnt->has_cmdblocks = 0; + /* + * Currently, all sequential devices are assumed to be tapes, all random + * devices disk, with the appropriate read only flags set for ROM / WORM + * treated as RO. + */ + switch (type = (scsi_result[0] & 0x1f)) { + case TYPE_TAPE: + case TYPE_DISK: + case TYPE_MOD: + case TYPE_PROCESSOR: + case TYPE_SCANNER: + case TYPE_MEDIUM_CHANGER: + case TYPE_ENCLOSURE: + SDpnt->writeable = 1; + break; + case TYPE_WORM: + case TYPE_ROM: + SDpnt->writeable = 0; + break; + default: + printk("scsi: unknown type %d\n", type); + } + + SDpnt->device_blocked = FALSE; + SDpnt->device_busy = 0; + SDpnt->single_lun = 0; + SDpnt->soft_reset = + (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2); + SDpnt->random = (type == TYPE_TAPE) ? 0 : 1; + SDpnt->type = (type & 0x1f); + + print_inquiry(scsi_result); + + for (sdtpnt = scsi_devicelist; sdtpnt; + sdtpnt = sdtpnt->next) + if (sdtpnt->detect) + SDpnt->attached += + (*sdtpnt->detect) (SDpnt); + + SDpnt->scsi_level = scsi_result[2] & 0x07; + if (SDpnt->scsi_level >= 2 || + (SDpnt->scsi_level == 1 && + (scsi_result[3] & 0x0f) == 1)) + SDpnt->scsi_level++; + + /* + * Accommodate drivers that want to sleep when they should be in a polling + * loop. + */ + SDpnt->disconnect = 0; + + /* + * Get any flags for this device. + */ + bflags = get_device_flags(scsi_result); + + /* + * Set the tagged_queue flag for SCSI-II devices that purport to support + * tagged queuing in the INQUIRY data. + */ + SDpnt->tagged_queue = 0; + if ((SDpnt->scsi_level >= SCSI_2) && + (scsi_result[7] & 2) && + !(bflags & BLIST_NOTQ)) { + SDpnt->tagged_supported = 1; + SDpnt->current_tag = 0; + } + /* + * Some revisions of the Texel CD ROM drives have handshaking problems when + * used with the Seagate controllers. Before we know what type of device + * we're talking to, we assume it's borken and then change it here if it + * turns out that it isn't a TEXEL drive. + */ + if ((bflags & BLIST_BORKEN) == 0) + SDpnt->borken = 0; + + /* + * If we want to only allow I/O to one of the luns attached to this device + * at a time, then we set this flag. + */ + if (bflags & BLIST_SINGLELUN) + SDpnt->single_lun = 1; + + /* + * These devices need this "key" to unlock the devices so we can use it + */ + if ((bflags & BLIST_KEY) != 0) { + printk("Unlocked floptical drive.\n"); + SDpnt->lockable = 0; + scsi_cmd[0] = MODE_SENSE; + scsi_cmd[1] = (lun << 5) & 0xe0; + scsi_cmd[2] = 0x2e; + scsi_cmd[3] = 0; + scsi_cmd[4] = 0x2a; + scsi_cmd[5] = 0; + SCpnt->cmd_len = 0; + { + DECLARE_MUTEX_LOCKED(sem); + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.sem = &sem; + spin_lock_irq(&io_request_lock); + scsi_do_cmd(SCpnt, (void *) scsi_cmd, + (void *) scsi_result, 0x2a, + scan_scsis_done, SCSI_TIMEOUT, 3); + spin_unlock_irq(&io_request_lock); + down(&sem); + SCpnt->request.sem = NULL; + } + } + /* + * Detach the command from the device. It was just a temporary to be used while + * scanning the bus - the real ones will be allocated later. + */ + SDpnt->device_queue = NULL; + + /* + * This device was already hooked up to the host in question, + * so at this point we just let go of it and it should be fine. We do need to + * allocate a new one and attach it to the host so that we can further scan the bus. + */ + SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof(Scsi_Device), GFP_ATOMIC); + *SDpnt2 = SDpnt; + if (!SDpnt) { + printk("scsi: scan_scsis_single: Cannot malloc\n"); + return 0; + } + /* + * And hook up our command block to the new device we will be testing + * for. + */ + SDpnt->device_queue = SCpnt; + SDpnt->online = TRUE; + + init_waitqueue_head(&SDpnt->device_wait); + + /* + * Since we just found one device, there had damn well better be one in the list + * already. + */ + if (shpnt->host_queue == NULL) + panic("scan_scsis_single: Host queue == NULL\n"); + + SDtail = shpnt->host_queue; + while (SDtail->next) { + SDtail = SDtail->next; + } + + /* Add this device to the linked list at the end */ + SDtail->next = SDpnt; + SDpnt->prev = SDtail; + SDpnt->next = NULL; + + /* + * Some scsi devices cannot be polled for lun != 0 due to firmware bugs + */ + if (bflags & BLIST_NOLUN) + return 0; /* break; */ + + /* + * If this device is known to support sparse multiple units, override the + * other settings, and scan all of them. + */ + if (bflags & BLIST_SPARSELUN) { + *max_dev_lun = 8; + *sparse_lun = 1; + return 1; + } + /* + * If this device is known to support multiple units, override the other + * settings, and scan all of them. + */ + if (bflags & BLIST_FORCELUN) { + *max_dev_lun = 8; + return 1; + } + /* + * REGAL CDC-4X: avoid hang after LUN 4 + */ + if (bflags & BLIST_MAX5LUN) { + *max_dev_lun = 5; + return 1; + } + /* + * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI + * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1 + * (ANSI SCSI Revision 1) and Response Data Format 0 + */ + if (((scsi_result[2] & 0x07) == 0) + || + ((scsi_result[2] & 0x07) == 1 && + (scsi_result[3] & 0x0f) == 0)) + return 0; + return 1; } /* @@ -1017,118 +1008,125 @@ * of the calling code to ensure that this is the case. */ -Scsi_Cmnd * scsi_request_queueable (struct request * req, Scsi_Device * device) +Scsi_Cmnd *scsi_request_queueable(struct request * req, Scsi_Device * device) { - Scsi_Cmnd * SCpnt = NULL; - int tablesize; - Scsi_Cmnd * found = NULL; - struct buffer_head * bh, *bhp; - - if (!device) - panic ("No device passed to scsi_request_queueable().\n"); - - if (req && req->rq_status == RQ_INACTIVE) - panic("Inactive in scsi_request_queueable"); - - /* - * Look for a free command block. If we have been instructed not to queue - * multiple commands to multi-lun devices, then check to see what else is - * going for this device first. - */ - - if (!device->single_lun) { - SCpnt = device->device_queue; - while(SCpnt){ - if(SCpnt->request.rq_status == RQ_INACTIVE) break; - SCpnt = SCpnt->next; - } - } else { - SCpnt = device->device_queue; - while(SCpnt){ - if(SCpnt->channel == device->channel - && SCpnt->target == device->id) { - if (SCpnt->lun == device->lun) { - if(found == NULL - && SCpnt->request.rq_status == RQ_INACTIVE) - { - found=SCpnt; - } - } - if(SCpnt->request.rq_status != RQ_INACTIVE) { - /* - * I think that we should really limit things to one - * outstanding command per device - this is what tends - * to trip up buggy firmware. - */ - return NULL; - } - } - SCpnt = SCpnt->next; - } - SCpnt = found; - } - - if (!SCpnt) return NULL; - - if (SCSI_BLOCK(device, device->host)) return NULL; - - if (req) { - memcpy(&SCpnt->request, req, sizeof(struct request)); - tablesize = device->host->sg_tablesize; - bhp = bh = req->bh; - if(!tablesize) bh = NULL; - /* Take a quick look through the table to see how big it is. - * We already have our copy of req, so we can mess with that - * if we want to. - */ - while(req->nr_sectors && bh){ - bhp = bhp->b_reqnext; - if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--; - req->nr_sectors -= bh->b_size >> 9; - req->sector += bh->b_size >> 9; - if(!tablesize) break; - bh = bhp; - } - if(req->nr_sectors && bh && bh->b_reqnext){ /* Any leftovers? */ - SCpnt->request.bhtail = bh; - req->bh = bh->b_reqnext; /* Divide request */ - bh->b_reqnext = NULL; - bh = req->bh; - - /* Now reset things so that req looks OK */ - SCpnt->request.nr_sectors -= req->nr_sectors; - req->current_nr_sectors = bh->b_size >> 9; - req->buffer = bh->b_data; - SCpnt->request.sem = NULL; /* Wait until whole thing done */ + Scsi_Cmnd *SCpnt = NULL; + int tablesize; + Scsi_Cmnd *found = NULL; + struct buffer_head *bh, *bhp; + + if (!device) + panic("No device passed to scsi_request_queueable().\n"); + + if (req && req->rq_status == RQ_INACTIVE) + panic("Inactive in scsi_request_queueable"); + + /* + * Look for a free command block. If we have been instructed not to queue + * multiple commands to multi-lun devices, then check to see what else is + * going for this device first. + */ + + if (!device->single_lun) { + SCpnt = device->device_queue; + while (SCpnt) { + if (SCpnt->request.rq_status == RQ_INACTIVE) + break; + SCpnt = SCpnt->next; + } + } else { + SCpnt = device->device_queue; + while (SCpnt) { + if (SCpnt->channel == device->channel + && SCpnt->target == device->id) { + if (SCpnt->lun == device->lun) { + if (found == NULL + && SCpnt->request.rq_status == RQ_INACTIVE) { + found = SCpnt; + } + } + if (SCpnt->request.rq_status != RQ_INACTIVE) { + /* + * I think that we should really limit things to one + * outstanding command per device - this is what tends + * to trip up buggy firmware. + */ + return NULL; + } + } + SCpnt = SCpnt->next; + } + SCpnt = found; + } + + if (!SCpnt) + return NULL; + + if (SCSI_BLOCK(device, device->host)) + return NULL; + + if (req) { + memcpy(&SCpnt->request, req, sizeof(struct request)); + tablesize = device->host->sg_tablesize; + bhp = bh = req->bh; + if (!tablesize) + bh = NULL; + /* Take a quick look through the table to see how big it is. + * We already have our copy of req, so we can mess with that + * if we want to. + */ + while (req->nr_sectors && bh) { + bhp = bhp->b_reqnext; + if (!bhp || !CONTIGUOUS_BUFFERS(bh, bhp)) + tablesize--; + req->nr_sectors -= bh->b_size >> 9; + req->sector += bh->b_size >> 9; + if (!tablesize) + break; + bh = bhp; + } + if (req->nr_sectors && bh && bh->b_reqnext) { /* Any leftovers? */ + SCpnt->request.bhtail = bh; + req->bh = bh->b_reqnext; /* Divide request */ + bh->b_reqnext = NULL; + bh = req->bh; + + /* Now reset things so that req looks OK */ + SCpnt->request.nr_sectors -= req->nr_sectors; + req->current_nr_sectors = bh->b_size >> 9; + req->buffer = bh->b_data; + SCpnt->request.sem = NULL; /* Wait until whole thing done */ + } else { + req->rq_status = RQ_INACTIVE; + wake_up(&wait_for_request); + } } else { - req->rq_status = RQ_INACTIVE; - wake_up(&wait_for_request); + SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Busy, but no request */ + SCpnt->request.sem = NULL; /* And no one is waiting for the device + * either */ } - } else { - SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Busy, but no request */ - SCpnt->request.sem = NULL; /* And no one is waiting for the device - * either */ - } - - atomic_inc(&SCpnt->host->host_active); - SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCpnt->target, - atomic_read(&SCpnt->host->host_active))); - SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ - SCpnt->old_use_sg = 0; - SCpnt->transfersize = 0; - SCpnt->underflow = 0; - SCpnt->cmd_len = 0; - -/* Since not everyone seems to set the device info correctly - * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. - */ - SCpnt->channel = device->channel; - SCpnt->lun = device->lun; - SCpnt->target = device->id; - SCpnt->state = SCSI_STATE_INITIALIZING; - SCpnt->owner = SCSI_OWNER_HIGHLEVEL; - return SCpnt; + atomic_inc(&SCpnt->host->host_active); + SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCpnt->target, + atomic_read(&SCpnt->host->host_active))); + SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ + SCpnt->old_use_sg = 0; + SCpnt->transfersize = 0; + SCpnt->underflow = 0; + SCpnt->cmd_len = 0; + + /* + * Since not everyone seems to set the device info correctly + * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. + */ + + SCpnt->channel = device->channel; + SCpnt->lun = device->lun; + SCpnt->target = device->id; + SCpnt->state = SCSI_STATE_INITIALIZING; + SCpnt->owner = SCSI_OWNER_HIGHLEVEL; + + return SCpnt; } /* This function returns a structure pointer that will be valid for @@ -1141,156 +1139,164 @@ * of the packets for each device */ -Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device, - int wait) +Scsi_Cmnd *scsi_allocate_device(struct request ** reqp, Scsi_Device * device, + int wait) { - kdev_t dev; - struct request * req = NULL; - int tablesize; - struct buffer_head * bh, *bhp; - struct Scsi_Host * host; - Scsi_Cmnd * SCpnt = NULL; - Scsi_Cmnd * SCwait = NULL; - Scsi_Cmnd * found = NULL; - - if (!device) - panic ("No device passed to scsi_allocate_device().\n"); - - if (reqp) req = *reqp; - - /* See if this request has already been queued by an interrupt routine */ - if (req) { - if(req->rq_status == RQ_INACTIVE) return NULL; - dev = req->rq_dev; - } else - dev = 0; /* unused */ + kdev_t dev; + struct request *req = NULL; + int tablesize; + struct buffer_head *bh, *bhp; + struct Scsi_Host *host; + Scsi_Cmnd *SCpnt = NULL; + Scsi_Cmnd *SCwait = NULL; + Scsi_Cmnd *found = NULL; - host = device->host; + if (!device) + panic("No device passed to scsi_allocate_device().\n"); - if (in_interrupt() && SCSI_BLOCK(device, host)) return NULL; + if (reqp) + req = *reqp; - while (1==1){ - if (!device->single_lun) { - SCpnt = device->device_queue; - while(SCpnt){ - SCwait = SCpnt; - if(SCpnt->request.rq_status == RQ_INACTIVE) break; - SCpnt = SCpnt->next; - } - } else { - SCpnt = device->device_queue; - while(SCpnt){ - if(SCpnt->channel == device->channel - && SCpnt->target == device->id) { - if (SCpnt->lun == device->lun) { - SCwait = SCpnt; - if(found == NULL - && SCpnt->request.rq_status == RQ_INACTIVE) - { - found=SCpnt; + /* + * See if this request has already been queued by an + * interrupt routine + */ + + if (req) { + if (req->rq_status == RQ_INACTIVE) + return NULL; + dev = req->rq_dev; + } else + dev = 0; /* unused */ + + host = device->host; + + if (in_interrupt() && SCSI_BLOCK(device, host)) + return NULL; + + while (1 == 1) { + if (!device->single_lun) { + SCpnt = device->device_queue; + while (SCpnt) { + SCwait = SCpnt; + if (SCpnt->request.rq_status == RQ_INACTIVE) + break; + SCpnt = SCpnt->next; } - } - if(SCpnt->request.rq_status != RQ_INACTIVE) { - /* - * I think that we should really limit things to one - * outstanding command per device - this is what tends - * to trip up buggy firmware. - */ - found = NULL; - break; - } + } else { + SCpnt = device->device_queue; + while (SCpnt) { + if (SCpnt->channel == device->channel + && SCpnt->target == device->id) { + if (SCpnt->lun == device->lun) { + SCwait = SCpnt; + if (found == NULL + && SCpnt->request.rq_status == RQ_INACTIVE) { + found = SCpnt; + } + } + if (SCpnt->request.rq_status != RQ_INACTIVE) { + /* + * I think that we should really limit things to one + * outstanding command per device - this is what tends + * to trip up buggy firmware. + */ + found = NULL; + break; + } + } + SCpnt = SCpnt->next; + } + SCpnt = found; } - SCpnt = SCpnt->next; - } - SCpnt = found; - } - /* See if this request has already been queued by an interrupt routine - */ - if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) { - return NULL; - } - if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE) /* Might have changed */ - { - if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){ - spin_unlock(&io_request_lock); /* FIXME!!!! */ - sleep_on(&device->device_wait); - spin_lock_irq(&io_request_lock); /* FIXME!!!! */ - } else { - if (!wait) return NULL; - if (!SCwait) { - printk("Attempt to allocate device channel %d," - " target %d, lun %d\n", device->channel, - device->id, device->lun); - panic("No device found in scsi_allocate_device\n"); - } - } - } else { - if (req) { - memcpy(&SCpnt->request, req, sizeof(struct request)); - tablesize = device->host->sg_tablesize; - bhp = bh = req->bh; - if(!tablesize) bh = NULL; - /* Take a quick look through the table to see how big it is. - * We already have our copy of req, so we can mess with that - * if we want to. + /* See if this request has already been queued by an interrupt routine */ - while(req->nr_sectors && bh){ - bhp = bhp->b_reqnext; - if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--; - req->nr_sectors -= bh->b_size >> 9; - req->sector += bh->b_size >> 9; - if(!tablesize) break; - bh = bhp; - } - if(req->nr_sectors && bh && bh->b_reqnext){/* Any leftovers? */ - SCpnt->request.bhtail = bh; - req->bh = bh->b_reqnext; /* Divide request */ - bh->b_reqnext = NULL; - bh = req->bh; - /* Now reset things so that req looks OK */ - SCpnt->request.nr_sectors -= req->nr_sectors; - req->current_nr_sectors = bh->b_size >> 9; - req->buffer = bh->b_data; - SCpnt->request.sem = NULL; /* Wait until whole thing done*/ + if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) { + return NULL; } - else - { - req->rq_status = RQ_INACTIVE; - *reqp = req->next; - wake_up(&wait_for_request); + if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE) { /* Might have changed */ + if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE) { + spin_unlock(&io_request_lock); /* FIXME!!!! */ + sleep_on(&device->device_wait); + spin_lock_irq(&io_request_lock); /* FIXME!!!! */ + } else { + if (!wait) + return NULL; + if (!SCwait) { + printk("Attempt to allocate device channel %d," + " target %d, lun %d\n", device->channel, + device->id, device->lun); + panic("No device found in scsi_allocate_device\n"); + } + } + } else { + if (req) { + memcpy(&SCpnt->request, req, sizeof(struct request)); + tablesize = device->host->sg_tablesize; + bhp = bh = req->bh; + if (!tablesize) + bh = NULL; + /* Take a quick look through the table to see how big it is. + * We already have our copy of req, so we can mess with that + * if we want to. + */ + while (req->nr_sectors && bh) { + bhp = bhp->b_reqnext; + if (!bhp || !CONTIGUOUS_BUFFERS(bh, bhp)) + tablesize--; + req->nr_sectors -= bh->b_size >> 9; + req->sector += bh->b_size >> 9; + if (!tablesize) + break; + bh = bhp; + } + if (req->nr_sectors && bh && bh->b_reqnext) { /* Any leftovers? */ + SCpnt->request.bhtail = bh; + req->bh = bh->b_reqnext; /* Divide request */ + bh->b_reqnext = NULL; + bh = req->bh; + /* Now reset things so that req looks OK */ + SCpnt->request.nr_sectors -= req->nr_sectors; + req->current_nr_sectors = bh->b_size >> 9; + req->buffer = bh->b_data; + SCpnt->request.sem = NULL; /* Wait until whole thing done */ + } else { + req->rq_status = RQ_INACTIVE; + *reqp = req->next; + wake_up(&wait_for_request); + } + } else { + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.sem = NULL; /* And no one is waiting for this + * to complete */ + } + atomic_inc(&SCpnt->host->host_active); + SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", + SCpnt->target, + atomic_read(&SCpnt->host->host_active))); + break; } - } else { - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = NULL; /* And no one is waiting for this - * to complete */ - } - atomic_inc(&SCpnt->host->host_active); - SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", - SCpnt->target, - atomic_read(&SCpnt->host->host_active))); - break; - } - } - - SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ - SCpnt->old_use_sg = 0; - SCpnt->transfersize = 0; /* No default transfer size */ - SCpnt->cmd_len = 0; - - SCpnt->underflow = 0; /* Do not flag underflow conditions */ - - /* Since not everyone seems to set the device info correctly - * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. - * FIXME(eric) This doesn't make any sense. - */ - SCpnt->channel = device->channel; - SCpnt->lun = device->lun; - SCpnt->target = device->id; - SCpnt->state = SCSI_STATE_INITIALIZING; - SCpnt->owner = SCSI_OWNER_HIGHLEVEL; + } + + SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ + SCpnt->old_use_sg = 0; + SCpnt->transfersize = 0; /* No default transfer size */ + SCpnt->cmd_len = 0; + + SCpnt->underflow = 0; /* Do not flag underflow conditions */ + + /* Since not everyone seems to set the device info correctly + * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. + * FIXME(eric) This doesn't make any sense. + */ + SCpnt->channel = device->channel; + SCpnt->lun = device->lun; + SCpnt->target = device->id; + SCpnt->state = SCSI_STATE_INITIALIZING; + SCpnt->owner = SCSI_OWNER_HIGHLEVEL; - return SCpnt; + return SCpnt; } /* @@ -1304,159 +1310,144 @@ * this funciton is called. This is in effect the inverse * of scsi_allocate_device/scsi_request_queueable. */ -void -scsi_release_command(Scsi_Cmnd * SCpnt) +void scsi_release_command(Scsi_Cmnd * SCpnt) { - SCpnt->request.rq_status = RQ_INACTIVE; - SCpnt->state = SCSI_STATE_UNUSED; - SCpnt->owner = SCSI_OWNER_NOBODY; - atomic_dec(&SCpnt->host->host_active); - - SCSI_LOG_MLQUEUE(5, printk("Deactivating command for device %d (active=%d, failed=%d)\n", - SCpnt->target, - atomic_read(&SCpnt->host->host_active), - SCpnt->host->host_failed)); - if( SCpnt->host->host_failed != 0 ) - { - SCSI_LOG_ERROR_RECOVERY(5, printk("Error handler thread %d %d\n", - SCpnt->host->in_recovery, - SCpnt->host->eh_active)); - } - - /* - * If the host is having troubles, then look to see if this was the last - * command that might have failed. If so, wake up the error handler. - */ - if( SCpnt->host->in_recovery - && !SCpnt->host->eh_active - && SCpnt->host->host_busy == SCpnt->host->host_failed ) - { - SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n", - atomic_read(&SCpnt->host->eh_wait->count))); - up(SCpnt->host->eh_wait); - } + SCpnt->request.rq_status = RQ_INACTIVE; + SCpnt->state = SCSI_STATE_UNUSED; + SCpnt->owner = SCSI_OWNER_NOBODY; + atomic_dec(&SCpnt->host->host_active); + + SCSI_LOG_MLQUEUE(5, printk("Deactivating command for device %d (active=%d, failed=%d)\n", + SCpnt->target, + atomic_read(&SCpnt->host->host_active), + SCpnt->host->host_failed)); + if (SCpnt->host->host_failed != 0) { + SCSI_LOG_ERROR_RECOVERY(5, printk("Error handler thread %d %d\n", + SCpnt->host->in_recovery, + SCpnt->host->eh_active)); + } + /* + * If the host is having troubles, then look to see if this was the last + * command that might have failed. If so, wake up the error handler. + */ + if (SCpnt->host->in_recovery + && !SCpnt->host->eh_active + && SCpnt->host->host_busy == SCpnt->host->host_failed) { + SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n", + atomic_read(&SCpnt->host->eh_wait->count))); + up(SCpnt->host->eh_wait); + } } /* * This is inline because we have stack problemes if we recurse to deeply. */ -inline int internal_cmnd (Scsi_Cmnd * SCpnt) +inline int internal_cmnd(Scsi_Cmnd * SCpnt) { #ifdef DEBUG_DELAY - unsigned long clock; + unsigned long clock; #endif - struct Scsi_Host * host; - int rtn = 0; - unsigned long timeout; + struct Scsi_Host *host; + int rtn = 0; + unsigned long timeout; #if DEBUG - unsigned long *ret = 0; + unsigned long *ret = 0; #ifdef __mips__ - __asm__ __volatile__ ("move\t%0,$31":"=r"(ret)); + __asm__ __volatile__("move\t%0,$31":"=r"(ret)); #else - ret = __builtin_return_address(0); + ret = __builtin_return_address(0); #endif #endif - host = SCpnt->host; + host = SCpnt->host; + + /* Assign a unique nonzero serial_number. */ + if (++serial_number == 0) + serial_number = 1; + SCpnt->serial_number = serial_number; + + /* + * We will wait MIN_RESET_DELAY clock ticks after the last reset so + * we can avoid the drive not being ready. + */ + timeout = host->last_reset + MIN_RESET_DELAY; + + if (host->resetting && time_before(jiffies, timeout)) { + int ticks_remaining = timeout - jiffies; + /* + * NOTE: This may be executed from within an interrupt + * handler! This is bad, but for now, it'll do. The irq + * level of the interrupt handler has been masked out by the + * platform dependent interrupt handling code already, so the + * sti() here will not cause another call to the SCSI host's + * interrupt handler (assuming there is one irq-level per + * host). + */ + spin_unlock_irq(&io_request_lock); + while (--ticks_remaining >= 0) + mdelay(1 + 999 / HZ); + host->resetting = 0; + spin_lock_irq(&io_request_lock); + } + if (host->hostt->use_new_eh_code) { + scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out); + } else { + scsi_add_timer(SCpnt, SCpnt->timeout_per_command, + scsi_old_times_out); + } + + /* + * We will use a queued command if possible, otherwise we will emulate the + * queuing and calling of completion function ourselves. + */ + SCSI_LOG_MLQUEUE(3, printk("internal_cmnd (host = %d, channel = %d, target = %d, " + "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n", + SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd, + SCpnt->buffer, SCpnt->bufflen, SCpnt->done)); + + SCpnt->state = SCSI_STATE_QUEUED; + SCpnt->owner = SCSI_OWNER_LOWLEVEL; + if (host->can_queue) { + SCSI_LOG_MLQUEUE(3, printk("queuecommand : routine at %p\n", + host->hostt->queuecommand)); + /* + * Use the old error handling code if we haven't converted the driver + * to use the new one yet. Note - only the new queuecommand variant + * passes a meaningful return value. + */ + if (host->hostt->use_new_eh_code) { + rtn = host->hostt->queuecommand(SCpnt, scsi_done); + if (rtn != 0) { + scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); + } + } else { + host->hostt->queuecommand(SCpnt, scsi_old_done); + } + } else { + int temp; - /* Assign a unique nonzero serial_number. */ - if (++serial_number == 0) serial_number = 1; - SCpnt->serial_number = serial_number; - - /* - * We will wait MIN_RESET_DELAY clock ticks after the last reset so - * we can avoid the drive not being ready. - */ - timeout = host->last_reset + MIN_RESET_DELAY; - - if (host->resetting && time_before(jiffies, timeout)) { - int ticks_remaining = timeout - jiffies; - /* - * NOTE: This may be executed from within an interrupt - * handler! This is bad, but for now, it'll do. The irq - * level of the interrupt handler has been masked out by the - * platform dependent interrupt handling code already, so the - * sti() here will not cause another call to the SCSI host's - * interrupt handler (assuming there is one irq-level per - * host). - */ - spin_unlock_irq(&io_request_lock); - while (--ticks_remaining >= 0) mdelay(1+999/HZ); - host->resetting = 0; - spin_lock_irq(&io_request_lock); - } - - if( host->hostt->use_new_eh_code ) - { - scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out); - } - else - { - scsi_add_timer(SCpnt, SCpnt->timeout_per_command, - scsi_old_times_out); - } - - /* - * We will use a queued command if possible, otherwise we will emulate the - * queuing and calling of completion function ourselves. - */ - SCSI_LOG_MLQUEUE(3,printk("internal_cmnd (host = %d, channel = %d, target = %d, " - "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n", - SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd, - SCpnt->buffer, SCpnt->bufflen, SCpnt->done)); - - SCpnt->state = SCSI_STATE_QUEUED; - SCpnt->owner = SCSI_OWNER_LOWLEVEL; - if (host->can_queue) - { - SCSI_LOG_MLQUEUE(3,printk("queuecommand : routine at %p\n", - host->hostt->queuecommand)); - /* - * Use the old error handling code if we haven't converted the driver - * to use the new one yet. Note - only the new queuecommand variant - * passes a meaningful return value. - */ - if( host->hostt->use_new_eh_code ) - { - rtn = host->hostt->queuecommand (SCpnt, scsi_done); - if( rtn != 0 ) - { - scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); - } - } - else - { - host->hostt->queuecommand (SCpnt, scsi_old_done); - } - } - else - { - int temp; - - SCSI_LOG_MLQUEUE(3,printk("command() : routine at %p\n", host->hostt->command)); - temp = host->hostt->command (SCpnt); - SCpnt->result = temp; + SCSI_LOG_MLQUEUE(3, printk("command() : routine at %p\n", host->hostt->command)); + temp = host->hostt->command(SCpnt); + SCpnt->result = temp; #ifdef DEBUG_DELAY - clock = jiffies + 4 * HZ; - spin_unlock_irq(&io_request_lock); - while (time_before(jiffies, clock)) barrier(); - spin_lock_irq(&io_request_lock); - printk("done(host = %d, result = %04x) : routine at %p\n", - host->host_no, temp, host->hostt->command); -#endif - if( host->hostt->use_new_eh_code ) - { - scsi_done(SCpnt); - } - else - { - scsi_old_done(SCpnt); - } - } - SCSI_LOG_MLQUEUE(3,printk("leaving internal_cmnd()\n")); - return rtn; + clock = jiffies + 4 * HZ; + spin_unlock_irq(&io_request_lock); + while (time_before(jiffies, clock)) + barrier(); + spin_lock_irq(&io_request_lock); + printk("done(host = %d, result = %04x) : routine at %p\n", + host->host_no, temp, host->hostt->command); +#endif + if (host->hostt->use_new_eh_code) { + scsi_done(SCpnt); + } else { + scsi_old_done(SCpnt); + } + } + SCSI_LOG_MLQUEUE(3, printk("leaving internal_cmnd()\n")); + return rtn; } /* @@ -1466,95 +1457,93 @@ * drivers go for the same host at the same time. */ -void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , - void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *), - int timeout, int retries) -{ - struct Scsi_Host * host = SCpnt->host; - Scsi_Device * device = SCpnt->device; +void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd, + void *buffer, unsigned bufflen, void (*done) (Scsi_Cmnd *), + int timeout, int retries) +{ + struct Scsi_Host *host = SCpnt->host; + Scsi_Device *device = SCpnt->device; + + SCpnt->owner = SCSI_OWNER_MIDLEVEL; + + SCSI_LOG_MLQUEUE(4, + { + int i; + int target = SCpnt->target; + printk("scsi_do_cmd (host = %d, channel = %d target = %d, " + "buffer =%p, bufflen = %d, done = %p, timeout = %d, " + "retries = %d)\n" + "command : ", host->host_no, SCpnt->channel, target, buffer, + bufflen, done, timeout, retries); + for (i = 0; i < 10; ++i) + printk("%02x ", ((unsigned char *) cmnd)[i]); + printk("\n"); + }); + + if (!host) { + panic("Invalid or not present host.\n"); + } + /* + * We must prevent reentrancy to the lowlevel host driver. This prevents + * it - we enter a loop until the host we want to talk to is not busy. + * Race conditions are prevented, as interrupts are disabled in between the + * time we check for the host being not busy, and the time we mark it busy + * ourselves. + */ - SCpnt->owner = SCSI_OWNER_MIDLEVEL; + SCpnt->pid = scsi_pid++; -SCSI_LOG_MLQUEUE(4, - { - int i; - int target = SCpnt->target; - printk ("scsi_do_cmd (host = %d, channel = %d target = %d, " - "buffer =%p, bufflen = %d, done = %p, timeout = %d, " - "retries = %d)\n" - "command : " , host->host_no, SCpnt->channel, target, buffer, - bufflen, done, timeout, retries); - for (i = 0; i < 10; ++i) - printk ("%02x ", ((unsigned char *) cmnd)[i]); - printk("\n"); - }); + while (SCSI_BLOCK((Scsi_Device *) NULL, host)) { + spin_unlock(&io_request_lock); /* FIXME!!! */ + SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host)); + spin_lock_irq(&io_request_lock); /* FIXME!!! */ + } + + if (host->block) + host_active = host; + + host->host_busy++; + device->device_busy++; - if (!host) - { - panic ("Invalid or not present host.\n"); - } - - - /* - * We must prevent reentrancy to the lowlevel host driver. This prevents - * it - we enter a loop until the host we want to talk to is not busy. - * Race conditions are prevented, as interrupts are disabled in between the - * time we check for the host being not busy, and the time we mark it busy - * ourselves. - */ - - SCpnt->pid = scsi_pid++; - - while (SCSI_BLOCK((Scsi_Device *) NULL, host)) { - spin_unlock(&io_request_lock); /* FIXME!!! */ - SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host)); - spin_lock_irq(&io_request_lock); /* FIXME!!! */ - } - - if (host->block) host_active = host; - - host->host_busy++; - device->device_busy++; - - /* - * Our own function scsi_done (which marks the host as not busy, disables - * the timeout counter, etc) will be called by us or by the - * scsi_hosts[host].queuecommand() function needs to also call - * the completion function for the high level driver. - */ - - memcpy ((void *) SCpnt->data_cmnd , (const void *) cmnd, 12); - SCpnt->reset_chain = NULL; - SCpnt->serial_number = 0; - SCpnt->serial_number_at_timeout = 0; - SCpnt->bufflen = bufflen; - SCpnt->buffer = buffer; - SCpnt->flags = 0; - SCpnt->retries = 0; - SCpnt->allowed = retries; - SCpnt->done = done; - SCpnt->timeout_per_command = timeout; - - memcpy ((void *) SCpnt->cmnd , (const void *) cmnd, 12); - /* Zero the sense buffer. Some host adapters automatically request - * sense on error. 0 is not a valid sense code. - */ - memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer); - SCpnt->request_buffer = buffer; - SCpnt->request_bufflen = bufflen; - SCpnt->old_use_sg = SCpnt->use_sg; - if (SCpnt->cmd_len == 0) - SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); - SCpnt->old_cmd_len = SCpnt->cmd_len; - - /* Start the timer ticking. */ - - SCpnt->internal_timeout = NORMAL_TIMEOUT; - SCpnt->abort_reason = 0; - SCpnt->result = 0; - internal_cmnd (SCpnt); + /* + * Our own function scsi_done (which marks the host as not busy, disables + * the timeout counter, etc) will be called by us or by the + * scsi_hosts[host].queuecommand() function needs to also call + * the completion function for the high level driver. + */ + + memcpy((void *) SCpnt->data_cmnd, (const void *) cmnd, 12); + SCpnt->reset_chain = NULL; + SCpnt->serial_number = 0; + SCpnt->serial_number_at_timeout = 0; + SCpnt->bufflen = bufflen; + SCpnt->buffer = buffer; + SCpnt->flags = 0; + SCpnt->retries = 0; + SCpnt->allowed = retries; + SCpnt->done = done; + SCpnt->timeout_per_command = timeout; + + memcpy((void *) SCpnt->cmnd, (const void *) cmnd, 12); + /* Zero the sense buffer. Some host adapters automatically request + * sense on error. 0 is not a valid sense code. + */ + memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer); + SCpnt->request_buffer = buffer; + SCpnt->request_bufflen = bufflen; + SCpnt->old_use_sg = SCpnt->use_sg; + if (SCpnt->cmd_len == 0) + SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); + SCpnt->old_cmd_len = SCpnt->cmd_len; + + /* Start the timer ticking. */ + + SCpnt->internal_timeout = NORMAL_TIMEOUT; + SCpnt->abort_reason = 0; + SCpnt->result = 0; + internal_cmnd(SCpnt); - SCSI_LOG_MLQUEUE(3,printk ("Leaving scsi_do_cmd()\n")); + SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n")); } /* This function is the mid-level interrupt routine, which decides how @@ -1577,60 +1566,57 @@ * engineer something to deal with it so that only the outer layer ever does any real * processing. */ -void -scsi_done (Scsi_Cmnd * SCpnt) +void scsi_done(Scsi_Cmnd * SCpnt) { - /* - * We don't have to worry about this one timing out any more. - */ - scsi_delete_timer(SCpnt); - - /* Set the serial numbers back to zero */ - SCpnt->serial_number = 0; - - /* - * First, see whether this command already timed out. If so, we ignore - * the response. We treat it as if the command never finished. - * - * Since serial_number is now 0, the error handler cound detect this - * situation and avoid to call the the low level driver abort routine. - * (DB) - */ - if( SCpnt->state == SCSI_STATE_TIMEOUT ) - { - SCSI_LOG_MLCOMPLETE(1,printk("Ignoring completion of %p due to timeout status", SCpnt)); - return; - } - - SCpnt->serial_number_at_timeout = 0; - SCpnt->state = SCSI_STATE_BHQUEUE; - SCpnt->owner = SCSI_OWNER_BH_HANDLER; - SCpnt->bh_next = NULL; - - /* - * Next, put this command in the BH queue. - * - * We need a spinlock here, or compare and exchange if we can reorder incoming - * Scsi_Cmnds, as it happens pretty often scsi_done is called multiple times - * before bh is serviced. -jj - * - * We already have the io_request_lock here, since we are called from the - * interrupt handler or the error handler. (DB) - * - */ - if (!scsi_bh_queue_head) { - scsi_bh_queue_head = SCpnt; - scsi_bh_queue_tail = SCpnt; - } else { - scsi_bh_queue_tail->bh_next = SCpnt; - scsi_bh_queue_tail = SCpnt; - } - - /* - * Mark the bottom half handler to be run. - */ - mark_bh(SCSI_BH); + /* + * We don't have to worry about this one timing out any more. + */ + scsi_delete_timer(SCpnt); + + /* Set the serial numbers back to zero */ + SCpnt->serial_number = 0; + + /* + * First, see whether this command already timed out. If so, we ignore + * the response. We treat it as if the command never finished. + * + * Since serial_number is now 0, the error handler cound detect this + * situation and avoid to call the the low level driver abort routine. + * (DB) + */ + if (SCpnt->state == SCSI_STATE_TIMEOUT) { + SCSI_LOG_MLCOMPLETE(1, printk("Ignoring completion of %p due to timeout status", SCpnt)); + return; + } + SCpnt->serial_number_at_timeout = 0; + SCpnt->state = SCSI_STATE_BHQUEUE; + SCpnt->owner = SCSI_OWNER_BH_HANDLER; + SCpnt->bh_next = NULL; + + /* + * Next, put this command in the BH queue. + * + * We need a spinlock here, or compare and exchange if we can reorder incoming + * Scsi_Cmnds, as it happens pretty often scsi_done is called multiple times + * before bh is serviced. -jj + * + * We already have the io_request_lock here, since we are called from the + * interrupt handler or the error handler. (DB) + * + */ + if (!scsi_bh_queue_head) { + scsi_bh_queue_head = SCpnt; + scsi_bh_queue_tail = SCpnt; + } else { + scsi_bh_queue_tail->bh_next = SCpnt; + scsi_bh_queue_tail = SCpnt; + } + + /* + * Mark the bottom half handler to be run. + */ + mark_bh(SCSI_BH); } /* @@ -1651,113 +1637,102 @@ */ void scsi_bottom_half_handler(void) { - Scsi_Cmnd * SCpnt; - Scsi_Cmnd * SCnext; - unsigned long flags; - - spin_lock_irqsave(&io_request_lock, flags); - - while(1==1) - { - SCpnt = scsi_bh_queue_head; - scsi_bh_queue_head = NULL; - - if( SCpnt == NULL ) { - spin_unlock_irqrestore(&io_request_lock, flags); - return; - } - - SCnext = SCpnt->bh_next; - - for(; SCpnt; SCpnt = SCnext) - { - SCnext = SCpnt->bh_next; - - switch( scsi_decide_disposition(SCpnt) ) - { - case SUCCESS: - /* - * Add to BH queue. - */ - SCSI_LOG_MLCOMPLETE(3,printk("Command finished %d %d 0x%x\n", SCpnt->host->host_busy, - SCpnt->host->host_failed, - SCpnt->result)); - - scsi_finish_command(SCpnt); - break; - case NEEDS_RETRY: - /* - * We only come in here if we want to retry a command. The - * test to see whether the command should be retried should be - * keeping track of the number of tries, so we don't end up looping, - * of course. - */ - SCSI_LOG_MLCOMPLETE(3,printk("Command needs retry %d %d 0x%x\n", SCpnt->host->host_busy, - SCpnt->host->host_failed, SCpnt->result)); - - scsi_retry_command(SCpnt); - break; - case ADD_TO_MLQUEUE: - /* - * This typically happens for a QUEUE_FULL message - - * typically only when the queue depth is only - * approximate for a given device. Adding a command - * to the queue for the device will prevent further commands - * from being sent to the device, so we shouldn't end up - * with tons of things being sent down that shouldn't be. - */ - scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_DEVICE_BUSY); - break; - default: - /* - * Here we have a fatal error of some sort. Turn it over to - * the error handler. - */ - SCSI_LOG_MLCOMPLETE(3,printk("Command failed %p %x active=%d busy=%d failed=%d\n", - SCpnt, SCpnt->result, - atomic_read(&SCpnt->host->host_active), - SCpnt->host->host_busy, - SCpnt->host->host_failed)); - - /* - * Dump the sense information too. - */ - if ((status_byte (SCpnt->result) & CHECK_CONDITION) != 0) - { - SCSI_LOG_MLCOMPLETE(3,print_sense("bh",SCpnt)); - } - - - if( SCpnt->host->eh_wait != NULL ) - { - SCpnt->host->host_failed++; - SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; - SCpnt->state = SCSI_STATE_FAILED; - SCpnt->host->in_recovery = 1; - /* - * If the host is having troubles, then look to see if this was the last - * command that might have failed. If so, wake up the error handler. - */ - if( SCpnt->host->host_busy == SCpnt->host->host_failed ) - { - SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n", - atomic_read(&SCpnt->host->eh_wait->count))); - up(SCpnt->host->eh_wait); - } - } - else - { - /* - * We only get here if the error recovery thread has died. - */ - scsi_finish_command(SCpnt); - } - } - } /* for(; SCpnt...) */ + Scsi_Cmnd *SCpnt; + Scsi_Cmnd *SCnext; + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + + while (1 == 1) { + SCpnt = scsi_bh_queue_head; + scsi_bh_queue_head = NULL; + + if (SCpnt == NULL) { + spin_unlock_irqrestore(&io_request_lock, flags); + return; + } + SCnext = SCpnt->bh_next; + + for (; SCpnt; SCpnt = SCnext) { + SCnext = SCpnt->bh_next; - } /* while(1==1) */ + switch (scsi_decide_disposition(SCpnt)) { + case SUCCESS: + /* + * Add to BH queue. + */ + SCSI_LOG_MLCOMPLETE(3, printk("Command finished %d %d 0x%x\n", SCpnt->host->host_busy, + SCpnt->host->host_failed, + SCpnt->result)); + + scsi_finish_command(SCpnt); + break; + case NEEDS_RETRY: + /* + * We only come in here if we want to retry a command. The + * test to see whether the command should be retried should be + * keeping track of the number of tries, so we don't end up looping, + * of course. + */ + SCSI_LOG_MLCOMPLETE(3, printk("Command needs retry %d %d 0x%x\n", SCpnt->host->host_busy, + SCpnt->host->host_failed, SCpnt->result)); + + scsi_retry_command(SCpnt); + break; + case ADD_TO_MLQUEUE: + /* + * This typically happens for a QUEUE_FULL message - + * typically only when the queue depth is only + * approximate for a given device. Adding a command + * to the queue for the device will prevent further commands + * from being sent to the device, so we shouldn't end up + * with tons of things being sent down that shouldn't be. + */ + scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_DEVICE_BUSY); + break; + default: + /* + * Here we have a fatal error of some sort. Turn it over to + * the error handler. + */ + SCSI_LOG_MLCOMPLETE(3, printk("Command failed %p %x active=%d busy=%d failed=%d\n", + SCpnt, SCpnt->result, + atomic_read(&SCpnt->host->host_active), + SCpnt->host->host_busy, + SCpnt->host->host_failed)); + + /* + * Dump the sense information too. + */ + if ((status_byte(SCpnt->result) & CHECK_CONDITION) != 0) { + SCSI_LOG_MLCOMPLETE(3, print_sense("bh", SCpnt)); + } + if (SCpnt->host->eh_wait != NULL) { + SCpnt->host->host_failed++; + SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; + SCpnt->state = SCSI_STATE_FAILED; + SCpnt->host->in_recovery = 1; + /* + * If the host is having troubles, then look to see if this was the last + * command that might have failed. If so, wake up the error handler. + */ + if (SCpnt->host->host_busy == SCpnt->host->host_failed) { + SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n", + atomic_read(&SCpnt->host->eh_wait->count))); + up(SCpnt->host->eh_wait); + } + } else { + /* + * We only get here if the error recovery thread has died. + */ + scsi_finish_command(SCpnt); + } + } + } /* for(; SCpnt...) */ + + } /* while(1==1) */ - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); } @@ -1771,18 +1746,17 @@ * level drivers should not become re-entrant as a result of * this. */ -int -scsi_retry_command(Scsi_Cmnd * SCpnt) +int scsi_retry_command(Scsi_Cmnd * SCpnt) { - memcpy ((void *) SCpnt->cmnd, (void*) SCpnt->data_cmnd, - sizeof(SCpnt->data_cmnd)); - SCpnt->request_buffer = SCpnt->buffer; - SCpnt->request_bufflen = SCpnt->bufflen; - SCpnt->use_sg = SCpnt->old_use_sg; - SCpnt->cmd_len = SCpnt->old_cmd_len; - SCpnt->result = 0; - memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer); - return internal_cmnd (SCpnt); + memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, + sizeof(SCpnt->data_cmnd)); + SCpnt->request_buffer = SCpnt->buffer; + SCpnt->request_bufflen = SCpnt->bufflen; + SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->result = 0; + memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer); + return internal_cmnd(SCpnt); } /* @@ -1792,234 +1766,222 @@ * request, waking processes that are waiting on results, * etc. */ -void -scsi_finish_command(Scsi_Cmnd * SCpnt) +void scsi_finish_command(Scsi_Cmnd * SCpnt) { - struct Scsi_Host * host; - Scsi_Device * device; + struct Scsi_Host *host; + Scsi_Device *device; - host = SCpnt->host; - device = SCpnt->device; + host = SCpnt->host; + device = SCpnt->device; - host->host_busy--; /* Indicate that we are free */ - device->device_busy--; /* Decrement device usage counter. */ - - if (host->block && host->host_busy == 0) - { - host_active = NULL; - - /* For block devices "wake_up" is done in end_scsi_request */ - if (!SCSI_BLK_MAJOR(MAJOR(SCpnt->request.rq_dev))) { - struct Scsi_Host * next; - - for (next = host->block; next != host; next = next->block) - wake_up(&next->host_wait); - } - - } - - /* - * Now try and drain the mid-level queue if any commands have been - * inserted. Check to see whether the queue even has anything in - * it first, as otherwise this is useless overhead. - */ - if( SCpnt->host->pending_commands != NULL ) - { - scsi_mlqueue_finish(SCpnt->host, SCpnt->device); - } - - wake_up(&host->host_wait); - - /* - * If we have valid sense information, then some kind of recovery - * must have taken place. Make a note of this. - */ - if( scsi_sense_valid(SCpnt) ) - { - SCpnt->result |= (DRIVER_SENSE << 24); - } - - SCSI_LOG_MLCOMPLETE(3,printk("Notifying upper driver of completion for device %d %x\n", - SCpnt->device->id, SCpnt->result)); - - SCpnt->owner = SCSI_OWNER_HIGHLEVEL; - SCpnt->state = SCSI_STATE_FINISHED; + host->host_busy--; /* Indicate that we are free */ + device->device_busy--; /* Decrement device usage counter. */ - /* We can get here with use_sg=0, causing a panic in the upper level (DB) */ - SCpnt->use_sg = SCpnt->old_use_sg; + if (host->block && host->host_busy == 0) { + host_active = NULL; - SCpnt->done (SCpnt); -} + /* For block devices "wake_up" is done in end_scsi_request */ + if (!SCSI_BLK_MAJOR(MAJOR(SCpnt->request.rq_dev))) { + struct Scsi_Host *next; -#ifdef CONFIG_MODULES -static int scsi_register_host(Scsi_Host_Template *); -static void scsi_unregister_host(Scsi_Host_Template *); -#endif + for (next = host->block; next != host; next = next->block) + wake_up(&next->host_wait); + } + } + /* + * Now try and drain the mid-level queue if any commands have been + * inserted. Check to see whether the queue even has anything in + * it first, as otherwise this is useless overhead. + */ + if (SCpnt->host->pending_commands != NULL) { + scsi_mlqueue_finish(SCpnt->host, SCpnt->device); + } + wake_up(&host->host_wait); + + /* + * If we have valid sense information, then some kind of recovery + * must have taken place. Make a note of this. + */ + if (scsi_sense_valid(SCpnt)) { + SCpnt->result |= (DRIVER_SENSE << 24); + } + SCSI_LOG_MLCOMPLETE(3, printk("Notifying upper driver of completion for device %d %x\n", + SCpnt->device->id, SCpnt->result)); + + SCpnt->owner = SCSI_OWNER_HIGHLEVEL; + SCpnt->state = SCSI_STATE_FINISHED; + + /* We can get here with use_sg=0, causing a panic in the upper level (DB) */ + SCpnt->use_sg = SCpnt->old_use_sg; + + SCpnt->done(SCpnt); +} + +#ifdef CONFIG_MODULES +static int scsi_register_host(Scsi_Host_Template *); +static void scsi_unregister_host(Scsi_Host_Template *); +#endif void *scsi_malloc(unsigned int len) { - unsigned int nbits, mask; - int i, j; - if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE) - return NULL; - - nbits = len >> 9; - mask = (1 << nbits) - 1; - - for(i=0;i < dma_sectors / SECTORS_PER_PAGE; i++) - for(j=0; j<=SECTORS_PER_PAGE - nbits; j++){ - if ((dma_malloc_freelist[i] & (mask << j)) == 0){ - dma_malloc_freelist[i] |= (mask << j); - scsi_dma_free_sectors -= nbits; + unsigned int nbits, mask; + int i, j; + if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE) + return NULL; + + nbits = len >> 9; + mask = (1 << nbits) - 1; + + for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++) + for (j = 0; j <= SECTORS_PER_PAGE - nbits; j++) { + if ((dma_malloc_freelist[i] & (mask << j)) == 0) { + dma_malloc_freelist[i] |= (mask << j); + scsi_dma_free_sectors -= nbits; #ifdef DEBUG - SCSI_LOG_MLQUEUE(3,printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9))); - printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9)); + SCSI_LOG_MLQUEUE(3, printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9))); + printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9)); #endif - return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9)); - } - } - return NULL; /* Nope. No more */ + return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9)); + } + } + return NULL; /* Nope. No more */ } int scsi_free(void *obj, unsigned int len) { - unsigned int page, sector, nbits, mask; + unsigned int page, sector, nbits, mask; #ifdef DEBUG - unsigned long ret = 0; + unsigned long ret = 0; #ifdef __mips__ - __asm__ __volatile__ ("move\t%0,$31":"=r"(ret)); + __asm__ __volatile__("move\t%0,$31":"=r"(ret)); #else - ret = __builtin_return_address(0); + ret = __builtin_return_address(0); #endif - printk("scsi_free %p %d\n",obj, len); - SCSI_LOG_MLQUEUE(3,printk("SFree: %p %d\n",obj, len)); + printk("scsi_free %p %d\n", obj, len); + SCSI_LOG_MLQUEUE(3, printk("SFree: %p %d\n", obj, len)); #endif - for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) { - unsigned long page_addr = (unsigned long) dma_malloc_pages[page]; - if ((unsigned long) obj >= page_addr && - (unsigned long) obj < page_addr + PAGE_SIZE) - { - sector = (((unsigned long) obj) - page_addr) >> 9; + for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) { + unsigned long page_addr = (unsigned long) dma_malloc_pages[page]; + if ((unsigned long) obj >= page_addr && + (unsigned long) obj < page_addr + PAGE_SIZE) { + sector = (((unsigned long) obj) - page_addr) >> 9; - nbits = len >> 9; - mask = (1 << nbits) - 1; + nbits = len >> 9; + mask = (1 << nbits) - 1; - if ((mask << sector) >= (1 << SECTORS_PER_PAGE)) - panic ("scsi_free:Bad memory alignment"); + if ((mask << sector) >= (1 << SECTORS_PER_PAGE)) + panic("scsi_free:Bad memory alignment"); - if((dma_malloc_freelist[page] & - (mask << sector)) != (mask<host; - int j; - Scsi_Cmnd * SCpnt; - - if (SDpnt->queue_depth == 0) - SDpnt->queue_depth = host->cmd_per_lun; - SDpnt->device_queue = NULL; - - for(j=0;jqueue_depth;j++){ - SCpnt = (Scsi_Cmnd *) - scsi_init_malloc(sizeof(Scsi_Cmnd), - GFP_ATOMIC | - (host->unchecked_isa_dma ? GFP_DMA : 0)); - if (NULL == SCpnt) - break; /* If not, the next line will oops ... */ - memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout)); - SCpnt->host = host; - SCpnt->device = SDpnt; - SCpnt->target = SDpnt->id; - SCpnt->lun = SDpnt->lun; - SCpnt->channel = SDpnt->channel; - SCpnt->request.rq_status = RQ_INACTIVE; - SCpnt->host_wait = FALSE; - SCpnt->device_wait = FALSE; - SCpnt->use_sg = 0; - SCpnt->old_use_sg = 0; - SCpnt->old_cmd_len = 0; - SCpnt->underflow = 0; - SCpnt->transfersize = 0; - SCpnt->serial_number = 0; - SCpnt->serial_number_at_timeout = 0; - SCpnt->host_scribble = NULL; - SCpnt->next = SDpnt->device_queue; - SDpnt->device_queue = SCpnt; - SCpnt->state = SCSI_STATE_UNUSED; - SCpnt->owner = SCSI_OWNER_NOBODY; - } - if (j < SDpnt->queue_depth) { /* low on space (D.Gilbert 990424) */ - printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n", - SDpnt->queue_depth, j); - SDpnt->queue_depth = j; - SDpnt->has_cmdblocks = (0 != j); - } - else - SDpnt->has_cmdblocks = 1; + struct Scsi_Host *host = SDpnt->host; + int j; + Scsi_Cmnd *SCpnt; + + if (SDpnt->queue_depth == 0) + SDpnt->queue_depth = host->cmd_per_lun; + SDpnt->device_queue = NULL; + + for (j = 0; j < SDpnt->queue_depth; j++) { + SCpnt = (Scsi_Cmnd *) + scsi_init_malloc(sizeof(Scsi_Cmnd), + GFP_ATOMIC | + (host->unchecked_isa_dma ? GFP_DMA : 0)); + if (NULL == SCpnt) + break; /* If not, the next line will oops ... */ + memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout)); + SCpnt->host = host; + SCpnt->device = SDpnt; + SCpnt->target = SDpnt->id; + SCpnt->lun = SDpnt->lun; + SCpnt->channel = SDpnt->channel; + SCpnt->request.rq_status = RQ_INACTIVE; + SCpnt->host_wait = FALSE; + SCpnt->device_wait = FALSE; + SCpnt->use_sg = 0; + SCpnt->old_use_sg = 0; + SCpnt->old_cmd_len = 0; + SCpnt->underflow = 0; + SCpnt->transfersize = 0; + SCpnt->serial_number = 0; + SCpnt->serial_number_at_timeout = 0; + SCpnt->host_scribble = NULL; + SCpnt->next = SDpnt->device_queue; + SDpnt->device_queue = SCpnt; + SCpnt->state = SCSI_STATE_UNUSED; + SCpnt->owner = SCSI_OWNER_NOBODY; + } + if (j < SDpnt->queue_depth) { /* low on space (D.Gilbert 990424) */ + printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n", + SDpnt->queue_depth, j); + SDpnt->queue_depth = j; + SDpnt->has_cmdblocks = (0 != j); + } else + SDpnt->has_cmdblocks = 1; } -#ifndef MODULE /* { */ +#ifndef MODULE /* { */ /* * scsi_dev_init() is our initialization routine, which in turn calls host * initialization, bus scanning, and sd/st initialization routines. @@ -2027,449 +1989,398 @@ */ int __init scsi_dev_init(void) { - Scsi_Device * SDpnt; - struct Scsi_Host * shpnt; - struct Scsi_Device_Template * sdtpnt; + Scsi_Device *SDpnt; + struct Scsi_Host *shpnt; + struct Scsi_Device_Template *sdtpnt; #ifdef FOO_ON_YOU - return; + return; #endif - /* Yes we're here... */ + /* Yes we're here... */ #if CONFIG_PROC_FS - dispatch_scsi_info_ptr = dispatch_scsi_info; + dispatch_scsi_info_ptr = dispatch_scsi_info; #endif - /* Init a few things so we can "malloc" memory. */ - scsi_loadable_module_flag = 0; + /* Init a few things so we can "malloc" memory. */ + scsi_loadable_module_flag = 0; - /* Register the /proc/scsi/scsi entry */ + /* Register the /proc/scsi/scsi entry */ #if CONFIG_PROC_FS - proc_scsi_register(0, &proc_scsi_scsi); + proc_scsi_register(0, &proc_scsi_scsi); #endif - /* initialize all hosts */ - scsi_init(); + /* initialize all hosts */ + scsi_init(); - /* - * This is where the processing takes place for most everything - * when commands are completed. Until we do this, we will not be able - * to queue any commands. - */ - init_bh(SCSI_BH, scsi_bottom_half_handler); - - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - scan_scsis(shpnt,0,0,0,0); /* scan for scsi devices */ - if (shpnt->select_queue_depths != NULL) - (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); - } - - printk("scsi : detected "); - for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if (sdtpnt->dev_noticed && sdtpnt->name) - printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name, - (sdtpnt->dev_noticed != 1) ? "s" : ""); - printk("total.\n"); - - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); - - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - for(SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) - { - /* SDpnt->scsi_request_fn = NULL; */ - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); - if(SDpnt->attached) { - scsi_build_commandblocks(SDpnt); - if (0 == SDpnt->has_cmdblocks) { - printk("scsi_dev_init: DANGER, no command blocks\n"); - /* What to do now ?? */ - } - } - } - } - - /* - * This should build the DMA pool. - */ - resize_dma_pool(); - - /* - * OK, now we finish the initialization by doing spin-up, read - * capacity, etc, etc - */ - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->finish && sdtpnt->nr_dev) - (*sdtpnt->finish)(); + /* + * This is where the processing takes place for most everything + * when commands are completed. Until we do this, we will not be able + * to queue any commands. + */ + init_bh(SCSI_BH, scsi_bottom_half_handler); - scsi_loadable_module_flag = 1; + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + scan_scsis(shpnt, 0, 0, 0, 0); /* scan for scsi devices */ + if (shpnt->select_queue_depths != NULL) + (shpnt->select_queue_depths) (shpnt, shpnt->host_queue); + } + + printk("scsi : detected "); + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if (sdtpnt->dev_noticed && sdtpnt->name) + printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name, + (sdtpnt->dev_noticed != 1) ? "s" : ""); + printk("total.\n"); + + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if (sdtpnt->init && sdtpnt->dev_noticed) + (*sdtpnt->init) (); + + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) { + /* SDpnt->scsi_request_fn = NULL; */ + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if (sdtpnt->attach) + (*sdtpnt->attach) (SDpnt); + if (SDpnt->attached) { + scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) { + printk("scsi_dev_init: DANGER, no command blocks\n"); + /* What to do now ?? */ + } + } + } + } - return 0; + /* + * This should build the DMA pool. + */ + resize_dma_pool(); + + /* + * OK, now we finish the initialization by doing spin-up, read + * capacity, etc, etc + */ + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if (sdtpnt->finish && sdtpnt->nr_dev) + (*sdtpnt->finish) (); + + scsi_loadable_module_flag = 1; + + return 0; } -#endif /* MODULE */ /* } */ +#endif /* MODULE */ /* } */ static void print_inquiry(unsigned char *data) { - int i; + int i; - printk(" Vendor: "); - for (i = 8; i < 16; i++) - { - if (data[i] >= 0x20 && i < data[4] + 5) - printk("%c", data[i]); - else - printk(" "); - } + printk(" Vendor: "); + for (i = 8; i < 16; i++) { + if (data[i] >= 0x20 && i < data[4] + 5) + printk("%c", data[i]); + else + printk(" "); + } - printk(" Model: "); - for (i = 16; i < 32; i++) - { - if (data[i] >= 0x20 && i < data[4] + 5) - printk("%c", data[i]); - else - printk(" "); - } + printk(" Model: "); + for (i = 16; i < 32; i++) { + if (data[i] >= 0x20 && i < data[4] + 5) + printk("%c", data[i]); + else + printk(" "); + } - printk(" Rev: "); - for (i = 32; i < 36; i++) - { - if (data[i] >= 0x20 && i < data[4] + 5) - printk("%c", data[i]); - else - printk(" "); - } + printk(" Rev: "); + for (i = 32; i < 36; i++) { + if (data[i] >= 0x20 && i < data[4] + 5) + printk("%c", data[i]); + else + printk(" "); + } - printk("\n"); + printk("\n"); - i = data[0] & 0x1f; + i = data[0] & 0x1f; - printk(" Type: %s ", - i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown " ); - printk(" ANSI SCSI revision: %02x", data[2] & 0x07); - if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1) - printk(" CCS\n"); - else - printk("\n"); + printk(" Type: %s ", + i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown "); + printk(" ANSI SCSI revision: %02x", data[2] & 0x07); + if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1) + printk(" CCS\n"); + else + printk("\n"); } #ifdef CONFIG_PROC_FS int scsi_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout) + int hostno, int inout) { - Scsi_Cmnd *SCpnt; - struct Scsi_Device_Template *SDTpnt; - Scsi_Device *scd; - struct Scsi_Host *HBA_ptr; - char *p; - int host, channel, id, lun; - int size, len = 0; - off_t begin = 0; - off_t pos = 0; - - if(inout == 0) { - /* - * First, see if there are any attached devices or not. - */ - for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) - { - if( HBA_ptr->host_queue != NULL ) - { - break; - } - } - size = sprintf(buffer+len,"Attached devices: %s\n", (HBA_ptr)?"":"none"); - len += size; - pos = begin + len; - for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) - { + Scsi_Cmnd *SCpnt; + struct Scsi_Device_Template *SDTpnt; + Scsi_Device *scd; + struct Scsi_Host *HBA_ptr; + char *p; + int host, channel, id, lun; + int size, len = 0; + off_t begin = 0; + off_t pos = 0; + + if (inout == 0) { + /* + * First, see if there are any attached devices or not. + */ + for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) { + if (HBA_ptr->host_queue != NULL) { + break; + } + } + size = sprintf(buffer + len, "Attached devices: %s\n", (HBA_ptr) ? "" : "none"); + len += size; + pos = begin + len; + for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) { #if 0 - size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, - HBA_ptr->hostt->procname); - len += size; - pos = begin + len; -#endif - for(scd = HBA_ptr->host_queue; scd; scd = scd->next) - { - proc_print_scsidevice(scd, buffer, &size, len); - len += size; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - } - } - - stop_output: - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Start slop */ - if(len>length) - len = length; /* Ending slop */ - return (len); - } - - if(!buffer || length < 11 || strncmp("scsi", buffer, 4)) - return(-EINVAL); - - /* - * Usage: echo "scsi dump #N" > /proc/scsi/scsi - * to dump status of all scsi commands. The number is used to specify the level - * of detail in the dump. - */ - if(!strncmp("dump", buffer + 5, 4)) - { - unsigned int level; - - p = buffer + 10; - - if( *p == '\0' ) - return (-EINVAL); - - level = simple_strtoul(p, NULL, 0); - scsi_dump_status(level); - } - /* - * Usage: echo "scsi log token #N" > /proc/scsi/scsi - * where token is one of [error,scan,mlqueue,mlcomplete,llqueue, - * llcomplete,hlqueue,hlcomplete] - */ -#if CONFIG_SCSI_LOGGING /* { */ - - if(!strncmp("log", buffer + 5, 3)) - { - char * token; - unsigned int level; - - p = buffer + 9; - token = p; - while(*p != ' ' && *p != '\t' && *p != '\0') - { - p++; - } - - if( *p == '\0' ) - { - if( strncmp(token, "all", 3) == 0 ) - { - /* - * Turn on absolutely everything. - */ - scsi_logging_level = ~0; - } - else if( strncmp(token, "none", 4) == 0 ) - { - /* - * Turn off absolutely everything. - */ - scsi_logging_level = 0; - } - else - { - return (-EINVAL); - } - } - else - { - *p++ = '\0'; - - level = simple_strtoul(p, NULL, 0); - - /* - * Now figure out what to do with it. - */ - if( strcmp(token, "error") == 0 ) - { - SCSI_SET_ERROR_RECOVERY_LOGGING(level); - } - else if( strcmp(token, "timeout") == 0 ) - { - SCSI_SET_TIMEOUT_LOGGING(level); - } - else if( strcmp(token, "scan") == 0 ) - { - SCSI_SET_SCAN_BUS_LOGGING(level); - } - else if( strcmp(token, "mlqueue") == 0 ) - { - SCSI_SET_MLQUEUE_LOGGING(level); - } - else if( strcmp(token, "mlcomplete") == 0 ) - { - SCSI_SET_MLCOMPLETE_LOGGING(level); - } - else if( strcmp(token, "llqueue") == 0 ) - { - SCSI_SET_LLQUEUE_LOGGING(level); - } - else if( strcmp(token, "llcomplete") == 0 ) - { - SCSI_SET_LLCOMPLETE_LOGGING(level); - } - else if( strcmp(token, "hlqueue") == 0 ) - { - SCSI_SET_HLQUEUE_LOGGING(level); - } - else if( strcmp(token, "hlcomplete") == 0 ) - { - SCSI_SET_HLCOMPLETE_LOGGING(level); - } - else if( strcmp(token, "ioctl") == 0 ) - { - SCSI_SET_IOCTL_LOGGING(level); - } - else - { - return (-EINVAL); - } - } - - printk("scsi logging level set to 0x%8.8x\n", scsi_logging_level); - } -#endif /* CONFIG_SCSI_LOGGING */ /* } */ - - /* - * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi - * with "0 1 2 3" replaced by your "Host Channel Id Lun". - * Consider this feature BETA. - * CAUTION: This is not for hotplugging your peripherals. As - * SCSI was not designed for this you could damage your - * hardware ! - * However perhaps it is legal to switch on an - * already connected device. It is perhaps not - * guaranteed this device doesn't corrupt an ongoing data transfer. - */ - if(!strncmp("add-single-device", buffer + 5, 17)) { - p = buffer + 23; - - host = simple_strtoul(p, &p, 0); - channel = simple_strtoul(p+1, &p, 0); - id = simple_strtoul(p+1, &p, 0); - lun = simple_strtoul(p+1, &p, 0); - - printk("scsi singledevice %d %d %d %d\n", host, channel, - id, lun); - - for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) - { - if( HBA_ptr->host_no == host ) - { - break; - } - } - if(!HBA_ptr) - return(-ENXIO); - - for(scd = HBA_ptr->host_queue; scd; scd = scd->next) - { - if((scd->channel == channel - && scd->id == id - && scd->lun == lun)) - { - break; - } - } - - if(scd) - return(-ENOSYS); /* We do not yet support unplugging */ - - scan_scsis (HBA_ptr, 1, channel, id, lun); - - /* FIXME (DB) This assumes that the queue_depth routines can be used - in this context as well, while they were all designed to be - called only once after the detect routine. (DB) */ - if (HBA_ptr->select_queue_depths != NULL) - (HBA_ptr->select_queue_depths)(HBA_ptr, HBA_ptr->host_queue); - - return(length); - - } - - /* - * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi - * with "0 1 2 3" replaced by your "Host Channel Id Lun". - * - * Consider this feature pre-BETA. - * - * CAUTION: This is not for hotplugging your peripherals. As - * SCSI was not designed for this you could damage your - * hardware and thoroughly confuse the SCSI subsystem. - * - */ - else if(!strncmp("remove-single-device", buffer + 5, 20)) { - p = buffer + 26; - - host = simple_strtoul(p, &p, 0); - channel = simple_strtoul(p+1, &p, 0); - id = simple_strtoul(p+1, &p, 0); - lun = simple_strtoul(p+1, &p, 0); - - - for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) - { - if( HBA_ptr->host_no == host ) - { - break; - } - } - if(!HBA_ptr) - return(-ENODEV); - - for(scd = HBA_ptr->host_queue; scd; scd = scd->next) - { - if((scd->channel == channel - && scd->id == id - && scd->lun == lun)) - { - break; - } - } - - if(scd == NULL) - return(-ENODEV); /* there is no such device attached */ - - if(scd->access_count) - return(-EBUSY); - - SDTpnt = scsi_devicelist; - while(SDTpnt != NULL) { - if(SDTpnt->detach) (*SDTpnt->detach)(scd); - SDTpnt = SDTpnt->next; - } - - if(scd->attached == 0) { - /* - * Nobody is using this device any more. - * Free all of the command structures. - */ - for(SCpnt=scd->device_queue; SCpnt; SCpnt = SCpnt->next) - { - scd->device_queue = SCpnt->next; - scsi_init_free((char *) SCpnt, sizeof(*SCpnt)); - } - /* Now we can remove the device structure */ - if( scd->next != NULL ) - scd->next->prev = scd->prev; - - if( scd->prev != NULL ) - scd->prev->next = scd->next; - - if( HBA_ptr->host_queue == scd ) - { - HBA_ptr->host_queue = scd->next; - } - - scsi_init_free((char *) scd, sizeof(Scsi_Device)); - } else { - return(-EBUSY); - } - return(0); - } - return(-EINVAL); + size += sprintf(buffer + len, "scsi%2d: %s\n", (int) HBA_ptr->host_no, + HBA_ptr->hostt->procname); + len += size; + pos = begin + len; +#endif + for (scd = HBA_ptr->host_queue; scd; scd = scd->next) { + proc_print_scsidevice(scd, buffer, &size, len); + len += size; + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + } + } + + stop_output: + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Start slop */ + if (len > length) + len = length; /* Ending slop */ + return (len); + } + if (!buffer || length < 11 || strncmp("scsi", buffer, 4)) + return (-EINVAL); + + /* + * Usage: echo "scsi dump #N" > /proc/scsi/scsi + * to dump status of all scsi commands. The number is used to specify the level + * of detail in the dump. + */ + if (!strncmp("dump", buffer + 5, 4)) { + unsigned int level; + + p = buffer + 10; + + if (*p == '\0') + return (-EINVAL); + + level = simple_strtoul(p, NULL, 0); + scsi_dump_status(level); + } + /* + * Usage: echo "scsi log token #N" > /proc/scsi/scsi + * where token is one of [error,scan,mlqueue,mlcomplete,llqueue, + * llcomplete,hlqueue,hlcomplete] + */ +#if CONFIG_SCSI_LOGGING /* { */ + + if (!strncmp("log", buffer + 5, 3)) { + char *token; + unsigned int level; + + p = buffer + 9; + token = p; + while (*p != ' ' && *p != '\t' && *p != '\0') { + p++; + } + + if (*p == '\0') { + if (strncmp(token, "all", 3) == 0) { + /* + * Turn on absolutely everything. + */ + scsi_logging_level = ~0; + } else if (strncmp(token, "none", 4) == 0) { + /* + * Turn off absolutely everything. + */ + scsi_logging_level = 0; + } else { + return (-EINVAL); + } + } else { + *p++ = '\0'; + + level = simple_strtoul(p, NULL, 0); + + /* + * Now figure out what to do with it. + */ + if (strcmp(token, "error") == 0) { + SCSI_SET_ERROR_RECOVERY_LOGGING(level); + } else if (strcmp(token, "timeout") == 0) { + SCSI_SET_TIMEOUT_LOGGING(level); + } else if (strcmp(token, "scan") == 0) { + SCSI_SET_SCAN_BUS_LOGGING(level); + } else if (strcmp(token, "mlqueue") == 0) { + SCSI_SET_MLQUEUE_LOGGING(level); + } else if (strcmp(token, "mlcomplete") == 0) { + SCSI_SET_MLCOMPLETE_LOGGING(level); + } else if (strcmp(token, "llqueue") == 0) { + SCSI_SET_LLQUEUE_LOGGING(level); + } else if (strcmp(token, "llcomplete") == 0) { + SCSI_SET_LLCOMPLETE_LOGGING(level); + } else if (strcmp(token, "hlqueue") == 0) { + SCSI_SET_HLQUEUE_LOGGING(level); + } else if (strcmp(token, "hlcomplete") == 0) { + SCSI_SET_HLCOMPLETE_LOGGING(level); + } else if (strcmp(token, "ioctl") == 0) { + SCSI_SET_IOCTL_LOGGING(level); + } else { + return (-EINVAL); + } + } + + printk("scsi logging level set to 0x%8.8x\n", scsi_logging_level); + } +#endif /* CONFIG_SCSI_LOGGING */ /* } */ + + /* + * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi + * with "0 1 2 3" replaced by your "Host Channel Id Lun". + * Consider this feature BETA. + * CAUTION: This is not for hotplugging your peripherals. As + * SCSI was not designed for this you could damage your + * hardware ! + * However perhaps it is legal to switch on an + * already connected device. It is perhaps not + * guaranteed this device doesn't corrupt an ongoing data transfer. + */ + if (!strncmp("add-single-device", buffer + 5, 17)) { + p = buffer + 23; + + host = simple_strtoul(p, &p, 0); + channel = simple_strtoul(p + 1, &p, 0); + id = simple_strtoul(p + 1, &p, 0); + lun = simple_strtoul(p + 1, &p, 0); + + printk("scsi singledevice %d %d %d %d\n", host, channel, + id, lun); + + for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) { + if (HBA_ptr->host_no == host) { + break; + } + } + if (!HBA_ptr) + return (-ENXIO); + + for (scd = HBA_ptr->host_queue; scd; scd = scd->next) { + if ((scd->channel == channel + && scd->id == id + && scd->lun == lun)) { + break; + } + } + + if (scd) + return (-ENOSYS); /* We do not yet support unplugging */ + + scan_scsis(HBA_ptr, 1, channel, id, lun); + + /* FIXME (DB) This assumes that the queue_depth routines can be used + in this context as well, while they were all designed to be + called only once after the detect routine. (DB) */ + if (HBA_ptr->select_queue_depths != NULL) + (HBA_ptr->select_queue_depths) (HBA_ptr, HBA_ptr->host_queue); + + return (length); + + } + /* + * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi + * with "0 1 2 3" replaced by your "Host Channel Id Lun". + * + * Consider this feature pre-BETA. + * + * CAUTION: This is not for hotplugging your peripherals. As + * SCSI was not designed for this you could damage your + * hardware and thoroughly confuse the SCSI subsystem. + * + */ + else if (!strncmp("remove-single-device", buffer + 5, 20)) { + p = buffer + 26; + + host = simple_strtoul(p, &p, 0); + channel = simple_strtoul(p + 1, &p, 0); + id = simple_strtoul(p + 1, &p, 0); + lun = simple_strtoul(p + 1, &p, 0); + + + for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) { + if (HBA_ptr->host_no == host) { + break; + } + } + if (!HBA_ptr) + return (-ENODEV); + + for (scd = HBA_ptr->host_queue; scd; scd = scd->next) { + if ((scd->channel == channel + && scd->id == id + && scd->lun == lun)) { + break; + } + } + + if (scd == NULL) + return (-ENODEV); /* there is no such device attached */ + + if (scd->access_count) + return (-EBUSY); + + SDTpnt = scsi_devicelist; + while (SDTpnt != NULL) { + if (SDTpnt->detach) + (*SDTpnt->detach) (scd); + SDTpnt = SDTpnt->next; + } + + if (scd->attached == 0) { + /* + * Nobody is using this device any more. + * Free all of the command structures. + */ + for (SCpnt = scd->device_queue; SCpnt; SCpnt = SCpnt->next) { + scd->device_queue = SCpnt->next; + scsi_init_free((char *) SCpnt, sizeof(*SCpnt)); + } + /* Now we can remove the device structure */ + if (scd->next != NULL) + scd->next->prev = scd->prev; + + if (scd->prev != NULL) + scd->prev->next = scd->next; + + if (HBA_ptr->host_queue == scd) { + HBA_ptr->host_queue = scd->next; + } + scsi_init_free((char *) scd, sizeof(Scsi_Device)); + } else { + return (-EBUSY); + } + return (0); + } + return (-EINVAL); } #endif @@ -2479,197 +2390,186 @@ */ static void resize_dma_pool(void) { - int i, k; - unsigned long size; - struct Scsi_Host * shpnt; - struct Scsi_Host * host = NULL; - Scsi_Device * SDpnt; - FreeSectorBitmap * new_dma_malloc_freelist = NULL; - unsigned int new_dma_sectors = 0; - unsigned int new_need_isa_buffer = 0; - unsigned char ** new_dma_malloc_pages = NULL; - int out_of_space = 0; + int i, k; + unsigned long size; + struct Scsi_Host *shpnt; + struct Scsi_Host *host = NULL; + Scsi_Device *SDpnt; + FreeSectorBitmap *new_dma_malloc_freelist = NULL; + unsigned int new_dma_sectors = 0; + unsigned int new_need_isa_buffer = 0; + unsigned char **new_dma_malloc_pages = NULL; + int out_of_space = 0; + + if (!scsi_hostlist) { + /* + * Free up the DMA pool. + */ + if (scsi_dma_free_sectors != dma_sectors) + panic("SCSI DMA pool memory leak %d %d\n", scsi_dma_free_sectors, dma_sectors); - if( !scsi_hostlist ) - { - /* - * Free up the DMA pool. - */ - if( scsi_dma_free_sectors != dma_sectors ) - panic("SCSI DMA pool memory leak %d %d\n",scsi_dma_free_sectors,dma_sectors); + for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++) + scsi_init_free(dma_malloc_pages[i], PAGE_SIZE); + if (dma_malloc_pages) + scsi_init_free((char *) dma_malloc_pages, + (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages)); + dma_malloc_pages = NULL; + if (dma_malloc_freelist) + scsi_init_free((char *) dma_malloc_freelist, + (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_freelist)); + dma_malloc_freelist = NULL; + dma_sectors = 0; + scsi_dma_free_sectors = 0; + return; + } + /* Next, check to see if we need to extend the DMA buffer pool */ - for(i=0; i < dma_sectors / SECTORS_PER_PAGE; i++) - scsi_init_free(dma_malloc_pages[i], PAGE_SIZE); - if (dma_malloc_pages) - scsi_init_free((char *) dma_malloc_pages, - (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages)); - dma_malloc_pages = NULL; - if (dma_malloc_freelist) - scsi_init_free((char *) dma_malloc_freelist, - (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_freelist)); - dma_malloc_freelist = NULL; - dma_sectors = 0; - scsi_dma_free_sectors = 0; - return; - } - /* Next, check to see if we need to extend the DMA buffer pool */ + new_dma_sectors = 2 * SECTORS_PER_PAGE; /* Base value we use */ + + if (__pa(high_memory) - 1 > ISA_DMA_THRESHOLD) + need_isa_bounce_buffers = 1; + else + need_isa_bounce_buffers = 0; - new_dma_sectors = 2*SECTORS_PER_PAGE; /* Base value we use */ + if (scsi_devicelist) + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) + new_dma_sectors += SECTORS_PER_PAGE; /* Increment for each host */ - if (__pa(high_memory)-1 > ISA_DMA_THRESHOLD) - need_isa_bounce_buffers = 1; - else - need_isa_bounce_buffers = 0; - - if (scsi_devicelist) - for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) - new_dma_sectors += SECTORS_PER_PAGE; /* Increment for each host */ - - for (host = scsi_hostlist; host; host = host->next) - { - for (SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - /* - * sd and sr drivers allocate scatterlists. - * sr drivers may allocate for each command 1x2048 or 2x1024 extra - * buffers for 2k sector size and 1k fs. - * sg driver allocates buffers < 4k. - * st driver does not need buffers from the dma pool. - * estimate 4k buffer/command for devices of unknown type (should panic). - */ - if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM || - SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) { - new_dma_sectors += ((host->sg_tablesize * - sizeof(struct scatterlist) + 511) >> 9) * - SDpnt->queue_depth; - if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM) - new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth; - } - else if (SDpnt->type == TYPE_SCANNER || - SDpnt->type == TYPE_PROCESSOR || - SDpnt->type == TYPE_MEDIUM_CHANGER || - SDpnt->type == TYPE_ENCLOSURE) { - new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth; - } - else { - if (SDpnt->type != TYPE_TAPE) { - printk("resize_dma_pool: unknown device type %d\n", SDpnt->type); - new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth; - } - } - - if(host->unchecked_isa_dma && - need_isa_bounce_buffers && - SDpnt->type != TYPE_TAPE) { - new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize * - SDpnt->queue_depth; - new_need_isa_buffer++; - } - } - } + for (host = scsi_hostlist; host; host = host->next) { + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + /* + * sd and sr drivers allocate scatterlists. + * sr drivers may allocate for each command 1x2048 or 2x1024 extra + * buffers for 2k sector size and 1k fs. + * sg driver allocates buffers < 4k. + * st driver does not need buffers from the dma pool. + * estimate 4k buffer/command for devices of unknown type (should panic). + */ + if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM || + SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) { + new_dma_sectors += ((host->sg_tablesize * + sizeof(struct scatterlist) + 511) >> 9) * + SDpnt->queue_depth; + if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM) + new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth; + } else if (SDpnt->type == TYPE_SCANNER || + SDpnt->type == TYPE_PROCESSOR || + SDpnt->type == TYPE_MEDIUM_CHANGER || + SDpnt->type == TYPE_ENCLOSURE) { + new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth; + } else { + if (SDpnt->type != TYPE_TAPE) { + printk("resize_dma_pool: unknown device type %d\n", SDpnt->type); + new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth; + } + } + + if (host->unchecked_isa_dma && + need_isa_bounce_buffers && + SDpnt->type != TYPE_TAPE) { + new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize * + SDpnt->queue_depth; + new_need_isa_buffer++; + } + } + } #ifdef DEBUG_INIT - printk("resize_dma_pool: needed dma sectors = %d\n", new_dma_sectors); + printk("resize_dma_pool: needed dma sectors = %d\n", new_dma_sectors); #endif - /* limit DMA memory to 32MB: */ - new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; + /* limit DMA memory to 32MB: */ + new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; - /* - * We never shrink the buffers - this leads to - * race conditions that I would rather not even think - * about right now. - */ -#if 0 /* Why do this? No gain and risks out_of_space */ - if( new_dma_sectors < dma_sectors ) - new_dma_sectors = dma_sectors; -#endif - if( new_dma_sectors <= dma_sectors ) - return; /* best to quit while we are in front */ - - for (k = 0; k < 20; ++k) { /* just in case */ - out_of_space = 0; - size = (new_dma_sectors / SECTORS_PER_PAGE) * - sizeof(FreeSectorBitmap); - new_dma_malloc_freelist = (FreeSectorBitmap *) - scsi_init_malloc(size, GFP_ATOMIC); - if (new_dma_malloc_freelist) { - size = (new_dma_sectors / SECTORS_PER_PAGE) * + /* + * We never shrink the buffers - this leads to + * race conditions that I would rather not even think + * about right now. + */ +#if 0 /* Why do this? No gain and risks out_of_space */ + if (new_dma_sectors < dma_sectors) + new_dma_sectors = dma_sectors; +#endif + if (new_dma_sectors <= dma_sectors) + return; /* best to quit while we are in front */ + + for (k = 0; k < 20; ++k) { /* just in case */ + out_of_space = 0; + size = (new_dma_sectors / SECTORS_PER_PAGE) * + sizeof(FreeSectorBitmap); + new_dma_malloc_freelist = (FreeSectorBitmap *) + scsi_init_malloc(size, GFP_ATOMIC); + if (new_dma_malloc_freelist) { + size = (new_dma_sectors / SECTORS_PER_PAGE) * sizeof(*new_dma_malloc_pages); - new_dma_malloc_pages = (unsigned char **) + new_dma_malloc_pages = (unsigned char **) scsi_init_malloc(size, GFP_ATOMIC); - if (! new_dma_malloc_pages) { - size = (new_dma_sectors / SECTORS_PER_PAGE) * + if (!new_dma_malloc_pages) { + size = (new_dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap); - scsi_init_free((char *)new_dma_malloc_freelist, size); - out_of_space = 1; - } + scsi_init_free((char *) new_dma_malloc_freelist, size); + out_of_space = 1; + } + } else + out_of_space = 1; + + if ((!out_of_space) && (new_dma_sectors > dma_sectors)) { + for (i = dma_sectors / SECTORS_PER_PAGE; + i < new_dma_sectors / SECTORS_PER_PAGE; i++) { + new_dma_malloc_pages[i] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + if (!new_dma_malloc_pages[i]) + break; + } + if (i != new_dma_sectors / SECTORS_PER_PAGE) { /* clean up */ + int k = i; + + out_of_space = 1; + for (i = 0; i < k; ++i) + scsi_init_free(new_dma_malloc_pages[i], PAGE_SIZE); + } + } + if (out_of_space) { /* try scaling down new_dma_sectors request */ + printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, " + "wanted=%u, scaling\n", dma_sectors, new_dma_sectors); + if (new_dma_sectors < (8 * SECTORS_PER_PAGE)) + break; /* pretty well hopeless ... */ + new_dma_sectors = (new_dma_sectors * 3) / 4; + new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; + if (new_dma_sectors <= dma_sectors) + break; /* stick with what we have got */ + } else + break; /* found space ... */ + } /* end of for loop */ + if (out_of_space) { + scsi_need_isa_buffer = new_need_isa_buffer; /* some useful info */ + printk(" WARNING, not enough memory, pool not expanded\n"); + return; } - else - out_of_space = 1; - - if ((! out_of_space) && (new_dma_sectors > dma_sectors)) { - for(i = dma_sectors / SECTORS_PER_PAGE; - i < new_dma_sectors / SECTORS_PER_PAGE; i++) { - new_dma_malloc_pages[i] = (unsigned char *) - scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); - if (! new_dma_malloc_pages[i]) - break; - } - if (i != new_dma_sectors / SECTORS_PER_PAGE) { /* clean up */ - int k = i; - - out_of_space = 1; - for (i = 0; i < k; ++i) - scsi_init_free(new_dma_malloc_pages[i], PAGE_SIZE); - } - } - if (out_of_space) { /* try scaling down new_dma_sectors request */ - printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, " - "wanted=%u, scaling\n", dma_sectors, new_dma_sectors); - if (new_dma_sectors < (8 * SECTORS_PER_PAGE)) - break; /* pretty well hopeless ... */ - new_dma_sectors = (new_dma_sectors * 3) / 4; - new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; - if (new_dma_sectors <= dma_sectors) - break; /* stick with what we have got */ + /* When we dick with the actual DMA list, we need to + * protect things + */ + if (dma_malloc_freelist) { + size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap); + memcpy(new_dma_malloc_freelist, dma_malloc_freelist, size); + scsi_init_free((char *) dma_malloc_freelist, size); } - else - break; /* found space ... */ - } /* end of for loop */ - if (out_of_space) { - scsi_need_isa_buffer = new_need_isa_buffer; /* some useful info */ - printk(" WARNING, not enough memory, pool not expanded\n"); - return; - } + dma_malloc_freelist = new_dma_malloc_freelist; - /* When we dick with the actual DMA list, we need to - * protect things - */ - if (dma_malloc_freelist) - { - size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap); - memcpy(new_dma_malloc_freelist, dma_malloc_freelist, size); - scsi_init_free((char *) dma_malloc_freelist, size); - } - dma_malloc_freelist = new_dma_malloc_freelist; - - if (dma_malloc_pages) - { - size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages); - memcpy(new_dma_malloc_pages, dma_malloc_pages, size); - scsi_init_free((char *) dma_malloc_pages, size); - } - - scsi_dma_free_sectors += new_dma_sectors - dma_sectors; - dma_malloc_pages = new_dma_malloc_pages; - dma_sectors = new_dma_sectors; - scsi_need_isa_buffer = new_need_isa_buffer; + if (dma_malloc_pages) { + size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages); + memcpy(new_dma_malloc_pages, dma_malloc_pages, size); + scsi_init_free((char *) dma_malloc_pages, size); + } + scsi_dma_free_sectors += new_dma_sectors - dma_sectors; + dma_malloc_pages = new_dma_malloc_pages; + dma_sectors = new_dma_sectors; + scsi_need_isa_buffer = new_need_isa_buffer; #ifdef DEBUG_INIT - printk("resize_dma_pool: dma free sectors = %d\n", scsi_dma_free_sectors); - printk("resize_dma_pool: dma sectors = %d\n", dma_sectors); - printk("resize_dma_pool: need isa buffers = %d\n", scsi_need_isa_buffer); + printk("resize_dma_pool: dma free sectors = %d\n", scsi_dma_free_sectors); + printk("resize_dma_pool: dma sectors = %d\n", dma_sectors); + printk("resize_dma_pool: need isa buffers = %d\n", scsi_need_isa_buffer); #endif } @@ -2681,175 +2581,157 @@ */ static int scsi_register_host(Scsi_Host_Template * tpnt) { - int pcount; - struct Scsi_Host * shpnt; - Scsi_Device * SDpnt; - struct Scsi_Device_Template * sdtpnt; - const char * name; - unsigned long flags; - int out_of_space = 0; - - if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or - * no detect routine available - */ - pcount = next_scsi_host; - - /* The detect routine must carefully spinunlock/spinlock if - it enables interrupts, since all interrupt handlers do - spinlock as well. - All lame drivers are going to fail due to the following - spinlock. For the time beeing let's use it only for drivers - using the new scsi code. NOTE: the detect routine could - redefine the value tpnt->use_new_eh_code. (DB, 13 May 1998) */ - - if (tpnt->use_new_eh_code) { - spin_lock_irqsave(&io_request_lock, flags); - tpnt->present = tpnt->detect(tpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - } - else - tpnt->present = tpnt->detect(tpnt); - - if (tpnt->present) - { - if(pcount == next_scsi_host) - { - if(tpnt->present > 1) - { - printk("Failure to register low-level scsi driver"); - scsi_unregister_host(tpnt); - return 1; - } - /* - * The low-level driver failed to register a driver. We - * can do this now. - */ - scsi_register(tpnt,0); - } - tpnt->next = scsi_hosts; /* Add to the linked list */ - scsi_hosts = tpnt; + int pcount; + struct Scsi_Host *shpnt; + Scsi_Device *SDpnt; + struct Scsi_Device_Template *sdtpnt; + const char *name; + unsigned long flags; + int out_of_space = 0; + + if (tpnt->next || !tpnt->detect) + return 1; /* Must be already loaded, or + * no detect routine available + */ + pcount = next_scsi_host; + + /* The detect routine must carefully spinunlock/spinlock if + it enables interrupts, since all interrupt handlers do + spinlock as well. + All lame drivers are going to fail due to the following + spinlock. For the time beeing let's use it only for drivers + using the new scsi code. NOTE: the detect routine could + redefine the value tpnt->use_new_eh_code. (DB, 13 May 1998) */ + + if (tpnt->use_new_eh_code) { + spin_lock_irqsave(&io_request_lock, flags); + tpnt->present = tpnt->detect(tpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + } else + tpnt->present = tpnt->detect(tpnt); + + if (tpnt->present) { + if (pcount == next_scsi_host) { + if (tpnt->present > 1) { + printk("Failure to register low-level scsi driver"); + scsi_unregister_host(tpnt); + return 1; + } + /* + * The low-level driver failed to register a driver. We + * can do this now. + */ + scsi_register(tpnt, 0); + } + tpnt->next = scsi_hosts; /* Add to the linked list */ + scsi_hosts = tpnt; - /* Add the new driver to /proc/scsi */ + /* Add the new driver to /proc/scsi */ #if CONFIG_PROC_FS - build_proc_dir_entries(tpnt); + build_proc_dir_entries(tpnt); #endif - /* - * Add the kernel threads for each host adapter that will - * handle error correction. - */ - for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) - { - if( shpnt->hostt == tpnt && shpnt->hostt->use_new_eh_code ) - { - DECLARE_MUTEX_LOCKED(sem); - - shpnt->eh_notify = &sem; - kernel_thread((int (*)(void *))scsi_error_handler, - (void *) shpnt, 0); - - /* - * Now wait for the kernel error thread to initialize itself - * as it might be needed when we scan the bus. - */ - down (&sem); - shpnt->eh_notify = NULL; - } - } - - for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) - { - if(shpnt->hostt == tpnt) - { - if(tpnt->info) - { - name = tpnt->info(shpnt); - } - else - { - name = tpnt->name; - } - printk ("scsi%d : %s\n", /* And print a little message */ - shpnt->host_no, name); - } - } + /* + * Add the kernel threads for each host adapter that will + * handle error correction. + */ + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + if (shpnt->hostt == tpnt && shpnt->hostt->use_new_eh_code) { + DECLARE_MUTEX_LOCKED(sem); + + shpnt->eh_notify = &sem; + kernel_thread((int (*)(void *)) scsi_error_handler, + (void *) shpnt, 0); + + /* + * Now wait for the kernel error thread to initialize itself + * as it might be needed when we scan the bus. + */ + down(&sem); + shpnt->eh_notify = NULL; + } + } - printk ("scsi : %d host%s.\n", next_scsi_host, - (next_scsi_host == 1) ? "" : "s"); + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + if (shpnt->hostt == tpnt) { + if (tpnt->info) { + name = tpnt->info(shpnt); + } else { + name = tpnt->name; + } + printk("scsi%d : %s\n", /* And print a little message */ + shpnt->host_no, name); + } + } - scsi_make_blocked_list(); + printk("scsi : %d host%s.\n", next_scsi_host, + (next_scsi_host == 1) ? "" : "s"); - /* The next step is to call scan_scsis here. This generates the - * Scsi_Devices entries - */ - for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) - { - if(shpnt->hostt == tpnt) - { - scan_scsis(shpnt,0,0,0,0); - if (shpnt->select_queue_depths != NULL) - { - (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); + scsi_make_blocked_list(); + + /* The next step is to call scan_scsis here. This generates the + * Scsi_Devices entries + */ + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + if (shpnt->hostt == tpnt) { + scan_scsis(shpnt, 0, 0, 0, 0); + if (shpnt->select_queue_depths != NULL) { + (shpnt->select_queue_depths) (shpnt, shpnt->host_queue); + } + } } - } - } - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - { - if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); - } - - /* - * Next we create the Scsi_Cmnd structures for this host - */ - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - for(SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) - if(SDpnt->host->hostt == tpnt) - { - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); - if(SDpnt->attached) { - scsi_build_commandblocks(SDpnt); - if (0 == SDpnt->has_cmdblocks) - out_of_space = 1; - } - } - } - - /* - * Now that we have all of the devices, resize the DMA pool, - * as required. */ - if (! out_of_space) - resize_dma_pool(); - - - /* This does any final handling that is required. */ - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - { - if(sdtpnt->finish && sdtpnt->nr_dev) - { - (*sdtpnt->finish)(); - } - } - } + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { + if (sdtpnt->init && sdtpnt->dev_noticed) + (*sdtpnt->init) (); + } + /* + * Next we create the Scsi_Cmnd structures for this host + */ + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) + if (SDpnt->host->hostt == tpnt) { + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if (sdtpnt->attach) + (*sdtpnt->attach) (SDpnt); + if (SDpnt->attached) { + scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) + out_of_space = 1; + } + } + } + + /* + * Now that we have all of the devices, resize the DMA pool, + * as required. */ + if (!out_of_space) + resize_dma_pool(); + + + /* This does any final handling that is required. */ + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { + if (sdtpnt->finish && sdtpnt->nr_dev) { + (*sdtpnt->finish) (); + } + } + } #if defined(USE_STATIC_SCSI_MEMORY) - printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n", - (scsi_memory_upper_value - scsi_memory_lower_value) / 1024, - (scsi_init_memory_start - scsi_memory_lower_value) / 1024, - (scsi_memory_upper_value - scsi_init_memory_start) / 1024); + printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n", + (scsi_memory_upper_value - scsi_memory_lower_value) / 1024, + (scsi_init_memory_start - scsi_memory_lower_value) / 1024, + (scsi_memory_upper_value - scsi_init_memory_start) / 1024); #endif - MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; - if (out_of_space) { - scsi_unregister_host(tpnt); /* easiest way to clean up?? */ - return 1; - } - else - return 0; + if (out_of_space) { + scsi_unregister_host(tpnt); /* easiest way to clean up?? */ + return 1; + } else + return 0; } /* @@ -2864,430 +2746,405 @@ */ static void scsi_unregister_host(Scsi_Host_Template * tpnt) { - int online_status; - int pcount; - Scsi_Cmnd * SCpnt; - Scsi_Device * SDpnt; - Scsi_Device * SDpnt1; - struct Scsi_Device_Template * sdtpnt; - struct Scsi_Host * sh1; - struct Scsi_Host * shpnt; - Scsi_Host_Template * SHT; - Scsi_Host_Template * SHTp; - - /* - * First verify that this host adapter is completely free with no pending - * commands - */ - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - for(SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) - { - if(SDpnt->host->hostt == tpnt - && SDpnt->host->hostt->module - && GET_USE_COUNT(SDpnt->host->hostt->module)) return; - /* - * FIXME(eric) - We need to find a way to notify the - * low level driver that we are shutting down - via the - * special device entry that still needs to get added. - * - * Is detach interface below good enough for this? - */ - } - } - - /* - * FIXME(eric) put a spinlock on this. We force all of the devices offline - * to help prevent race conditions where other hosts/processors could try and - * get in and queue a command. - */ - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - for(SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) - { - if(SDpnt->host->hostt == tpnt ) - SDpnt->online = FALSE; - - } - } - - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - if (shpnt->hostt != tpnt) - { - continue; - } - - for(SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) - { - /* - * Loop over all of the commands associated with the device. If any of - * them are busy, then set the state back to inactive and bail. - */ - for(SCpnt = SDpnt->device_queue; SCpnt; - SCpnt = SCpnt->next) - { - online_status = SDpnt->online; - SDpnt->online = FALSE; - if(SCpnt->request.rq_status != RQ_INACTIVE) - { - printk("SCSI device not inactive - rq_status=%d, target=%d, pid=%ld, state=%d, owner=%d.\n", - SCpnt->request.rq_status, SCpnt->target, SCpnt->pid, - SCpnt->state, SCpnt->owner); - for(SDpnt1 = shpnt->host_queue; SDpnt1; - SDpnt1 = SDpnt1->next) - { - for(SCpnt = SDpnt1->device_queue; SCpnt; - SCpnt = SCpnt->next) - if(SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING) - SCpnt->request.rq_status = RQ_INACTIVE; - } - SDpnt->online = online_status; - printk("Device busy???\n"); - return; - } - /* - * No, this device is really free. Mark it as such, and - * continue on. - */ - SCpnt->state = SCSI_STATE_DISCONNECTING; - SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */ - } - } - } - /* Next we detach the high level drivers from the Scsi_Device structures */ - - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - if(shpnt->hostt != tpnt) - { - continue; - } - - for(SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) - { - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->detach) (*sdtpnt->detach)(SDpnt); - - /* If something still attached, punt */ - if (SDpnt->attached) - { - printk("Attached usage count = %d\n", SDpnt->attached); - return; - } - } - } - - /* - * Next, kill the kernel error recovery thread for this host. - */ - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - if( shpnt->hostt == tpnt - && shpnt->hostt->use_new_eh_code - && shpnt->ehandler != NULL ) - { - DECLARE_MUTEX_LOCKED(sem); - - shpnt->eh_notify = &sem; - send_sig(SIGKILL, shpnt->ehandler, 1); - down(&sem); - shpnt->eh_notify = NULL; - } - } - - /* Next we free up the Scsi_Cmnd structures for this host */ - - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - if(shpnt->hostt != tpnt) - { - continue; - } - - for(SDpnt = shpnt->host_queue; SDpnt; - SDpnt = shpnt->host_queue) - { - while (SDpnt->device_queue) - { - SCpnt = SDpnt->device_queue->next; - scsi_init_free((char *) SDpnt->device_queue, sizeof(Scsi_Cmnd)); - SDpnt->device_queue = SCpnt; - } - SDpnt->has_cmdblocks = 0; - - /* Next free up the Scsi_Device structures for this host */ - shpnt->host_queue = SDpnt->next; - scsi_init_free((char *) SDpnt, sizeof (Scsi_Device)); - - } - } - - /* Next we go through and remove the instances of the individual hosts - * that were detected */ - - for(shpnt = scsi_hostlist; shpnt; shpnt = sh1) - { - sh1 = shpnt->next; - if(shpnt->hostt == tpnt) { - if(shpnt->loaded_as_module) { - pcount = next_scsi_host; - /* Remove the /proc/scsi directory entry */ + int online_status; + int pcount; + Scsi_Cmnd *SCpnt; + Scsi_Device *SDpnt; + Scsi_Device *SDpnt1; + struct Scsi_Device_Template *sdtpnt; + struct Scsi_Host *sh1; + struct Scsi_Host *shpnt; + Scsi_Host_Template *SHT; + Scsi_Host_Template *SHTp; + + /* + * First verify that this host adapter is completely free with no pending + * commands + */ + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (SDpnt = shpnt->host_queue; SDpnt; + SDpnt = SDpnt->next) { + if (SDpnt->host->hostt == tpnt + && SDpnt->host->hostt->module + && GET_USE_COUNT(SDpnt->host->hostt->module)) + return; + /* + * FIXME(eric) - We need to find a way to notify the + * low level driver that we are shutting down - via the + * special device entry that still needs to get added. + * + * Is detach interface below good enough for this? + */ + } + } + + /* + * FIXME(eric) put a spinlock on this. We force all of the devices offline + * to help prevent race conditions where other hosts/processors could try and + * get in and queue a command. + */ + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (SDpnt = shpnt->host_queue; SDpnt; + SDpnt = SDpnt->next) { + if (SDpnt->host->hostt == tpnt) + SDpnt->online = FALSE; + + } + } + + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + if (shpnt->hostt != tpnt) { + continue; + } + for (SDpnt = shpnt->host_queue; SDpnt; + SDpnt = SDpnt->next) { + /* + * Loop over all of the commands associated with the device. If any of + * them are busy, then set the state back to inactive and bail. + */ + for (SCpnt = SDpnt->device_queue; SCpnt; + SCpnt = SCpnt->next) { + online_status = SDpnt->online; + SDpnt->online = FALSE; + if (SCpnt->request.rq_status != RQ_INACTIVE) { + printk("SCSI device not inactive - rq_status=%d, target=%d, pid=%ld, state=%d, owner=%d.\n", + SCpnt->request.rq_status, SCpnt->target, SCpnt->pid, + SCpnt->state, SCpnt->owner); + for (SDpnt1 = shpnt->host_queue; SDpnt1; + SDpnt1 = SDpnt1->next) { + for (SCpnt = SDpnt1->device_queue; SCpnt; + SCpnt = SCpnt->next) + if (SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING) + SCpnt->request.rq_status = RQ_INACTIVE; + } + SDpnt->online = online_status; + printk("Device busy???\n"); + return; + } + /* + * No, this device is really free. Mark it as such, and + * continue on. + */ + SCpnt->state = SCSI_STATE_DISCONNECTING; + SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */ + } + } + } + /* Next we detach the high level drivers from the Scsi_Device structures */ + + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + if (shpnt->hostt != tpnt) { + continue; + } + for (SDpnt = shpnt->host_queue; SDpnt; + SDpnt = SDpnt->next) { + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if (sdtpnt->detach) + (*sdtpnt->detach) (SDpnt); + + /* If something still attached, punt */ + if (SDpnt->attached) { + printk("Attached usage count = %d\n", SDpnt->attached); + return; + } + } + } + + /* + * Next, kill the kernel error recovery thread for this host. + */ + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + if (shpnt->hostt == tpnt + && shpnt->hostt->use_new_eh_code + && shpnt->ehandler != NULL) { + DECLARE_MUTEX_LOCKED(sem); + + shpnt->eh_notify = &sem; + send_sig(SIGKILL, shpnt->ehandler, 1); + down(&sem); + shpnt->eh_notify = NULL; + } + } + + /* Next we free up the Scsi_Cmnd structures for this host */ + + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + if (shpnt->hostt != tpnt) { + continue; + } + for (SDpnt = shpnt->host_queue; SDpnt; + SDpnt = shpnt->host_queue) { + while (SDpnt->device_queue) { + SCpnt = SDpnt->device_queue->next; + scsi_init_free((char *) SDpnt->device_queue, sizeof(Scsi_Cmnd)); + SDpnt->device_queue = SCpnt; + } + SDpnt->has_cmdblocks = 0; + + /* Next free up the Scsi_Device structures for this host */ + shpnt->host_queue = SDpnt->next; + scsi_init_free((char *) SDpnt, sizeof(Scsi_Device)); + + } + } + + /* Next we go through and remove the instances of the individual hosts + * that were detected */ + + for (shpnt = scsi_hostlist; shpnt; shpnt = sh1) { + sh1 = shpnt->next; + if (shpnt->hostt == tpnt) { + if (shpnt->loaded_as_module) { + pcount = next_scsi_host; + /* Remove the /proc/scsi directory entry */ #if CONFIG_PROC_FS - proc_scsi_unregister(tpnt->proc_dir, - shpnt->host_no + PROC_SCSI_FILE); + proc_scsi_unregister(tpnt->proc_dir, + shpnt->host_no + PROC_SCSI_FILE); #endif - if(tpnt->release) - (*tpnt->release)(shpnt); - else { - /* This is the default case for the release function. - * It should do the right thing for most correctly - * written host adapters. - */ - if (shpnt->irq) free_irq(shpnt->irq, NULL); - if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel); - if (shpnt->io_port && shpnt->n_io_port) - release_region(shpnt->io_port, shpnt->n_io_port); - } - if(pcount == next_scsi_host) scsi_unregister(shpnt); - tpnt->present--; - } - } - } - - /* - * If there are absolutely no more hosts left, it is safe - * to completely nuke the DMA pool. The resize operation will - * do the right thing and free everything. - */ - if( !scsi_hosts ) - resize_dma_pool(); + if (tpnt->release) + (*tpnt->release) (shpnt); + else { + /* This is the default case for the release function. + * It should do the right thing for most correctly + * written host adapters. + */ + if (shpnt->irq) + free_irq(shpnt->irq, NULL); + if (shpnt->dma_channel != 0xff) + free_dma(shpnt->dma_channel); + if (shpnt->io_port && shpnt->n_io_port) + release_region(shpnt->io_port, shpnt->n_io_port); + } + if (pcount == next_scsi_host) + scsi_unregister(shpnt); + tpnt->present--; + } + } + } + + /* + * If there are absolutely no more hosts left, it is safe + * to completely nuke the DMA pool. The resize operation will + * do the right thing and free everything. + */ + if (!scsi_hosts) + resize_dma_pool(); - printk ("scsi : %d host%s.\n", next_scsi_host, - (next_scsi_host == 1) ? "" : "s"); + printk("scsi : %d host%s.\n", next_scsi_host, + (next_scsi_host == 1) ? "" : "s"); #if defined(USE_STATIC_SCSI_MEMORY) - printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n", - (scsi_memory_upper_value - scsi_memory_lower_value) / 1024, - (scsi_init_memory_start - scsi_memory_lower_value) / 1024, - (scsi_memory_upper_value - scsi_init_memory_start) / 1024); -#endif - - scsi_make_blocked_list(); - - /* There were some hosts that were loaded at boot time, so we cannot - do any more than this */ - if (tpnt->present) return; - - /* OK, this is the very last step. Remove this host adapter from the - linked list. */ - for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next) - if(SHT == tpnt) { - if(SHTp) - SHTp->next = SHT->next; - else - scsi_hosts = SHT->next; - SHT->next = NULL; - break; - } + printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n", + (scsi_memory_upper_value - scsi_memory_lower_value) / 1024, + (scsi_init_memory_start - scsi_memory_lower_value) / 1024, + (scsi_memory_upper_value - scsi_init_memory_start) / 1024); +#endif - /* Rebuild the /proc/scsi directory entries */ + scsi_make_blocked_list(); + + /* There were some hosts that were loaded at boot time, so we cannot + do any more than this */ + if (tpnt->present) + return; + + /* OK, this is the very last step. Remove this host adapter from the + linked list. */ + for (SHTp = NULL, SHT = scsi_hosts; SHT; SHTp = SHT, SHT = SHT->next) + if (SHT == tpnt) { + if (SHTp) + SHTp->next = SHT->next; + else + scsi_hosts = SHT->next; + SHT->next = NULL; + break; + } + /* Rebuild the /proc/scsi directory entries */ #if CONFIG_PROC_FS - proc_scsi_unregister(tpnt->proc_dir, tpnt->proc_dir->low_ino); + proc_scsi_unregister(tpnt->proc_dir, tpnt->proc_dir->low_ino); #endif - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; } /* * This entry point should be called by a loadable module if it is trying * add a high level scsi driver to the system. */ -static int scsi_register_device_module(struct Scsi_Device_Template * tpnt) +static int scsi_register_device_module(struct Scsi_Device_Template *tpnt) { - Scsi_Device * SDpnt; - struct Scsi_Host * shpnt; - int out_of_space = 0; - - if (tpnt->next) return 1; - - scsi_register_device(tpnt); - /* - * First scan the devices that we know about, and see if we notice them. - */ - - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - for(SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) - { - if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt); - } - } - - /* - * If any of the devices would match this driver, then perform the - * init function. - */ - if(tpnt->init && tpnt->dev_noticed) - if ((*tpnt->init)()) return 1; - - /* - * Now actually connect the devices to the new driver. - */ - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - for(SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) - { - if(tpnt->attach) (*tpnt->attach)(SDpnt); - /* - * If this driver attached to the device, and don't have any - * command blocks for this device, allocate some. - */ - if(SDpnt->attached && SDpnt->has_cmdblocks == 0) - { - SDpnt->online = TRUE; - scsi_build_commandblocks(SDpnt); - if (0 == SDpnt->has_cmdblocks) - out_of_space = 1; - } - } - } - - /* - * This does any final handling that is required. - */ - if(tpnt->finish && tpnt->nr_dev) (*tpnt->finish)(); - if (! out_of_space) - resize_dma_pool(); - MOD_INC_USE_COUNT; + Scsi_Device *SDpnt; + struct Scsi_Host *shpnt; + int out_of_space = 0; - if (out_of_space) { - scsi_unregister_device(tpnt); /* easiest way to clean up?? */ - return 1; - } - else + if (tpnt->next) + return 1; + + scsi_register_device(tpnt); + /* + * First scan the devices that we know about, and see if we notice them. + */ + + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (SDpnt = shpnt->host_queue; SDpnt; + SDpnt = SDpnt->next) { + if (tpnt->detect) + SDpnt->attached += (*tpnt->detect) (SDpnt); + } + } + + /* + * If any of the devices would match this driver, then perform the + * init function. + */ + if (tpnt->init && tpnt->dev_noticed) + if ((*tpnt->init) ()) + return 1; + + /* + * Now actually connect the devices to the new driver. + */ + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (SDpnt = shpnt->host_queue; SDpnt; + SDpnt = SDpnt->next) { + if (tpnt->attach) + (*tpnt->attach) (SDpnt); + /* + * If this driver attached to the device, and don't have any + * command blocks for this device, allocate some. + */ + if (SDpnt->attached && SDpnt->has_cmdblocks == 0) { + SDpnt->online = TRUE; + scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) + out_of_space = 1; + } + } + } + + /* + * This does any final handling that is required. + */ + if (tpnt->finish && tpnt->nr_dev) + (*tpnt->finish) (); + if (!out_of_space) + resize_dma_pool(); + MOD_INC_USE_COUNT; + + if (out_of_space) { + scsi_unregister_device(tpnt); /* easiest way to clean up?? */ + return 1; + } else + return 0; +} + +static int scsi_unregister_device(struct Scsi_Device_Template *tpnt) +{ + Scsi_Device *SDpnt; + Scsi_Cmnd *SCpnt; + struct Scsi_Host *shpnt; + struct Scsi_Device_Template *spnt; + struct Scsi_Device_Template *prev_spnt; + + /* + * If we are busy, this is not going to fly. + */ + if (GET_USE_COUNT(tpnt->module) != 0) + return 0; + + /* + * Next, detach the devices from the driver. + */ + + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (SDpnt = shpnt->host_queue; SDpnt; + SDpnt = SDpnt->next) { + if (tpnt->detach) + (*tpnt->detach) (SDpnt); + if (SDpnt->attached == 0) { + SDpnt->online = FALSE; + + /* + * Nobody is using this device any more. Free all of the + * command structures. + */ + for (SCpnt = SDpnt->device_queue; SCpnt; + SCpnt = SCpnt->next) { + if (SCpnt == SDpnt->device_queue) + SDpnt->device_queue = SCpnt->next; + scsi_init_free((char *) SCpnt, sizeof(*SCpnt)); + } + SDpnt->has_cmdblocks = 0; + } + } + } + /* + * Extract the template from the linked list. + */ + spnt = scsi_devicelist; + prev_spnt = NULL; + while (spnt != tpnt) { + prev_spnt = spnt; + spnt = spnt->next; + } + if (prev_spnt == NULL) + scsi_devicelist = tpnt->next; + else + prev_spnt->next = spnt->next; + + MOD_DEC_USE_COUNT; + /* + * Final cleanup for the driver is done in the driver sources in the + * cleanup function. + */ return 0; } -static int scsi_unregister_device(struct Scsi_Device_Template * tpnt) + +int scsi_register_module(int module_type, void *ptr) { - Scsi_Device * SDpnt; - Scsi_Cmnd * SCpnt; - struct Scsi_Host * shpnt; - struct Scsi_Device_Template * spnt; - struct Scsi_Device_Template * prev_spnt; - - /* - * If we are busy, this is not going to fly. - */ - if(GET_USE_COUNT(tpnt->module) != 0) return 0; - - /* - * Next, detach the devices from the driver. - */ - - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - for(SDpnt = shpnt->host_queue; SDpnt; - SDpnt = SDpnt->next) - { - if(tpnt->detach) (*tpnt->detach)(SDpnt); - if(SDpnt->attached == 0) - { - SDpnt->online = FALSE; - - /* - * Nobody is using this device any more. Free all of the - * command structures. - */ - for(SCpnt = SDpnt->device_queue; SCpnt; - SCpnt = SCpnt->next) - { - if(SCpnt == SDpnt->device_queue) - SDpnt->device_queue = SCpnt->next; - scsi_init_free((char *) SCpnt, sizeof(*SCpnt)); - } - SDpnt->has_cmdblocks = 0; - } - } - } - /* - * Extract the template from the linked list. - */ - spnt = scsi_devicelist; - prev_spnt = NULL; - while(spnt != tpnt) - { - prev_spnt = spnt; - spnt = spnt->next; - } - if(prev_spnt == NULL) - scsi_devicelist = tpnt->next; - else - prev_spnt->next = spnt->next; - - MOD_DEC_USE_COUNT; - /* - * Final cleanup for the driver is done in the driver sources in the - * cleanup function. - */ - return 0; -} - - -int scsi_register_module(int module_type, void * ptr) -{ - switch(module_type) - { - case MODULE_SCSI_HA: - return scsi_register_host((Scsi_Host_Template *) ptr); - - /* Load upper level device handler of some kind */ - case MODULE_SCSI_DEV: + switch (module_type) { + case MODULE_SCSI_HA: + return scsi_register_host((Scsi_Host_Template *) ptr); + + /* Load upper level device handler of some kind */ + case MODULE_SCSI_DEV: #ifdef CONFIG_KMOD - if (scsi_hosts == NULL) - request_module("scsi_hostadapter"); + if (scsi_hosts == NULL) + request_module("scsi_hostadapter"); #endif - return scsi_register_device_module((struct Scsi_Device_Template *) ptr); - /* The rest of these are not yet implemented */ - - /* Load constants.o */ - case MODULE_SCSI_CONST: - - /* Load specialized ioctl handler for some device. Intended for - * cdroms that have non-SCSI2 audio command sets. */ - case MODULE_SCSI_IOCTL: - - default: - return 1; - } + return scsi_register_device_module((struct Scsi_Device_Template *) ptr); + /* The rest of these are not yet implemented */ + + /* Load constants.o */ + case MODULE_SCSI_CONST: + + /* Load specialized ioctl handler for some device. Intended for + * cdroms that have non-SCSI2 audio command sets. */ + case MODULE_SCSI_IOCTL: + + default: + return 1; + } } -void scsi_unregister_module(int module_type, void * ptr) +void scsi_unregister_module(int module_type, void *ptr) { - switch(module_type) - { - case MODULE_SCSI_HA: - scsi_unregister_host((Scsi_Host_Template *) ptr); - break; - case MODULE_SCSI_DEV: - scsi_unregister_device((struct Scsi_Device_Template *) ptr); - break; - /* The rest of these are not yet implemented. */ - case MODULE_SCSI_CONST: - case MODULE_SCSI_IOCTL: - break; - default: - } - return; + switch (module_type) { + case MODULE_SCSI_HA: + scsi_unregister_host((Scsi_Host_Template *) ptr); + break; + case MODULE_SCSI_DEV: + scsi_unregister_device((struct Scsi_Device_Template *) ptr); + break; + /* The rest of these are not yet implemented. */ + case MODULE_SCSI_CONST: + case MODULE_SCSI_IOCTL: + break; + default: + } + return; } -#endif /* CONFIG_MODULES */ +#endif /* CONFIG_MODULES */ /* * Function: scsi_dump_status @@ -3307,183 +3164,173 @@ * * FIXME - some formatting of the output into tables would be very handy. */ -static void -scsi_dump_status(int level) +static void scsi_dump_status(int level) { #if CONFIG_PROC_FS -#if CONFIG_SCSI_LOGGING /* { */ - int i; - struct Scsi_Host * shpnt; - Scsi_Cmnd * SCpnt; - Scsi_Device * SDpnt; - printk("Dump of scsi host parameters:\n"); - i = 0; - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - printk(" %d %d %d : %d %p\n", - shpnt->host_failed, - shpnt->host_busy, - atomic_read(&shpnt->host_active), - shpnt->host_blocked, - shpnt->pending_commands); - - } - - printk("\n\n"); - printk("Dump of scsi command parameters:\n"); - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - printk("h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n"); - for(SDpnt=shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) - { - for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) - { - /* (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x */ - printk("(%3d) %2d:%1d:%2d:%2d (%6s %4ld %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n", - i++, - - SCpnt->host->host_no, - SCpnt->channel, - SCpnt->target, - SCpnt->lun, - - kdevname(SCpnt->request.rq_dev), - SCpnt->request.sector, - SCpnt->request.nr_sectors, - SCpnt->request.current_nr_sectors, - SCpnt->request.rq_status, - SCpnt->use_sg, - - SCpnt->retries, - SCpnt->allowed, - SCpnt->flags, - - SCpnt->timeout_per_command, - SCpnt->timeout, - SCpnt->internal_timeout, - - SCpnt->cmnd[0], - SCpnt->sense_buffer[2], - SCpnt->result); - } - } - } - - for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) - { - for(SDpnt=shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) - { - /* Now dump the request lists for each block device */ - printk("Dump of pending block device requests\n"); - for(i=0; irq_dev), - req->cmd, - req->sector, - req->nr_sectors, - req->current_nr_sectors); - req = req->next; - } - printk("\n"); - } - } - } - } - printk("wait_for_request = %p\n", wait_for_request); -#endif /* CONFIG_SCSI_LOGGING */ /* } */ -#endif /* CONFIG_PROC_FS */ +#if CONFIG_SCSI_LOGGING /* { */ + int i; + struct Scsi_Host *shpnt; + Scsi_Cmnd *SCpnt; + Scsi_Device *SDpnt; + printk("Dump of scsi host parameters:\n"); + i = 0; + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + printk(" %d %d %d : %d %p\n", + shpnt->host_failed, + shpnt->host_busy, + atomic_read(&shpnt->host_active), + shpnt->host_blocked, + shpnt->pending_commands); + + } + + printk("\n\n"); + printk("Dump of scsi command parameters:\n"); + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + printk("h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n"); + for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) { + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { + /* (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x */ + printk("(%3d) %2d:%1d:%2d:%2d (%6s %4ld %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n", + i++, + + SCpnt->host->host_no, + SCpnt->channel, + SCpnt->target, + SCpnt->lun, + + kdevname(SCpnt->request.rq_dev), + SCpnt->request.sector, + SCpnt->request.nr_sectors, + SCpnt->request.current_nr_sectors, + SCpnt->request.rq_status, + SCpnt->use_sg, + + SCpnt->retries, + SCpnt->allowed, + SCpnt->flags, + + SCpnt->timeout_per_command, + SCpnt->timeout, + SCpnt->internal_timeout, + + SCpnt->cmnd[0], + SCpnt->sense_buffer[2], + SCpnt->result); + } + } + } + + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) { + /* Now dump the request lists for each block device */ + printk("Dump of pending block device requests\n"); + for (i = 0; i < MAX_BLKDEV; i++) { + if (blk_dev[i].current_request) { + struct request *req; + printk("%d: ", i); + req = blk_dev[i].current_request; + while (req) { + printk("(%s %d %ld %ld %ld) ", + kdevname(req->rq_dev), + req->cmd, + req->sector, + req->nr_sectors, + req->current_nr_sectors); + req = req->next; + } + printk("\n"); + } + } + } + } + printk("wait_for_request = %p\n", wait_for_request); +#endif /* CONFIG_SCSI_LOGGING */ /* } */ +#endif /* CONFIG_PROC_FS */ } #ifdef MODULE -int init_module(void) +int init_module(void) { - unsigned long size; - int has_space = 0; + unsigned long size; + int has_space = 0; - /* - * This makes /proc/scsi visible. - */ + /* + * This makes /proc/scsi visible. + */ #if CONFIG_PROC_FS - dispatch_scsi_info_ptr = dispatch_scsi_info; + dispatch_scsi_info_ptr = dispatch_scsi_info; #endif - scsi_loadable_module_flag = 1; + scsi_loadable_module_flag = 1; - /* Register the /proc/scsi/scsi entry */ + /* Register the /proc/scsi/scsi entry */ #if CONFIG_PROC_FS - proc_scsi_register(0, &proc_scsi_scsi); + proc_scsi_register(0, &proc_scsi_scsi); #endif - dma_sectors = PAGE_SIZE / SECTOR_SIZE; - scsi_dma_free_sectors= dma_sectors; - /* - * Set up a minimal DMA buffer list - this will be used during scan_scsis - * in some cases. - */ - - /* One bit per sector to indicate free/busy */ - size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap); - dma_malloc_freelist = (FreeSectorBitmap *) - scsi_init_malloc(size, GFP_ATOMIC); - if (dma_malloc_freelist) { - /* One pointer per page for the page list */ - dma_malloc_pages = (unsigned char **)scsi_init_malloc( - (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages), - GFP_ATOMIC); - if (dma_malloc_pages) { - dma_malloc_pages[0] = (unsigned char *) - scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); - if (dma_malloc_pages[0]) - has_space = 1; - } - } - if (! has_space) { + dma_sectors = PAGE_SIZE / SECTOR_SIZE; + scsi_dma_free_sectors = dma_sectors; + /* + * Set up a minimal DMA buffer list - this will be used during scan_scsis + * in some cases. + */ + + /* One bit per sector to indicate free/busy */ + size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap); + dma_malloc_freelist = (FreeSectorBitmap *) + scsi_init_malloc(size, GFP_ATOMIC); if (dma_malloc_freelist) { - scsi_init_free((char *)dma_malloc_freelist, size); - if (dma_malloc_pages) - scsi_init_free((char *)dma_malloc_pages, - (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages)); + /* One pointer per page for the page list */ + dma_malloc_pages = (unsigned char **) scsi_init_malloc( + (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages), + GFP_ATOMIC); + if (dma_malloc_pages) { + dma_malloc_pages[0] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + if (dma_malloc_pages[0]) + has_space = 1; + } } - printk("scsi::init_module: failed, out of memory\n"); - return 1; - } - - /* - * This is where the processing takes place for most everything - * when commands are completed. - */ - init_bh(SCSI_BH, scsi_bottom_half_handler); + if (!has_space) { + if (dma_malloc_freelist) { + scsi_init_free((char *) dma_malloc_freelist, size); + if (dma_malloc_pages) + scsi_init_free((char *) dma_malloc_pages, + (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages)); + } + printk("scsi::init_module: failed, out of memory\n"); + return 1; + } + /* + * This is where the processing takes place for most everything + * when commands are completed. + */ + init_bh(SCSI_BH, scsi_bottom_half_handler); - return 0; + return 0; } -void cleanup_module( void) +void cleanup_module(void) { - remove_bh(SCSI_BH); + remove_bh(SCSI_BH); #if CONFIG_PROC_FS - proc_scsi_unregister(0, PROC_SCSI_SCSI); + proc_scsi_unregister(0, PROC_SCSI_SCSI); - /* No, we're not here anymore. Don't show the /proc/scsi files. */ - dispatch_scsi_info_ptr = 0L; + /* No, we're not here anymore. Don't show the /proc/scsi files. */ + dispatch_scsi_info_ptr = 0L; #endif - /* - * Free up the DMA pool. - */ - resize_dma_pool(); + /* + * Free up the DMA pool. + */ + resize_dma_pool(); } -#endif /* MODULE */ + +#endif /* MODULE */ /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.3.16/linux/drivers/scsi/scsi.h Tue Aug 31 17:29:14 1999 +++ linux/drivers/scsi/scsi.h Tue Sep 7 11:50:56 1999 @@ -15,7 +15,7 @@ #ifndef _SCSI_H #define _SCSI_H -#include /* for CONFIG_SCSI_LOGGING */ +#include /* for CONFIG_SCSI_LOGGING */ /* * Some of the public constants are being moved to this file. @@ -33,19 +33,19 @@ * Some defs, in case these are not defined elsewhere. */ #ifndef TRUE -# define TRUE 1 +#define TRUE 1 #endif #ifndef FALSE -# define FALSE 0 +#define FALSE 0 #endif #define MAX_SCSI_DEVICE_CODE 14 extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; #ifdef DEBUG - #define SCSI_TIMEOUT (5*HZ) +#define SCSI_TIMEOUT (5*HZ) #else - #define SCSI_TIMEOUT (2*HZ) +#define SCSI_TIMEOUT (2*HZ) #endif /* @@ -104,9 +104,9 @@ #define IDENTIFY_BASE 0x80 #define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\ ((can_disconnect) ? 0x40 : 0) |\ - ((lun) & 0x07)) + ((lun) & 0x07)) + - /* * This defines the scsi logging feature. It is a means by which the * user can select how much information they get about various goings on, @@ -205,7 +205,7 @@ SCSI_CHECK_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL,CMD); #define SCSI_LOG_IOCTL(LEVEL,CMD) \ SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD); - + #define SCSI_SET_ERROR_RECOVERY_LOGGING(LEVEL) \ SCSI_SET_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL); @@ -227,7 +227,7 @@ SCSI_SET_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL); #define SCSI_SET_IOCTL_LOGGING(LEVEL) \ SCSI_SET_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL); - + /* * the return of the status word will be in the following format : * The low byte is the status returned by the SCSI command, @@ -248,19 +248,19 @@ */ -#define DID_OK 0x00 /* NO error */ -#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ -#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ -#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ -#define DID_BAD_TARGET 0x04 /* BAD target. */ -#define DID_ABORT 0x05 /* Told to abort for some other reason */ -#define DID_PARITY 0x06 /* Parity error */ -#define DID_ERROR 0x07 /* Internal error */ -#define DID_RESET 0x08 /* Reset by somebody. */ -#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ -#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ -#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ -#define DRIVER_OK 0x00 /* Driver status */ +#define DID_OK 0x00 /* NO error */ +#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ +#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ +#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ +#define DID_BAD_TARGET 0x04 /* BAD target. */ +#define DID_ABORT 0x05 /* Told to abort for some other reason */ +#define DID_PARITY 0x06 /* Parity error */ +#define DID_ERROR 0x07 /* Internal error */ +#define DID_RESET 0x08 /* Reset by somebody. */ +#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ +#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ +#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ +#define DRIVER_OK 0x00 /* Driver status */ /* * These indicate the error that occurred, and what is available. @@ -269,7 +269,7 @@ #define DRIVER_BUSY 0x01 #define DRIVER_SOFT 0x02 #define DRIVER_MEDIA 0x03 -#define DRIVER_ERROR 0x04 +#define DRIVER_ERROR 0x04 #define DRIVER_INVALID 0x05 #define DRIVER_TIMEOUT 0x06 @@ -277,7 +277,7 @@ #define DRIVER_SENSE 0x08 #define SUGGEST_RETRY 0x10 -#define SUGGEST_ABORT 0x20 +#define SUGGEST_ABORT 0x20 #define SUGGEST_REMAP 0x30 #define SUGGEST_DIE 0x40 #define SUGGEST_SENSE 0x80 @@ -339,7 +339,7 @@ * Add some typedefs so that we can prototyope a bunch of the functions. */ typedef struct scsi_device Scsi_Device; -typedef struct scsi_cmnd Scsi_Cmnd; +typedef struct scsi_cmnd Scsi_Cmnd; /* * Here is where we prototype most of the mid-layer. @@ -347,18 +347,18 @@ /* * Initializes all SCSI devices. This scans all scsi busses. - */ + */ -extern int scsi_dev_init (void); +extern int scsi_dev_init(void); -void * scsi_malloc(unsigned int); -int scsi_free(void *, unsigned int); -extern unsigned int scsi_logging_level; /* What do we log? */ -extern unsigned int scsi_dma_free_sectors; /* How much room do we have left */ -extern unsigned int scsi_need_isa_buffer; /* True if some devices need indirection - * buffers */ +void *scsi_malloc(unsigned int); +int scsi_free(void *, unsigned int); +extern unsigned int scsi_logging_level; /* What do we log? */ +extern unsigned int scsi_dma_free_sectors; /* How much room do we have left */ +extern unsigned int scsi_need_isa_buffer; /* True if some devices need indirection + * buffers */ extern void scsi_make_blocked_list(void); extern volatile int in_scan_scsis; extern const unsigned char scsi_command_size[8]; @@ -366,16 +366,16 @@ /* * These are the error handling functions defined in scsi_error.c */ -extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout, - void (*complete)(Scsi_Cmnd *)); -extern void scsi_done (Scsi_Cmnd *SCpnt); -extern int scsi_delete_timer(Scsi_Cmnd * SCset); -extern void scsi_error_handler(void * host); -extern int scsi_retry_command(Scsi_Cmnd *); +extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout, + void (*complete) (Scsi_Cmnd *)); +extern void scsi_done(Scsi_Cmnd * SCpnt); +extern int scsi_delete_timer(Scsi_Cmnd * SCset); +extern void scsi_error_handler(void *host); +extern int scsi_retry_command(Scsi_Cmnd *); extern void scsi_finish_command(Scsi_Cmnd *); -extern int scsi_sense_valid(Scsi_Cmnd *); -extern int scsi_decide_disposition (Scsi_Cmnd * SCpnt); -extern int scsi_block_when_processing_errors(Scsi_Device *); +extern int scsi_sense_valid(Scsi_Cmnd *); +extern int scsi_decide_disposition(Scsi_Cmnd * SCpnt); +extern int scsi_block_when_processing_errors(Scsi_Device *); extern void scsi_sleep(int); /* @@ -384,15 +384,15 @@ * DID_ABORT is returned in the hostbyte. */ -extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd , - void *buffer, unsigned bufflen, - void (*done)(struct scsi_cmnd *), - int timeout, int retries); +extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd, + void *buffer, unsigned bufflen, + void (*done) (struct scsi_cmnd *), + int timeout, int retries); -extern Scsi_Cmnd * scsi_allocate_device(struct request **, Scsi_Device *, int); +extern Scsi_Cmnd *scsi_allocate_device(struct request **, Scsi_Device *, int); -extern Scsi_Cmnd * scsi_request_queueable(struct request *, Scsi_Device *); +extern Scsi_Cmnd *scsi_request_queueable(struct request *, Scsi_Device *); extern void scsi_release_command(Scsi_Cmnd *); @@ -412,62 +412,62 @@ struct scsi_device { /* private: */ - /* - * This information is private to the scsi mid-layer. Wrapping it in a - * struct private is a way of marking it in a sort of C++ type of way. - */ - struct scsi_device * next; /* Used for linked list */ - struct scsi_device * prev; /* Used for linked list */ - wait_queue_head_t device_wait;/* Used to wait if - device is busy */ - struct Scsi_Host * host; - volatile unsigned short device_busy; /* commands actually active on low-level */ - void (* scsi_request_fn)(void); /* Used to jumpstart things after an - * ioctl */ - Scsi_Cmnd * device_queue; /* queue of SCSI Command structures */ + /* + * This information is private to the scsi mid-layer. Wrapping it in a + * struct private is a way of marking it in a sort of C++ type of way. + */ + struct scsi_device *next; /* Used for linked list */ + struct scsi_device *prev; /* Used for linked list */ + wait_queue_head_t device_wait; /* Used to wait if + device is busy */ + struct Scsi_Host *host; + volatile unsigned short device_busy; /* commands actually active on low-level */ + void (*scsi_request_fn) (void); /* Used to jumpstart things after an + * ioctl */ + Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */ /* public: */ - unsigned char id, lun, channel; + unsigned char id, lun, channel; - unsigned int manufacturer; /* Manufacturer of device, for using - * vendor-specific cmd's */ - int attached; /* # of high level drivers attached to - * this */ - int access_count; /* Count of open channels/mounts */ - - void *hostdata; /* available to low-level driver */ - char type; - char scsi_level; - char vendor[8], model[16], rev[4]; - unsigned char current_tag; /* current tag */ - unsigned char sync_min_period; /* Not less than this period */ - unsigned char sync_max_offset; /* Not greater than this offset */ - unsigned char queue_depth; /* How deep a queue to use */ - - unsigned online:1; - unsigned writeable:1; - unsigned removable:1; - unsigned random:1; - unsigned has_cmdblocks:1; - unsigned changed:1; /* Data invalid due to media change */ - unsigned busy:1; /* Used to prevent races */ - unsigned lockable:1; /* Able to prevent media removal */ - unsigned borken:1; /* Tell the Seagate driver to be - * painfully slow on this device */ - unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ - unsigned tagged_queue:1; /* SCSI-II tagged queuing enabled */ - unsigned disconnect:1; /* can disconnect */ - unsigned soft_reset:1; /* Uses soft reset option */ - unsigned sync:1; /* Negotiate for sync transfers */ - unsigned wide:1; /* Negotiate for WIDE transfers */ - unsigned single_lun:1; /* Indicates we should only allow I/O to - * one of the luns for the device at a - * time. */ - unsigned was_reset:1; /* There was a bus reset on the bus for - * this device */ - unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN - * because we did a bus reset. */ - unsigned device_blocked:1; /* Device returned QUEUE_FULL. */ + unsigned int manufacturer; /* Manufacturer of device, for using + * vendor-specific cmd's */ + int attached; /* # of high level drivers attached to + * this */ + int access_count; /* Count of open channels/mounts */ + + void *hostdata; /* available to low-level driver */ + char type; + char scsi_level; + char vendor[8], model[16], rev[4]; + unsigned char current_tag; /* current tag */ + unsigned char sync_min_period; /* Not less than this period */ + unsigned char sync_max_offset; /* Not greater than this offset */ + unsigned char queue_depth; /* How deep a queue to use */ + + unsigned online:1; + unsigned writeable:1; + unsigned removable:1; + unsigned random:1; + unsigned has_cmdblocks:1; + unsigned changed:1; /* Data invalid due to media change */ + unsigned busy:1; /* Used to prevent races */ + unsigned lockable:1; /* Able to prevent media removal */ + unsigned borken:1; /* Tell the Seagate driver to be + * painfully slow on this device */ + unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ + unsigned tagged_queue:1; /* SCSI-II tagged queuing enabled */ + unsigned disconnect:1; /* can disconnect */ + unsigned soft_reset:1; /* Uses soft reset option */ + unsigned sync:1; /* Negotiate for sync transfers */ + unsigned wide:1; /* Negotiate for WIDE transfers */ + unsigned single_lun:1; /* Indicates we should only allow I/O to + * one of the luns for the device at a + * time. */ + unsigned was_reset:1; /* There was a bus reset on the bus for + * this device */ + unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN + * because we did a bus reset. */ + unsigned device_blocked:1; /* Device returned QUEUE_FULL. */ }; @@ -476,147 +476,147 @@ * with low level drivers that support multiple outstanding commands. */ typedef struct scsi_pointer { - char * ptr; /* data pointer */ - int this_residual; /* left in this buffer */ - struct scatterlist *buffer; /* which buffer */ - int buffers_residual; /* how many buffers left */ - - volatile int Status; - volatile int Message; - volatile int have_data_in; - volatile int sent_command; - volatile int phase; + char *ptr; /* data pointer */ + int this_residual; /* left in this buffer */ + struct scatterlist *buffer; /* which buffer */ + int buffers_residual; /* how many buffers left */ + + volatile int Status; + volatile int Message; + volatile int have_data_in; + volatile int sent_command; + volatile int phase; } Scsi_Pointer; struct scsi_cmnd { /* private: */ - /* - * This information is private to the scsi mid-layer. Wrapping it in a - * struct private is a way of marking it in a sort of C++ type of way. - */ - struct Scsi_Host * host; - unsigned short state; - unsigned short owner; - Scsi_Device * device; - struct scsi_cmnd * next; - struct scsi_cmnd * reset_chain; - - int eh_state; /* Used for state tracking in error handlr */ - void (*done)(struct scsi_cmnd *); /* Mid-level done function */ - /* - A SCSI Command is assigned a nonzero serial_number when internal_cmnd - passes it to the driver's queue command function. The serial_number - is cleared when scsi_done is entered indicating that the command has - been completed. If a timeout occurs, the serial number at the moment - of timeout is copied into serial_number_at_timeout. By subsequently - comparing the serial_number and serial_number_at_timeout fields - during abort or reset processing, we can detect whether the command - has already completed. This also detects cases where the command has - completed and the SCSI Command structure has already being reused - for another command, so that we can avoid incorrectly aborting or - resetting the new command. - */ - - unsigned long serial_number; - unsigned long serial_number_at_timeout; - - int retries; - int allowed; - int timeout_per_command; - int timeout_total; - int timeout; - - /* - * We handle the timeout differently if it happens when a reset, - * abort, etc are in process. - */ - unsigned volatile char internal_timeout; - struct scsi_cmnd * bh_next; /* To enumerate the commands waiting - to be processed. */ - + /* + * This information is private to the scsi mid-layer. Wrapping it in a + * struct private is a way of marking it in a sort of C++ type of way. + */ + struct Scsi_Host *host; + unsigned short state; + unsigned short owner; + Scsi_Device *device; + struct scsi_cmnd *next; + struct scsi_cmnd *reset_chain; + + int eh_state; /* Used for state tracking in error handlr */ + void (*done) (struct scsi_cmnd *); /* Mid-level done function */ + /* + A SCSI Command is assigned a nonzero serial_number when internal_cmnd + passes it to the driver's queue command function. The serial_number + is cleared when scsi_done is entered indicating that the command has + been completed. If a timeout occurs, the serial number at the moment + of timeout is copied into serial_number_at_timeout. By subsequently + comparing the serial_number and serial_number_at_timeout fields + during abort or reset processing, we can detect whether the command + has already completed. This also detects cases where the command has + completed and the SCSI Command structure has already being reused + for another command, so that we can avoid incorrectly aborting or + resetting the new command. + */ + + unsigned long serial_number; + unsigned long serial_number_at_timeout; + + int retries; + int allowed; + int timeout_per_command; + int timeout_total; + int timeout; + + /* + * We handle the timeout differently if it happens when a reset, + * abort, etc are in process. + */ + unsigned volatile char internal_timeout; + struct scsi_cmnd *bh_next; /* To enumerate the commands waiting + to be processed. */ + /* public: */ - unsigned char target; - unsigned char lun; - unsigned char channel; - unsigned char cmd_len; - unsigned char old_cmd_len; - - /* These elements define the operation we are about to perform */ - unsigned char cmnd[12]; - unsigned request_bufflen; /* Actual request size */ - - struct timer_list eh_timeout; /* Used to time out the command. */ - void * request_buffer; /* Actual requested buffer */ - - /* These elements define the operation we ultimately want to perform */ - unsigned char data_cmnd[12]; - unsigned short old_use_sg; /* We save use_sg here when requesting - * sense info */ - unsigned short use_sg; /* Number of pieces of scatter-gather */ - unsigned short sglist_len; /* size of malloc'd scatter-gather list */ - unsigned short abort_reason; /* If the mid-level code requests an - * abort, this is the reason. */ - unsigned bufflen; /* Size of data buffer */ - void * buffer; /* Data buffer */ - - unsigned underflow; /* Return error if less than - this amount is transfered */ - - unsigned transfersize; /* How much we are guaranteed to - transfer with each SCSI transfer - (ie, between disconnect / - reconnects. Probably == sector - size */ - - - struct request request; /* A copy of the command we are - working on */ - - unsigned char sense_buffer[16]; /* Sense for this command, - needed */ - - unsigned flags; - - /* - * These two flags are used to track commands that are in the - * mid-level queue. The idea is that a command can be there for - * one of two reasons - either the host is busy or the device is - * busy. Thus when a command on the host finishes, we only try - * and requeue commands that we might expect to be queueable. - */ - unsigned host_wait:1; - unsigned device_wait:1; - - /* These variables are for the cdrom only. Once we have variable size - * buffers in the buffer cache, they will go away. */ - int this_count; - /* End of special cdrom variables */ - - /* Low-level done function - can be used by low-level driver to point - * to completion function. Not used by mid/upper level code. */ - void (*scsi_done)(struct scsi_cmnd *); - - /* - * The following fields can be written to by the host specific code. - * Everything else should be left alone. - */ - - Scsi_Pointer SCp; /* Scratchpad used by some host adapters */ - - unsigned char * host_scribble; /* The host adapter is allowed to - * call scsi_malloc and get some memory - * and hang it here. The host adapter - * is also expected to call scsi_free - * to release this memory. (The memory - * obtained by scsi_malloc is guaranteed - * to be at an address < 16Mb). */ - - int result; /* Status code from lower level driver */ - - unsigned char tag; /* SCSI-II queued command tag */ - unsigned long pid; /* Process ID, starts at 0 */ + unsigned char target; + unsigned char lun; + unsigned char channel; + unsigned char cmd_len; + unsigned char old_cmd_len; + + /* These elements define the operation we are about to perform */ + unsigned char cmnd[12]; + unsigned request_bufflen; /* Actual request size */ + + struct timer_list eh_timeout; /* Used to time out the command. */ + void *request_buffer; /* Actual requested buffer */ + + /* These elements define the operation we ultimately want to perform */ + unsigned char data_cmnd[12]; + unsigned short old_use_sg; /* We save use_sg here when requesting + * sense info */ + unsigned short use_sg; /* Number of pieces of scatter-gather */ + unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + unsigned short abort_reason; /* If the mid-level code requests an + * abort, this is the reason. */ + unsigned bufflen; /* Size of data buffer */ + void *buffer; /* Data buffer */ + + unsigned underflow; /* Return error if less than + this amount is transfered */ + + unsigned transfersize; /* How much we are guaranteed to + transfer with each SCSI transfer + (ie, between disconnect / + reconnects. Probably == sector + size */ + + + struct request request; /* A copy of the command we are + working on */ + + unsigned char sense_buffer[16]; /* Sense for this command, + needed */ + + unsigned flags; + + /* + * These two flags are used to track commands that are in the + * mid-level queue. The idea is that a command can be there for + * one of two reasons - either the host is busy or the device is + * busy. Thus when a command on the host finishes, we only try + * and requeue commands that we might expect to be queueable. + */ + unsigned host_wait:1; + unsigned device_wait:1; + + /* These variables are for the cdrom only. Once we have variable size + * buffers in the buffer cache, they will go away. */ + int this_count; + /* End of special cdrom variables */ + + /* Low-level done function - can be used by low-level driver to point + * to completion function. Not used by mid/upper level code. */ + void (*scsi_done) (struct scsi_cmnd *); + + /* + * The following fields can be written to by the host specific code. + * Everything else should be left alone. + */ + + Scsi_Pointer SCp; /* Scratchpad used by some host adapters */ + + unsigned char *host_scribble; /* The host adapter is allowed to + * call scsi_malloc and get some memory + * and hang it here. The host adapter + * is also expected to call scsi_free + * to release this memory. (The memory + * obtained by scsi_malloc is guaranteed + * to be at an address < 16Mb). */ + + int result; /* Status code from lower level driver */ + + unsigned char tag; /* SCSI-II queued command tag */ + unsigned long pid; /* Process ID, starts at 0 */ }; @@ -627,63 +627,61 @@ #define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 extern int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason); -extern int scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device); +extern int scsi_mlqueue_finish(struct Scsi_Host *host, Scsi_Device * device); #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR) #include "hosts.h" -static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors) +static Scsi_Cmnd *end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors) { - struct request * req; - struct buffer_head * bh; - - req = &SCpnt->request; - req->errors = 0; - if (!uptodate) { - printk(DEVICE_NAME " I/O error: dev %s, sector %lu\n", - kdevname(req->rq_dev), req->sector); - } - - do { - if ((bh = req->bh) != NULL) { - req->bh = bh->b_reqnext; - req->nr_sectors -= bh->b_size >> 9; - req->sector += bh->b_size >> 9; - bh->b_reqnext = NULL; - bh->b_end_io(bh, uptodate); - sectors -= bh->b_size >> 9; - if ((bh = req->bh) != NULL) { - req->current_nr_sectors = bh->b_size >> 9; - if (req->nr_sectors < req->current_nr_sectors) { - req->nr_sectors = req->current_nr_sectors; - printk("end_scsi_request: buffer-list destroyed\n"); + struct request *req; + struct buffer_head *bh; + + req = &SCpnt->request; + req->errors = 0; + if (!uptodate) { + printk(DEVICE_NAME " I/O error: dev %s, sector %lu\n", + kdevname(req->rq_dev), req->sector); + } + do { + if ((bh = req->bh) != NULL) { + req->bh = bh->b_reqnext; + req->nr_sectors -= bh->b_size >> 9; + req->sector += bh->b_size >> 9; + bh->b_reqnext = NULL; + bh->b_end_io(bh, uptodate); + sectors -= bh->b_size >> 9; + if ((bh = req->bh) != NULL) { + req->current_nr_sectors = bh->b_size >> 9; + if (req->nr_sectors < req->current_nr_sectors) { + req->nr_sectors = req->current_nr_sectors; + printk("end_scsi_request: buffer-list destroyed\n"); + } + } } - } + } while (sectors && bh); + if (req->bh) { + req->buffer = bh->b_data; + return SCpnt; + } + DEVICE_OFF(req->rq_dev); + if (req->sem != NULL) { + up(req->sem); + } + add_blkdev_randomness(MAJOR(req->rq_dev)); + + if (SCpnt->host->block) { + struct Scsi_Host *next; + + for (next = SCpnt->host->block; next != SCpnt->host; + next = next->block) + wake_up(&next->host_wait); } - } while(sectors && bh); - if (req->bh){ - req->buffer = bh->b_data; - return SCpnt; - } - DEVICE_OFF(req->rq_dev); - if (req->sem != NULL) { - up(req->sem); - } - add_blkdev_randomness(MAJOR(req->rq_dev)); - - if (SCpnt->host->block) { - struct Scsi_Host * next; - - for (next = SCpnt->host->block; next != SCpnt->host; - next = next->block) - wake_up(&next->host_wait); - } - - wake_up(&wait_for_request); - wake_up(&SCpnt->device->device_wait); - scsi_release_command(SCpnt); - return NULL; + wake_up(&wait_for_request); + wake_up(&SCpnt->device->device_wait); + scsi_release_command(SCpnt); + return NULL; } diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c --- v2.3.16/linux/drivers/scsi/scsi_debug.c Mon Jul 5 20:35:18 1999 +++ linux/drivers/scsi/scsi_debug.c Sat Sep 4 10:48:46 1999 @@ -30,9 +30,10 @@ #include -struct proc_dir_entry proc_scsi_scsi_debug = { - PROC_SCSI_SCSI_DEBUG, 10, "scsi_debug", - S_IFDIR | S_IRUGO | S_IXUGO, 2 +struct proc_dir_entry proc_scsi_scsi_debug = +{ + PROC_SCSI_SCSI_DEBUG, 10, "scsi_debug", + S_IFDIR | S_IRUGO | S_IXUGO, 2 }; @@ -55,7 +56,7 @@ #define CLEAR /* Number of real scsi disks that will be detected ahead of time */ -static int NR_REAL=-1; +static int NR_REAL = -1; #define NR_BLK_DEV 12 #ifndef MAJOR_NR @@ -67,7 +68,8 @@ #define DISK_SPEED 10 #define CAPACITY (0x80000) -static int starts[] = {N_HEAD, N_HEAD * N_SECTOR, 50000, CAPACITY, 0}; +static int starts[] = +{N_HEAD, N_HEAD * N_SECTOR, 50000, CAPACITY, 0}; static int npart = 0; #include "scsi_debug.h" @@ -78,8 +80,8 @@ #endif #ifdef SPEEDY -#define VERIFY1_DEBUG(RW) -#define VERIFY_DEBUG(RW) +#define VERIFY1_DEBUG(RW) +#define VERIFY_DEBUG(RW) #else #define VERIFY1_DEBUG(RW) \ @@ -115,15 +117,15 @@ }; #endif -typedef void (*done_fct_t)(Scsi_Cmnd *); +typedef void (*done_fct_t) (Scsi_Cmnd *); -static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = {NULL, }; +static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = {NULL,}; static void scsi_debug_intr_handle(unsigned long); static struct timer_list timeout[SCSI_DEBUG_MAILBOXES]; -Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,}; +Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] = {NULL,}; static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,}; /* @@ -133,379 +135,384 @@ static char sense_buffer[128] = {0,}; -static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){ - int i; +static void scsi_dump(Scsi_Cmnd * SCpnt, int flag) +{ + int i; #if 0 - unsigned char * pnt; + unsigned char *pnt; #endif - unsigned int * lpnt; - struct scatterlist * sgpnt = NULL; - printk("use_sg: %d",SCpnt->use_sg); - if (SCpnt->use_sg){ - sgpnt = (struct scatterlist *) SCpnt->buffer; - for(i=0; iuse_sg; i++) { - lpnt = (int *) sgpnt[i].alt_address; - printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); - if (lpnt) printk(" (Alt %x) ",lpnt[15]); + unsigned int *lpnt; + struct scatterlist *sgpnt = NULL; + printk("use_sg: %d", SCpnt->use_sg); + if (SCpnt->use_sg) { + sgpnt = (struct scatterlist *) SCpnt->buffer; + for (i = 0; i < SCpnt->use_sg; i++) { + lpnt = (int *) sgpnt[i].alt_address; + printk(":%p %p %d\n", sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); + if (lpnt) + printk(" (Alt %x) ", lpnt[15]); + }; + } else { + printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer, + SCpnt->bufflen); + lpnt = (int *) SCpnt->request.buffer; + if (lpnt) + printk(" (Alt %x) ", lpnt[15]); + }; + lpnt = (unsigned int *) SCpnt; + for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { + if ((i & 7) == 0) + printk("\n"); + printk("%x ", *lpnt++); + }; + printk("\n"); + if (flag == 0) + return; + lpnt = (unsigned int *) sgpnt[0].alt_address; + for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { + if ((i & 7) == 0) + printk("\n"); + printk("%x ", *lpnt++); }; - } else { - printk("nosg: %p %p %d\n",SCpnt->request.buffer, SCpnt->buffer, - SCpnt->bufflen); - lpnt = (int *) SCpnt->request.buffer; - if (lpnt) printk(" (Alt %x) ",lpnt[15]); - }; - lpnt = (unsigned int *) SCpnt; - for (i=0;icmnd; - struct partition * p; - int block; - struct buffer_head * bh = NULL; - unsigned char * buff; - int nbytes, sgcount; - int scsi_debug_errsts; - struct scatterlist * sgpnt; - int target = SCpnt->target; - int bufflen = SCpnt->request_bufflen; - unsigned long flags; - int i; - sgcount = 0; - sgpnt = NULL; - - /* - * If we are being notified of the mid-level reposessing a command due to timeout, - * just return. - */ - if( done == NULL ) - { - return 0; - } - - DEB(if (target >= NR_FAKE_DISKS) - { - SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0; - }); - - buff = (unsigned char *) SCpnt->request_buffer; - - if(target>=NR_FAKE_DISKS || SCpnt->lun != 0) - { - SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); - return 0; - } - - if( SCrst[target] != 0 && !scsi_debug_lockup ) - { - SCrst[target] = 0; - memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); - SCpnt->sense_buffer[0] = 0x70; - SCpnt->sense_buffer[2] = UNIT_ATTENTION; - SCpnt->result = (CHECK_CONDITION << 1); - done(SCpnt); - } - switch(*cmd){ - case REQUEST_SENSE: - SCSI_LOG_LLQUEUE(3,printk("Request sense...\n")); + unchar *cmd = (unchar *) SCpnt->cmnd; + struct partition *p; + int block; + struct buffer_head *bh = NULL; + unsigned char *buff; + int nbytes, sgcount; + int scsi_debug_errsts; + struct scatterlist *sgpnt; + int target = SCpnt->target; + int bufflen = SCpnt->request_bufflen; + unsigned long flags; + int i; + sgcount = 0; + sgpnt = NULL; + + /* + * If we are being notified of the mid-level reposessing a command due to timeout, + * just return. + */ + if (done == NULL) { + return 0; + } + DEB(if (target >= NR_FAKE_DISKS) { + SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0; + } + ); + + buff = (unsigned char *) SCpnt->request_buffer; + + if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) { + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + } + if (SCrst[target] != 0 && !scsi_debug_lockup) { + SCrst[target] = 0; + memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); + SCpnt->sense_buffer[0] = 0x70; + SCpnt->sense_buffer[2] = UNIT_ATTENTION; + SCpnt->result = (CHECK_CONDITION << 1); + done(SCpnt); + } + switch (*cmd) { + case REQUEST_SENSE: + SCSI_LOG_LLQUEUE(3, printk("Request sense...\n")); #ifndef DEBUG - { - int i; - printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen); - for(i=0;i<12;i++) printk("%d ",sense_buffer[i]); - printk("\n"); - }; + { + int i; + printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen); + for (i = 0; i < 12; i++) + printk("%d ", sense_buffer[i]); + printk("\n"); + }; #endif - memset(buff, 0, bufflen); - memcpy(buff, sense_buffer, bufflen); - memset(sense_buffer, 0, sizeof(sense_buffer)); - SCpnt->result = 0; - done(SCpnt); - return 0; - case ALLOW_MEDIUM_REMOVAL: - if(cmd[4]) - { - SCSI_LOG_LLQUEUE(2,printk("Medium removal inhibited...")); - } - else - { - SCSI_LOG_LLQUEUE(2,printk("Medium removal enabled...")); - } - scsi_debug_errsts = 0; - break; - case INQUIRY: - SCSI_LOG_LLQUEUE(3,printk("Inquiry...(%p %d)\n", buff, bufflen)); - memset(buff, 0, bufflen); - buff[0] = TYPE_DISK; - buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ - buff[2] = 1; - buff[4] = 33 - 5; - memcpy(&buff[8],"Foo Inc",7); - memcpy(&buff[16],"XYZZY",5); - memcpy(&buff[32],"1",1); - scsi_debug_errsts = 0; - break; - case TEST_UNIT_READY: - SCSI_LOG_LLQUEUE(3,printk("Test unit ready(%p %d)\n", buff, bufflen)); - if (buff) - memset(buff, 0, bufflen); - scsi_debug_errsts = 0; - break; - case READ_CAPACITY: - SCSI_LOG_LLQUEUE(3,printk("Read Capacity\n")); - if(NR_REAL < 0) NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f; - memset(buff, 0, bufflen); - buff[0] = (CAPACITY >> 24); - buff[1] = (CAPACITY >> 16) & 0xff; - buff[2] = (CAPACITY >> 8) & 0xff; - buff[3] = CAPACITY & 0xff; - buff[6] = 2; /* 512 byte sectors */ - scsi_debug_errsts = 0; - break; - case READ_10: - case READ_6: + memset(buff, 0, bufflen); + memcpy(buff, sense_buffer, bufflen); + memset(sense_buffer, 0, sizeof(sense_buffer)); + SCpnt->result = 0; + done(SCpnt); + return 0; + case ALLOW_MEDIUM_REMOVAL: + if (cmd[4]) { + SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited...")); + } else { + SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled...")); + } + scsi_debug_errsts = 0; + break; + case INQUIRY: + SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen)); + memset(buff, 0, bufflen); + buff[0] = TYPE_DISK; + buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ + buff[2] = 1; + buff[4] = 33 - 5; + memcpy(&buff[8], "Foo Inc", 7); + memcpy(&buff[16], "XYZZY", 5); + memcpy(&buff[32], "1", 1); + scsi_debug_errsts = 0; + break; + case TEST_UNIT_READY: + SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen)); + if (buff) + memset(buff, 0, bufflen); + scsi_debug_errsts = 0; + break; + case READ_CAPACITY: + SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n")); + if (NR_REAL < 0) + NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f; + memset(buff, 0, bufflen); + buff[0] = (CAPACITY >> 24); + buff[1] = (CAPACITY >> 16) & 0xff; + buff[2] = (CAPACITY >> 8) & 0xff; + buff[3] = CAPACITY & 0xff; + buff[6] = 2; /* 512 byte sectors */ + scsi_debug_errsts = 0; + break; + case READ_10: + case READ_6: #ifdef DEBUG - printk("Read..."); + printk("Read..."); #endif - if ((*cmd) == READ_10) - block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); - else - block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - VERIFY_DEBUG(READ); + if ((*cmd) == READ_10) + block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); + else + block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); + VERIFY_DEBUG(READ); #if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE) - { - int delay = SCSI_SETUP_LATENCY; - - delay += SCpnt->request.nr_sectors * SCSI_DATARATE; - if(delay) usleep(delay); - }; + { + int delay = SCSI_SETUP_LATENCY; + + delay += SCpnt->request.nr_sectors * SCSI_DATARATE; + if (delay) + usleep(delay); + }; #endif - + #ifdef DEBUG - printk("(r%d)",SCpnt->request.nr_sectors); + printk("(r%d)", SCpnt->request.nr_sectors); #endif - nbytes = bufflen; - if(SCpnt->use_sg){ - sgcount = 0; - sgpnt = (struct scatterlist *) buff; - buff = sgpnt[sgcount].address; - bufflen = sgpnt[sgcount].length; - bh = SCpnt->request.bh; - }; - scsi_debug_errsts = 0; - do{ - VERIFY1_DEBUG(READ); - /* For the speedy test, we do not even want to fill the buffer with anything */ -#ifdef CLEAR - memset(buff, 0, bufflen); -#endif - /* If this is block 0, then we want to read the partition table for this - * device. Let's make one up */ - if(block == 0) { - int i; - memset(buff, 0, bufflen); - *((unsigned short *) (buff+510)) = 0xAA55; - p = (struct partition* ) (buff + 0x1be); - i = 0; - while(starts[i+1]){ - p->start_sect = starts[i]; - p->nr_sects = starts[i+1] - starts [i]; - p->sys_ind = 0x81; /* Linux partition */ - p->head = (i == 0 ? 1 : 0); - p->sector = 1; - p->cyl = starts[i] / N_HEAD / N_SECTOR; - p->end_head = N_HEAD - 1; - p->end_sector = N_SECTOR; - p->end_cyl = starts[i + 1] / N_HEAD / N_SECTOR; - p++; - i++; + nbytes = bufflen; + if (SCpnt->use_sg) { + sgcount = 0; + sgpnt = (struct scatterlist *) buff; + buff = sgpnt[sgcount].address; + bufflen = sgpnt[sgcount].length; + bh = SCpnt->request.bh; }; - if (!npart) npart = i; scsi_debug_errsts = 0; - break; - }; + do { + VERIFY1_DEBUG(READ); + /* For the speedy test, we do not even want to fill the buffer with anything */ +#ifdef CLEAR + memset(buff, 0, bufflen); +#endif + /* If this is block 0, then we want to read the partition table for this + * device. Let's make one up */ + if (block == 0) { + int i; + memset(buff, 0, bufflen); + *((unsigned short *) (buff + 510)) = 0xAA55; + p = (struct partition *) (buff + 0x1be); + i = 0; + while (starts[i + 1]) { + p->start_sect = starts[i]; + p->nr_sects = starts[i + 1] - starts[i]; + p->sys_ind = 0x81; /* Linux partition */ + p->head = (i == 0 ? 1 : 0); + p->sector = 1; + p->cyl = starts[i] / N_HEAD / N_SECTOR; + p->end_head = N_HEAD - 1; + p->end_sector = N_SECTOR; + p->end_cyl = starts[i + 1] / N_HEAD / N_SECTOR; + p++; + i++; + }; + if (!npart) + npart = i; + scsi_debug_errsts = 0; + break; + }; #ifdef DEBUG - if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors, - SCpnt->request.current_nr_sectors); + if (SCpnt->use_sg) + printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors, + SCpnt->request.current_nr_sectors); #endif - + #if 0 - /* Simulate a disk change */ - if(block == 0xfff0) { - sense_buffer[0] = 0x70; - sense_buffer[2] = UNIT_ATTENTION; - starts[0] += 10; - starts[1] += 10; - starts[2] += 10; - + /* Simulate a disk change */ + if (block == 0xfff0) { + sense_buffer[0] = 0x70; + sense_buffer[2] = UNIT_ATTENTION; + starts[0] += 10; + starts[1] += 10; + starts[2] += 10; + #ifdef DEBUG - { - int i; - printk("scsi_debug: Filling sense buffer:"); - for(i=0;i<12;i++) printk("%d ",sense_buffer[i]); - printk("\n"); - }; -#endif - scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); - break; - } /* End phony disk change code */ -#endif - + { + int i; + printk("scsi_debug: Filling sense buffer:"); + for (i = 0; i < 12; i++) + printk("%d ", sense_buffer[i]); + printk("\n"); + }; +#endif + scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + break; + } /* End phony disk change code */ +# + #ifdef CLEAR - memcpy(buff, &target, sizeof(target)); - memcpy(buff+sizeof(target), cmd, 24); - memcpy(buff+60, &block, sizeof(block)); - memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd)); + memcpy(buff, &target, sizeof(target)); + memcpy(buff + sizeof(target), cmd, 24); + memcpy(buff + 60, &block, sizeof(block)); + memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd)); #endif - nbytes -= bufflen; - if(SCpnt->use_sg){ + nbytes -= bufflen; + if (SCpnt->use_sg) { #ifdef CLEAR - memcpy(buff+128, bh, sizeof(struct buffer_head)); + memcpy(buff + 128, bh, sizeof(struct buffer_head)); #endif - block += bufflen >> 9; - bh = bh->b_reqnext; - sgcount++; - if (nbytes) { - if(!bh) panic("Too few blocks for linked request."); - buff = sgpnt[sgcount].address; - bufflen = sgpnt[sgcount].length; - }; - } - } while(nbytes); - - SCpnt->result = 0; - (done)(SCpnt); - return 0; - - if (SCpnt->use_sg && !scsi_debug_errsts) - if(bh) scsi_dump(SCpnt, 0); - break; - case WRITE_10: - case WRITE_6: + block += bufflen >> 9; + bh = bh->b_reqnext; + sgcount++; + if (nbytes) { + if (!bh) + panic("Too few blocks for linked request."); + buff = sgpnt[sgcount].address; + bufflen = sgpnt[sgcount].length; + }; + } + } while (nbytes); + + SCpnt->result = 0; + (done) (SCpnt); + return 0; + + if (SCpnt->use_sg && !scsi_debug_errsts) + if (bh) + scsi_dump(SCpnt, 0); + break; + case WRITE_10: + case WRITE_6: #ifdef DEBUG - printk("Write\n"); + printk("Write\n"); #endif - if ((*cmd) == WRITE_10) - block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); - else - block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - VERIFY_DEBUG(WRITE); - /* printk("(w%d)",SCpnt->request.nr_sectors); */ - if (SCpnt->use_sg){ - if ((bufflen >> 9) != SCpnt->request.nr_sectors) - panic ("Trying to write wrong number of blocks\n"); - sgpnt = (struct scatterlist *) buff; - buff = sgpnt[sgcount].address; - }; + if ((*cmd) == WRITE_10) + block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); + else + block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); + VERIFY_DEBUG(WRITE); + /* printk("(w%d)",SCpnt->request.nr_sectors); */ + if (SCpnt->use_sg) { + if ((bufflen >> 9) != SCpnt->request.nr_sectors) + panic("Trying to write wrong number of blocks\n"); + sgpnt = (struct scatterlist *) buff; + buff = sgpnt[sgcount].address; + }; #if 0 - if (block != *((unsigned long *) (buff+60))) { - printk("%x %x :",block, *((unsigned long *) (buff+60))); - scsi_dump(SCpnt,1); - panic("Bad block written.\n"); - }; + if (block != *((unsigned long *) (buff + 60))) { + printk("%x %x :", block, *((unsigned long *) (buff + 60))); + scsi_dump(SCpnt, 1); + panic("Bad block written.\n"); + }; #endif - scsi_debug_errsts = 0; - break; - case MODE_SENSE: - /* - * Used to detect write protected status. - */ - scsi_debug_errsts = 0; - memset(buff, 0, 6); - break; - default: - SCSI_LOG_LLQUEUE(3,printk("Unknown command %d\n",*cmd)); - SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); - return 0; - }; - - save_flags(flags); - cli(); - for(i=0;i= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) - { - SCSI_LOG_LLQUEUE(1,printk("Command rejected - host busy\n")); - restore_flags(flags); - return 1; - } + scsi_debug_errsts = 0; + break; + case MODE_SENSE: + /* + * Used to detect write protected status. + */ + scsi_debug_errsts = 0; + memset(buff, 0, 6); + break; + default: + SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd)); + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + }; + + save_flags(flags); + cli(); + for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) { + if (timeout[i].function == NULL) + break; + }; + + /* + * If all of the slots are full, just return 1. The new error handling scheme + * allows this, and the mid-level should queue things. + */ + if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) { + SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n")); + restore_flags(flags); + return 1; + } + SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i)); - SCSI_LOG_LLQUEUE(1,printk("Command accepted - slot %d\n", i)); - #ifdef IMMEDIATE - if( !scsi_debug_lockup ) - { - SCpnt->result = scsi_debug_errsts; - scsi_debug_intr_handle(i); /* No timer - do this one right away */ - } - restore_flags(flags); + if (!scsi_debug_lockup) { + SCpnt->result = scsi_debug_errsts; + scsi_debug_intr_handle(i); /* No timer - do this one right away */ + } + restore_flags(flags); #else - - SCpnt->result = scsi_debug_errsts; - timeout[i].function = scsi_debug_intr_handle; - timeout[i].data = i; - timeout[i].expires = jiffies + DISK_SPEED; - SCint[i] = SCpnt; - do_done[i] = done; - - restore_flags(flags); - add_timer(&timeout[i]); - if (!done) - panic("scsi_debug_queuecommand: done can't be NULL\n"); - + + SCpnt->result = scsi_debug_errsts; + timeout[i].function = scsi_debug_intr_handle; + timeout[i].data = i; + timeout[i].expires = jiffies + DISK_SPEED; + SCint[i] = SCpnt; + do_done[i] = done; + + restore_flags(flags); + add_timer(&timeout[i]); + if (!done) + panic("scsi_debug_queuecommand: done can't be NULL\n"); + #if 0 - printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires,jiffies); + printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies); #endif #endif - - return 0; + + return 0; } volatile static int internal_done_flag = 0; volatile static int internal_done_errcode = 0; static void internal_done(Scsi_Cmnd * SCpnt) { - internal_done_errcode = SCpnt->result; - ++internal_done_flag; + internal_done_errcode = SCpnt->result; + ++internal_done_flag; } int scsi_debug_command(Scsi_Cmnd * SCpnt) { - DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n")); - scsi_debug_queuecommand(SCpnt, internal_done); - - while (!internal_done_flag); - internal_done_flag = 0; - return internal_done_errcode; + DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n")); + scsi_debug_queuecommand(SCpnt, internal_done); + + while (!internal_done_flag); + internal_done_flag = 0; + return internal_done_errcode; } /* A "high" level interrupt handler. This should be called once per jiffy @@ -513,184 +520,175 @@ static void scsi_debug_intr_handle(unsigned long indx) { - Scsi_Cmnd * SCtmp; - void (*my_done)(Scsi_Cmnd *); + Scsi_Cmnd *SCtmp; + void (*my_done) (Scsi_Cmnd *); #ifdef DEBUG - int to; + int to; #endif - + #if 0 - del_timer(&timeout[indx]); + del_timer(&timeout[indx]); #endif - - SCtmp = (Scsi_Cmnd *) SCint[indx]; - my_done = do_done[indx]; - do_done[indx] = NULL; - timeout[indx].function = NULL; - SCint[indx] = NULL; - - if (!my_done) { - printk("scsi_debug_intr_handle: Unexpected interrupt\n"); - return; - } - + + SCtmp = (Scsi_Cmnd *) SCint[indx]; + my_done = do_done[indx]; + do_done[indx] = NULL; + timeout[indx].function = NULL; + SCint[indx] = NULL; + + if (!my_done) { + printk("scsi_debug_intr_handle: Unexpected interrupt\n"); + return; + } #ifdef DEBUG - printk("In intr_handle..."); - printk("...done %d %x %d %d\n",i , my_done, to, jiffies); - printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done); + printk("In intr_handle..."); + printk("...done %d %x %d %d\n", i, my_done, to, jiffies); + printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done); #endif - - my_done(SCtmp); + + my_done(SCtmp); #ifdef DEBUG - printk("Called done.\n"); + printk("Called done.\n"); #endif } int scsi_debug_detect(Scsi_Host_Template * tpnt) { - int i; + int i; - for(i=0; i < NR_HOSTS_PRESENT; i++) - { - tpnt->proc_dir = &proc_scsi_scsi_debug; - scsi_register(tpnt,0); - } - return NR_HOSTS_PRESENT; + for (i = 0; i < NR_HOSTS_PRESENT; i++) { + tpnt->proc_dir = &proc_scsi_scsi_debug; + scsi_register(tpnt, 0); + } + return NR_HOSTS_PRESENT; } int scsi_debug_abort(Scsi_Cmnd * SCpnt) { #if 0 - int j; - void (*my_done)(Scsi_Cmnd *); - unsigned long flags; + int j; + void (*my_done) (Scsi_Cmnd *); + unsigned long flags; #endif - - DEB(printk("scsi_debug_abort\n")); + + DEB(printk("scsi_debug_abort\n")); #if 0 - SCpnt->result = SCpnt->abort_reason << 16; - for(j=0;jresult = SCpnt->abort_reason << 16; + for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) { + if (SCpnt == SCint[j]) { + my_done = do_done[j]; + my_done(SCpnt); + save_flags(flags); + cli(); + timeout[j] = 0; + SCint[j] = NULL; + do_done[j] = NULL; + restore_flags(flags); + }; }; - }; #endif - return SCSI_ABORT_SNOOZE; + return SCSI_ABORT_SNOOZE; } -int scsi_debug_biosparam(Disk * disk, kdev_t dev, int* info){ - int size = disk->capacity; - info[0] = N_HEAD; - info[1] = N_SECTOR; - info[2] = (size + 2047) >> 11; - if (info[2] >= 1024) info[2] = 1024; - return 0; +int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info) +{ + int size = disk->capacity; + info[0] = N_HEAD; + info[1] = N_SECTOR; + info[2] = (size + 2047) >> 11; + if (info[2] >= 1024) + info[2] = 1024; + return 0; } int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why) { - int i; - unsigned long flags; - - void (*my_done)(Scsi_Cmnd *); - printk("Bus unlocked by reset - %d\n", why); - scsi_debug_lockup = 0; - DEB(printk("scsi_debug_reset called\n")); - for(i=0;iresult = DID_RESET << 16; - my_done = do_done[i]; - my_done(SCint[i]); - save_flags(flags); - cli(); - SCint[i] = NULL; - do_done[i] = NULL; - timeout[i].function = NULL; - restore_flags(flags); - } - return SCSI_RESET_SUCCESS; + int i; + unsigned long flags; + + void (*my_done) (Scsi_Cmnd *); + printk("Bus unlocked by reset - %d\n", why); + scsi_debug_lockup = 0; + DEB(printk("scsi_debug_reset called\n")); + for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) { + if (SCint[i] == NULL) + continue; + SCint[i]->result = DID_RESET << 16; + my_done = do_done[i]; + my_done(SCint[i]); + save_flags(flags); + cli(); + SCint[i] = NULL; + do_done[i] = NULL; + timeout[i].function = NULL; + restore_flags(flags); + } + return SCSI_RESET_SUCCESS; } const char *scsi_debug_info(void) { - static char buffer[] = " "; /* looks nicer without anything here */ - return buffer; + static char buffer[] = " "; /* looks nicer without anything here */ + return buffer; } /* scsi_debug_proc_info * Used if the driver currently has no own support for /proc/scsi */ -int scsi_debug_proc_info(char *buffer, char **start, off_t offset, - int length, int inode, int inout) +int scsi_debug_proc_info(char *buffer, char **start, off_t offset, + int length, int inode, int inout) { - int len, pos, begin; - int orig_length; + int len, pos, begin; + int orig_length; - orig_length = length; + orig_length = length; - if(inout == 1) - { - /* First check for the Signature */ - if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) { - buffer += 11; - length -= 11; - - if( buffer[length - 1] == '\n' ) - { - buffer[length-1] = '\0'; - length--; - } - - /* - * OK, we are getting some kind of command. Figure out - * what we are supposed to do here. Simulate bus lockups - * to test our reset capability. - */ - if( length == 6 && strncmp(buffer, "lockup", length) == 0 ) - { - scsi_debug_lockup = 1; - return orig_length; - } - - if( length == 6 && strncmp(buffer, "unlock", length) == 0 ) - { - scsi_debug_lockup = 0; - return orig_length; - } - - printk("Unknown command:%s (%d)\n", buffer, length); - } else - printk("Wrong Signature:%10s\n", (char *) buffer); - - return -EINVAL; - - } - - begin = 0; - pos = len = sprintf(buffer, - "This driver is not a real scsi driver, but it plays one on TV.\n" - "It is very handy for debugging specific problems because you\n" - "can simulate a variety of error conditions\n"); - if(pos < offset) - { - len = 0; - begin = pos; - } - - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); - if(len > length) - len = length; - - return(len); + if (inout == 1) { + /* First check for the Signature */ + if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) { + buffer += 11; + length -= 11; + + if (buffer[length - 1] == '\n') { + buffer[length - 1] = '\0'; + length--; + } + /* + * OK, we are getting some kind of command. Figure out + * what we are supposed to do here. Simulate bus lockups + * to test our reset capability. + */ + if (length == 6 && strncmp(buffer, "lockup", length) == 0) { + scsi_debug_lockup = 1; + return orig_length; + } + if (length == 6 && strncmp(buffer, "unlock", length) == 0) { + scsi_debug_lockup = 0; + return orig_length; + } + printk("Unknown command:%s (%d)\n", buffer, length); + } else + printk("Wrong Signature:%10s\n", (char *) buffer); + + return -EINVAL; + + } + begin = 0; + pos = len = sprintf(buffer, + "This driver is not a real scsi driver, but it plays one on TV.\n" + "It is very handy for debugging specific problems because you\n" + "can simulate a variety of error conditions\n"); + if (pos < offset) { + len = 0; + begin = pos; + } + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); + if (len > length) + len = length; + + return (len); } #ifdef MODULE @@ -699,7 +697,7 @@ #include "scsi_module.c" #endif - + /* * Overrides for Emacs so that we almost follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_debug.h linux/drivers/scsi/scsi_debug.h --- v2.3.16/linux/drivers/scsi/scsi_debug.h Sun Dec 27 22:19:23 1998 +++ linux/drivers/scsi/scsi_debug.h Sat Sep 4 10:48:46 1999 @@ -5,14 +5,14 @@ int scsi_debug_detect(Scsi_Host_Template *); int scsi_debug_command(Scsi_Cmnd *); -int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int scsi_debug_abort(Scsi_Cmnd *); int scsi_debug_biosparam(Disk *, kdev_t, int[]); int scsi_debug_reset(Scsi_Cmnd *, unsigned int); int scsi_debug_proc_info(char *, char **, off_t, int, int, int); - + #ifndef NULL - #define NULL 0 +#define NULL 0 #endif diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.3.16/linux/drivers/scsi/scsi_error.c Sun Aug 15 11:49:53 1999 +++ linux/drivers/scsi/scsi_error.c Sat Sep 4 10:48:46 1999 @@ -3,8 +3,8 @@ * * SCSI error/timeout handling * Initial versions: Eric Youngdale. Based upon conversations with - * Leonard Zubkoff and David Miller at Linux Expo, - * ideas originating from all over the place. + * Leonard Zubkoff and David Miller at Linux Expo, + * ideas originating from all over the place. * */ @@ -36,19 +36,19 @@ #include "constants.h" #ifdef MODULE - #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) +#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) #else - #define SHUTDOWN_SIGS (0UL) +#define SHUTDOWN_SIGS (0UL) #endif #ifdef DEBUG - #define SENSE_TIMEOUT SCSI_TIMEOUT - #define ABORT_TIMEOUT SCSI_TIMEOUT - #define RESET_TIMEOUT SCSI_TIMEOUT +#define SENSE_TIMEOUT SCSI_TIMEOUT +#define ABORT_TIMEOUT SCSI_TIMEOUT +#define RESET_TIMEOUT SCSI_TIMEOUT #else - #define SENSE_TIMEOUT (10*HZ) - #define RESET_TIMEOUT (2*HZ) - #define ABORT_TIMEOUT (15*HZ) +#define SENSE_TIMEOUT (10*HZ) +#define RESET_TIMEOUT (2*HZ) +#define ABORT_TIMEOUT (15*HZ) #endif #define STATIC @@ -63,20 +63,20 @@ static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_error.c,v 1.10 1997/12/08 04:50:35 eric Exp $"; -STATIC int scsi_check_sense (Scsi_Cmnd * SCpnt); -STATIC int scsi_request_sense(Scsi_Cmnd *); -STATIC void scsi_send_eh_cmnd (Scsi_Cmnd * SCpnt, int timeout); -STATIC int scsi_try_to_abort_command(Scsi_Cmnd *, int); -STATIC int scsi_test_unit_ready(Scsi_Cmnd *); -STATIC int scsi_try_bus_device_reset(Scsi_Cmnd *, int timeout); -STATIC int scsi_try_bus_reset(Scsi_Cmnd *); -STATIC int scsi_try_host_reset(Scsi_Cmnd *); -STATIC int scsi_unit_is_ready(Scsi_Cmnd *); -STATIC void scsi_eh_action_done(Scsi_Cmnd *, int); -STATIC int scsi_eh_retry_command(Scsi_Cmnd *); -STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt); -STATIC void scsi_restart_operations(struct Scsi_Host *); -STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt); +STATIC int scsi_check_sense(Scsi_Cmnd * SCpnt); +STATIC int scsi_request_sense(Scsi_Cmnd *); +STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout); +STATIC int scsi_try_to_abort_command(Scsi_Cmnd *, int); +STATIC int scsi_test_unit_ready(Scsi_Cmnd *); +STATIC int scsi_try_bus_device_reset(Scsi_Cmnd *, int timeout); +STATIC int scsi_try_bus_reset(Scsi_Cmnd *); +STATIC int scsi_try_host_reset(Scsi_Cmnd *); +STATIC int scsi_unit_is_ready(Scsi_Cmnd *); +STATIC void scsi_eh_action_done(Scsi_Cmnd *, int); +STATIC int scsi_eh_retry_command(Scsi_Cmnd *); +STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt); +STATIC void scsi_restart_operations(struct Scsi_Host *); +STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt); /* @@ -91,36 +91,33 @@ * * Returns: Nothing * - * Notes: This should be turned into an inline function. + * Notes: This should be turned into an inline function. * * More Notes: Each scsi command has it's own timer, and as it is added to * the queue, we set up the timer. When the command completes, * we cancel the timer. Pretty simple, really, especially * compared to the old way of handling this crap. */ -void -scsi_add_timer(Scsi_Cmnd * SCset, - int timeout, - void (*complete)(Scsi_Cmnd *)) -{ - - /* - * If the clock was already running for this command, then - * first delete the timer. The timer handling code gets rather - * confused if we don't do this. - */ - if( SCset->eh_timeout.function != NULL ) - { - del_timer(&SCset->eh_timeout); - } - - SCset->eh_timeout.data = (unsigned long) SCset; - SCset->eh_timeout.expires = jiffies + timeout; - SCset->eh_timeout.function = (void (*)(unsigned long))complete; +void scsi_add_timer(Scsi_Cmnd * SCset, + int timeout, + void (*complete) (Scsi_Cmnd *)) +{ + + /* + * If the clock was already running for this command, then + * first delete the timer. The timer handling code gets rather + * confused if we don't do this. + */ + if (SCset->eh_timeout.function != NULL) { + del_timer(&SCset->eh_timeout); + } + SCset->eh_timeout.data = (unsigned long) SCset; + SCset->eh_timeout.expires = jiffies + timeout; + SCset->eh_timeout.function = (void (*)(unsigned long)) complete; - SCSI_LOG_ERROR_RECOVERY(5,printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete)); + SCSI_LOG_ERROR_RECOVERY(5, printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete)); - add_timer(&SCset->eh_timeout); + add_timer(&SCset->eh_timeout); } @@ -133,22 +130,21 @@ * * Returns: Amount of time remaining before command would have timed out. * - * Notes: This should be turned into an inline function. + * Notes: This should be turned into an inline function. */ -int -scsi_delete_timer(Scsi_Cmnd * SCset) +int scsi_delete_timer(Scsi_Cmnd * SCset) { - int rtn; + int rtn; - rtn = jiffies - SCset->eh_timeout.expires; - del_timer(&SCset->eh_timeout); + rtn = jiffies - SCset->eh_timeout.expires; + del_timer(&SCset->eh_timeout); - SCSI_LOG_ERROR_RECOVERY(5,printk("Clearing timer for command %p\n", SCset)); + SCSI_LOG_ERROR_RECOVERY(5, printk("Clearing timer for command %p\n", SCset)); - SCset->eh_timeout.data = (unsigned long) NULL; - SCset->eh_timeout.function = NULL; + SCset->eh_timeout.data = (unsigned long) NULL; + SCset->eh_timeout.function = NULL; - return rtn; + return rtn; } /* @@ -162,74 +158,70 @@ * * Notes: */ -static void do_scsi_times_out (Scsi_Cmnd * SCpnt) +static void do_scsi_times_out(Scsi_Cmnd * SCpnt) { - /* - * Notify the low-level code that this operation failed and we are - * reposessing the command. - */ + /* + * Notify the low-level code that this operation failed and we are + * reposessing the command. + */ #ifdef ERIC_neverdef - /* - * FIXME(eric) - * Allow the host adapter to push a queue ordering tag - * out to the bus to force the command in question to complete. - * If the host wants to do this, then we just restart the timer - * for the command. Before we really do this, some real thought - * as to the optimum way to handle this should be done. We *do* - * need to force ordering every so often to ensure that all requests - * do eventually complete, but I am not sure if this is the best way - * to actually go about it. - * - * Better yet, force a sync here, but don't block since we are in an - * interrupt. - */ - if( SCpnt->host->hostt->eh_ordered_queue_tag ) - { - if( (*SCpnt->host->hostt->eh_ordered_queue_tag)(SCpnt)) - { - scsi_add_timer(SCpnt, SCpnt->internal_timeout, - scsi_times_out); - return; - } - } - /* - * FIXME(eric) - add a second special interface to handle this - * case. Ideally that interface can also be used to request - * a queu - */ - if (SCpnt->host->can_queue) - { - SCpnt->host->hostt->queuecommand (SCpnt, NULL); - } + /* + * FIXME(eric) + * Allow the host adapter to push a queue ordering tag + * out to the bus to force the command in question to complete. + * If the host wants to do this, then we just restart the timer + * for the command. Before we really do this, some real thought + * as to the optimum way to handle this should be done. We *do* + * need to force ordering every so often to ensure that all requests + * do eventually complete, but I am not sure if this is the best way + * to actually go about it. + * + * Better yet, force a sync here, but don't block since we are in an + * interrupt. + */ + if (SCpnt->host->hostt->eh_ordered_queue_tag) { + if ((*SCpnt->host->hostt->eh_ordered_queue_tag) (SCpnt)) { + scsi_add_timer(SCpnt, SCpnt->internal_timeout, + scsi_times_out); + return; + } + } + /* + * FIXME(eric) - add a second special interface to handle this + * case. Ideally that interface can also be used to request + * a queu + */ + if (SCpnt->host->can_queue) { + SCpnt->host->hostt->queuecommand(SCpnt, NULL); + } #endif - /* Set the serial_number_at_timeout to the current serial_number */ - SCpnt->serial_number_at_timeout = SCpnt->serial_number; + /* Set the serial_number_at_timeout to the current serial_number */ + SCpnt->serial_number_at_timeout = SCpnt->serial_number; + + SCpnt->eh_state = FAILED; + SCpnt->state = SCSI_STATE_TIMEOUT; + SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; + + SCpnt->host->in_recovery = 1; + SCpnt->host->host_failed++; + + SCSI_LOG_TIMEOUT(3, printk("Command timed out active=%d busy=%d failed=%d\n", + atomic_read(&SCpnt->host->host_active), + SCpnt->host->host_busy, + SCpnt->host->host_failed)); - SCpnt->eh_state = FAILED; - SCpnt->state = SCSI_STATE_TIMEOUT; - SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; - - SCpnt->host->in_recovery = 1; - SCpnt->host->host_failed++; - - SCSI_LOG_TIMEOUT(3,printk("Command timed out active=%d busy=%d failed=%d\n", - atomic_read(&SCpnt->host->host_active), - SCpnt->host->host_busy, - SCpnt->host->host_failed)); - - /* - * If the host is having troubles, then look to see if this was the last - * command that might have failed. If so, wake up the error handler. - */ - if( SCpnt->host->host_busy == SCpnt->host->host_failed ) - { - up(SCpnt->host->eh_wait); - } + /* + * If the host is having troubles, then look to see if this was the last + * command that might have failed. If so, wake up the error handler. + */ + if (SCpnt->host->host_busy == SCpnt->host->host_failed) { + up(SCpnt->host->eh_wait); + } } -void scsi_times_out (Scsi_Cmnd * SCpnt) +void scsi_times_out(Scsi_Cmnd * SCpnt) { unsigned long flags; @@ -252,15 +244,14 @@ * Notes: We block until the host is out of error recovery, and then * check to see whether the host or the device is offline. */ -int -scsi_block_when_processing_errors(Scsi_Device * SDpnt) +int scsi_block_when_processing_errors(Scsi_Device * SDpnt) { - SCSI_SLEEP( &SDpnt->host->host_wait, SDpnt->host->in_recovery); + SCSI_SLEEP(&SDpnt->host->host_wait, SDpnt->host->in_recovery); - SCSI_LOG_ERROR_RECOVERY(5,printk("Open returning %d\n", SDpnt->online)); + SCSI_LOG_ERROR_RECOVERY(5, printk("Open returning %d\n", SDpnt->online)); - return SDpnt->online; + return SDpnt->online; } /* @@ -272,39 +263,39 @@ * * Returns: Nothing. * - * Notes: During error handling, the kernel thread will be sleeping - * waiting for some action to complete on the device. Our only - * job is to record that it timed out, and to wake up the - * thread. + * Notes: During error handling, the kernel thread will be sleeping + * waiting for some action to complete on the device. Our only + * job is to record that it timed out, and to wake up the + * thread. */ STATIC -void scsi_eh_times_out (Scsi_Cmnd * SCpnt) +void scsi_eh_times_out(Scsi_Cmnd * SCpnt) { - unsigned long flags; - int rtn = FAILED; + unsigned long flags; + int rtn = FAILED; - spin_lock_irqsave(&io_request_lock, flags); + spin_lock_irqsave(&io_request_lock, flags); - SCpnt->eh_state = SCSI_STATE_TIMEOUT; - SCpnt->owner = SCSI_OWNER_LOWLEVEL; + SCpnt->eh_state = SCSI_STATE_TIMEOUT; + SCpnt->owner = SCSI_OWNER_LOWLEVEL; - /* - * As far as the low level driver is concerned, this command is still - * active, so we must give the low level driver a chance to abort it. (DB) - */ - if (SCpnt->host->hostt->eh_abort_handler) - rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt); + /* + * As far as the low level driver is concerned, this command is still + * active, so we must give the low level driver a chance to abort it. (DB) + */ + if (SCpnt->host->hostt->eh_abort_handler) + rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt); - SCpnt->request.rq_status = RQ_SCSI_DONE; - SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; + SCpnt->request.rq_status = RQ_SCSI_DONE; + SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; - SCSI_LOG_ERROR_RECOVERY(5,printk("In scsi_eh_times_out %p\n", SCpnt)); + SCSI_LOG_ERROR_RECOVERY(5, printk("In scsi_eh_times_out %p\n", SCpnt)); - if (SCpnt->host->eh_action != NULL) - up(SCpnt->host->eh_action); - else - printk("Missing scsi error handler thread\n"); - spin_unlock_irqrestore(&io_request_lock, flags); + if (SCpnt->host->eh_action != NULL) + up(SCpnt->host->eh_action); + else + printk("Missing scsi error handler thread\n"); + spin_unlock_irqrestore(&io_request_lock, flags); } @@ -317,24 +308,24 @@ * * Returns: Nothing. * - * Notes: During error handling, the kernel thread will be sleeping - * waiting for some action to complete on the device. Our only - * job is to record that the action completed, and to wake up the - * thread. + * Notes: During error handling, the kernel thread will be sleeping + * waiting for some action to complete on the device. Our only + * job is to record that the action completed, and to wake up the + * thread. */ STATIC -void scsi_eh_done (Scsi_Cmnd * SCpnt) +void scsi_eh_done(Scsi_Cmnd * SCpnt) { - SCpnt->request.rq_status = RQ_SCSI_DONE; - - SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; - SCpnt->eh_state = SUCCESS; + SCpnt->request.rq_status = RQ_SCSI_DONE; + + SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; + SCpnt->eh_state = SUCCESS; - SCSI_LOG_ERROR_RECOVERY(5,printk("In eh_done %p result:%x\n", SCpnt, - SCpnt->result)); + SCSI_LOG_ERROR_RECOVERY(5, printk("In eh_done %p result:%x\n", SCpnt, + SCpnt->result)); - if (SCpnt->host->eh_action != NULL) - up(SCpnt->host->eh_action); + if (SCpnt->host->eh_action != NULL) + up(SCpnt->host->eh_action); } /* @@ -343,208 +334,205 @@ * Purpose: Completion function for error handling. * * Arguments: SCpnt - command that is timing out. - * answer - boolean that indicates whether operation succeeded. + * answer - boolean that indicates whether operation succeeded. * * Returns: Nothing. * - * Notes: This callback is only used for abort and reset operations. + * Notes: This callback is only used for abort and reset operations. */ STATIC -void scsi_eh_action_done (Scsi_Cmnd * SCpnt, int answer) +void scsi_eh_action_done(Scsi_Cmnd * SCpnt, int answer) { - SCpnt->request.rq_status = RQ_SCSI_DONE; - - SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; - SCpnt->eh_state = (answer ? SUCCESS : FAILED); + SCpnt->request.rq_status = RQ_SCSI_DONE; - if (SCpnt->host->eh_action != NULL) - up(SCpnt->host->eh_action); + SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; + SCpnt->eh_state = (answer ? SUCCESS : FAILED); + + if (SCpnt->host->eh_action != NULL) + up(SCpnt->host->eh_action); } /* - * Function: scsi_sense_valid() + * Function: scsi_sense_valid() * - * Purpose: Determine whether a host has automatically obtained sense - * information or not. If we have it, then give a recommendation - * as to what we should do next. + * Purpose: Determine whether a host has automatically obtained sense + * information or not. If we have it, then give a recommendation + * as to what we should do next. */ -int -scsi_sense_valid(Scsi_Cmnd * SCpnt) +int scsi_sense_valid(Scsi_Cmnd * SCpnt) { - if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) - { - return FALSE; - } - return TRUE; + if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) { + return FALSE; + } + return TRUE; } /* - * Function: scsi_eh_retry_command() + * Function: scsi_eh_retry_command() * - * Purpose: Retry the original command + * Purpose: Retry the original command * - * Returns: SUCCESS - we were able to get the sense data. - * FAILED - we were not able to get the sense data. + * Returns: SUCCESS - we were able to get the sense data. + * FAILED - we were not able to get the sense data. * - * Notes: This function will *NOT* return until the command either - * times out, or it completes. + * Notes: This function will *NOT* return until the command either + * times out, or it completes. */ -STATIC int -scsi_eh_retry_command(Scsi_Cmnd * SCpnt) +STATIC int scsi_eh_retry_command(Scsi_Cmnd * SCpnt) { - memcpy ((void *) SCpnt->cmnd, (void*) SCpnt->data_cmnd, - sizeof(SCpnt->data_cmnd)); - SCpnt->request_buffer = SCpnt->buffer; - SCpnt->request_bufflen = SCpnt->bufflen; - SCpnt->use_sg = SCpnt->old_use_sg; - SCpnt->cmd_len = SCpnt->old_cmd_len; + memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, + sizeof(SCpnt->data_cmnd)); + SCpnt->request_buffer = SCpnt->buffer; + SCpnt->request_bufflen = SCpnt->bufflen; + SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; - scsi_send_eh_cmnd (SCpnt, SCpnt->timeout_per_command); + scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command); - /* - * Hey, we are done. Let's look to see what happened. - */ - return SCpnt->eh_state; + /* + * Hey, we are done. Let's look to see what happened. + */ + return SCpnt->eh_state; } /* - * Function: scsi_request_sense() + * Function: scsi_request_sense() * - * Purpose: Request sense data from a particular target. + * Purpose: Request sense data from a particular target. * - * Returns: SUCCESS - we were able to get the sense data. - * FAILED - we were not able to get the sense data. + * Returns: SUCCESS - we were able to get the sense data. + * FAILED - we were not able to get the sense data. * - * Notes: Some hosts automatically obtain this information, others - * require that we obtain it on our own. + * Notes: Some hosts automatically obtain this information, others + * require that we obtain it on our own. * - * This function will *NOT* return until the command either - * times out, or it completes. + * This function will *NOT* return until the command either + * times out, or it completes. */ -STATIC int -scsi_request_sense(Scsi_Cmnd * SCpnt) +STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt) { - static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0}; - unsigned char scsi_result0[256], *scsi_result=NULL; - - - memcpy ((void *) SCpnt->cmnd , (void *) generic_sense, - sizeof(generic_sense)); - - SCpnt->cmnd[1] = SCpnt->lun << 5; - - scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma) - ? &scsi_result0[0] : scsi_init_malloc (512, GFP_ATOMIC|GFP_DMA); - - if (scsi_result == NULL) { - printk("cannot allocate scsi_result in scsi_request_sense.\n"); - return FAILED; - } - - /* - * Zero the sense buffer. Some host adapters automatically always request - * sense, so it is not a good idea that SCpnt->request_buffer and - * SCpnt->sense_buffer point to the same address (DB). - * 0 is not a valid sense code. - */ - memset ((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); - memset ((void *) scsi_result, 0, 256); - - SCpnt->request_buffer = scsi_result; - SCpnt->request_bufflen = 256; - SCpnt->use_sg = 0; - SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); - - scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT); - - /* Last chance to have valid sense data */ - if (!scsi_sense_valid(SCpnt)) memcpy((void *) SCpnt->sense_buffer, - SCpnt->request_buffer, - sizeof(SCpnt->sense_buffer)); - - if (scsi_result != &scsi_result0[0] && scsi_result != NULL) - scsi_init_free (scsi_result, 512); - - /* - * When we eventually call scsi_finish, we really wish to complete - * the original request, so let's restore the original data. (DB) - */ - memcpy ((void *) SCpnt->cmnd, (void*) SCpnt->data_cmnd, - sizeof(SCpnt->data_cmnd)); - SCpnt->request_buffer = SCpnt->buffer; - SCpnt->request_bufflen = SCpnt->bufflen; - SCpnt->use_sg = SCpnt->old_use_sg; - SCpnt->cmd_len = SCpnt->old_cmd_len; - - /* - * Hey, we are done. Let's look to see what happened. - */ - return SCpnt->eh_state; -} - -/* - * Function: scsi_test_unit_ready() - * - * Purpose: Run test unit ready command to see if the device is talking to us or not. - * - */ -STATIC int -scsi_test_unit_ready(Scsi_Cmnd * SCpnt) -{ - static unsigned char tur_command[6] = {TEST_UNIT_READY, 0,0,0,0,0}; - unsigned char scsi_result0[256], *scsi_result=NULL; - - memcpy ((void *) SCpnt->cmnd , (void *) tur_command, - sizeof(tur_command)); - - SCpnt->cmnd[1] = SCpnt->lun << 5; - - scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma) - ? &scsi_result0[0] : scsi_init_malloc (512, GFP_ATOMIC|GFP_DMA); - - if (scsi_result == NULL) { - printk("cannot allocate scsi_result in scsi_test_unit_ready.\n"); - return FAILED; - } - - /* - * Zero the sense buffer. Some host adapters automatically always request - * sense, so it is not a good idea that SCpnt->request_buffer and - * SCpnt->sense_buffer point to the same address (DB). - * 0 is not a valid sense code. - */ - memset ((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); - memset ((void *) scsi_result, 0, 256); - - SCpnt->request_buffer = scsi_result; - SCpnt->request_bufflen = 256; - SCpnt->use_sg = 0; - SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); - scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT); - - /* Last chance to have valid sense data */ - if (!scsi_sense_valid(SCpnt)) memcpy((void *) SCpnt->sense_buffer, - SCpnt->request_buffer, - sizeof(SCpnt->sense_buffer)); - - if (scsi_result != &scsi_result0[0] && scsi_result != NULL) - scsi_init_free (scsi_result, 512); - - /* - * When we eventually call scsi_finish, we really wish to complete - * the original request, so let's restore the original data. (DB) - */ - memcpy ((void *) SCpnt->cmnd, (void*) SCpnt->data_cmnd, - sizeof(SCpnt->data_cmnd)); - SCpnt->request_buffer = SCpnt->buffer; - SCpnt->request_bufflen = SCpnt->bufflen; - SCpnt->use_sg = SCpnt->old_use_sg; - SCpnt->cmd_len = SCpnt->old_cmd_len; - - /* - * Hey, we are done. Let's look to see what happened. - */ - return SCpnt->eh_state; + static unsigned char generic_sense[6] = + {REQUEST_SENSE, 0, 0, 0, 255, 0}; + unsigned char scsi_result0[256], *scsi_result = NULL; + + + memcpy((void *) SCpnt->cmnd, (void *) generic_sense, + sizeof(generic_sense)); + + SCpnt->cmnd[1] = SCpnt->lun << 5; + + scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma) + ? &scsi_result0[0] : scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA); + + if (scsi_result == NULL) { + printk("cannot allocate scsi_result in scsi_request_sense.\n"); + return FAILED; + } + /* + * Zero the sense buffer. Some host adapters automatically always request + * sense, so it is not a good idea that SCpnt->request_buffer and + * SCpnt->sense_buffer point to the same address (DB). + * 0 is not a valid sense code. + */ + memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); + memset((void *) scsi_result, 0, 256); + + SCpnt->request_buffer = scsi_result; + SCpnt->request_bufflen = 256; + SCpnt->use_sg = 0; + SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); + + scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); + + /* Last chance to have valid sense data */ + if (!scsi_sense_valid(SCpnt)) + memcpy((void *) SCpnt->sense_buffer, + SCpnt->request_buffer, + sizeof(SCpnt->sense_buffer)); + + if (scsi_result != &scsi_result0[0] && scsi_result != NULL) + scsi_init_free(scsi_result, 512); + + /* + * When we eventually call scsi_finish, we really wish to complete + * the original request, so let's restore the original data. (DB) + */ + memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, + sizeof(SCpnt->data_cmnd)); + SCpnt->request_buffer = SCpnt->buffer; + SCpnt->request_bufflen = SCpnt->bufflen; + SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; + + /* + * Hey, we are done. Let's look to see what happened. + */ + return SCpnt->eh_state; +} + +/* + * Function: scsi_test_unit_ready() + * + * Purpose: Run test unit ready command to see if the device is talking to us or not. + * + */ +STATIC int scsi_test_unit_ready(Scsi_Cmnd * SCpnt) +{ + static unsigned char tur_command[6] = + {TEST_UNIT_READY, 0, 0, 0, 0, 0}; + unsigned char scsi_result0[256], *scsi_result = NULL; + + memcpy((void *) SCpnt->cmnd, (void *) tur_command, + sizeof(tur_command)); + + SCpnt->cmnd[1] = SCpnt->lun << 5; + + scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma) + ? &scsi_result0[0] : scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA); + + if (scsi_result == NULL) { + printk("cannot allocate scsi_result in scsi_test_unit_ready.\n"); + return FAILED; + } + /* + * Zero the sense buffer. Some host adapters automatically always request + * sense, so it is not a good idea that SCpnt->request_buffer and + * SCpnt->sense_buffer point to the same address (DB). + * 0 is not a valid sense code. + */ + memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); + memset((void *) scsi_result, 0, 256); + + SCpnt->request_buffer = scsi_result; + SCpnt->request_bufflen = 256; + SCpnt->use_sg = 0; + SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); + scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); + + /* Last chance to have valid sense data */ + if (!scsi_sense_valid(SCpnt)) + memcpy((void *) SCpnt->sense_buffer, + SCpnt->request_buffer, + sizeof(SCpnt->sense_buffer)); + + if (scsi_result != &scsi_result0[0] && scsi_result != NULL) + scsi_init_free(scsi_result, 512); + + /* + * When we eventually call scsi_finish, we really wish to complete + * the original request, so let's restore the original data. (DB) + */ + memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, + sizeof(SCpnt->data_cmnd)); + SCpnt->request_buffer = SCpnt->buffer; + SCpnt->request_bufflen = SCpnt->bufflen; + SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; + + /* + * Hey, we are done. Let's look to see what happened. + */ + return SCpnt->eh_state; } /* @@ -553,164 +541,146 @@ * to be locked we can avoid the lock here.. */ STATIC -void scsi_sleep_done (struct semaphore * sem) +void scsi_sleep_done(struct semaphore *sem) { - if( sem != NULL ) - { - up(sem); - } + if (sem != NULL) { + up(sem); + } } -void scsi_sleep (int timeout) +void scsi_sleep(int timeout) { - DECLARE_MUTEX_LOCKED(sem); - struct timer_list timer; + DECLARE_MUTEX_LOCKED(sem); + struct timer_list timer; - init_timer(&timer); - timer.data = (unsigned long) &sem; - timer.expires = jiffies + timeout; - timer.function = (void (*)(unsigned long))scsi_sleep_done; - - SCSI_LOG_ERROR_RECOVERY(5,printk("Sleeping for timer tics %d\n", timeout)); - - add_timer(&timer); + init_timer(&timer); + timer.data = (unsigned long) &sem; + timer.expires = jiffies + timeout; + timer.function = (void (*)(unsigned long)) scsi_sleep_done; - spin_unlock_irq(&io_request_lock); - down(&sem); - spin_lock_irq(&io_request_lock); - - del_timer(&timer); + SCSI_LOG_ERROR_RECOVERY(5, printk("Sleeping for timer tics %d\n", timeout)); + + add_timer(&timer); + + spin_unlock_irq(&io_request_lock); + down(&sem); + spin_lock_irq(&io_request_lock); + + del_timer(&timer); } /* - * Function: scsi_send_eh_cmnd + * Function: scsi_send_eh_cmnd * - * Purpose: Send a command out to a device as part of error recovery. + * Purpose: Send a command out to a device as part of error recovery. * - * Notes: The initialization of the structures is quite a bit different - * in this case, and furthermore, there is a different completion - * handler. + * Notes: The initialization of the structures is quite a bit different + * in this case, and furthermore, there is a different completion + * handler. */ -STATIC void scsi_send_eh_cmnd (Scsi_Cmnd * SCpnt, int timeout) +STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout) { - struct Scsi_Host * host; - - host = SCpnt->host; - -retry: - /* - * We will use a queued command if possible, otherwise we will emulate the - * queuing and calling of completion function ourselves. - */ - SCpnt->owner = SCSI_OWNER_LOWLEVEL; - - if (host->can_queue) - { - DECLARE_MUTEX_LOCKED(sem); - - SCpnt->eh_state = SCSI_STATE_QUEUED; + struct Scsi_Host *host; - scsi_add_timer(SCpnt, timeout, scsi_eh_times_out); + host = SCpnt->host; + retry: /* - * Set up the semaphore so we wait for the command to complete. + * We will use a queued command if possible, otherwise we will emulate the + * queuing and calling of completion function ourselves. */ - SCpnt->host->eh_action = &sem; - SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->owner = SCSI_OWNER_LOWLEVEL; - host->hostt->queuecommand (SCpnt, scsi_eh_done); - spin_unlock_irq(&io_request_lock); - down(&sem); - spin_lock_irq(&io_request_lock); + if (host->can_queue) { + DECLARE_MUTEX_LOCKED(sem); - SCpnt->host->eh_action = NULL; + SCpnt->eh_state = SCSI_STATE_QUEUED; - del_timer(&SCpnt->eh_timeout); + scsi_add_timer(SCpnt, timeout, scsi_eh_times_out); - /* - * See if timeout. If so, tell the host to forget about it. - * In other words, we don't want a callback any more. - */ - if( SCpnt->eh_state == SCSI_STATE_TIMEOUT ) - { - SCpnt->eh_state = FAILED; - } - - SCSI_LOG_ERROR_RECOVERY(5,printk("send_eh_cmnd: %p eh_state:%x\n", - SCpnt, SCpnt->eh_state)); - } - else - { - int temp; + /* + * Set up the semaphore so we wait for the command to complete. + */ + SCpnt->host->eh_action = &sem; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + + host->hostt->queuecommand(SCpnt, scsi_eh_done); + spin_unlock_irq(&io_request_lock); + down(&sem); + spin_lock_irq(&io_request_lock); + + SCpnt->host->eh_action = NULL; + + del_timer(&SCpnt->eh_timeout); + + /* + * See if timeout. If so, tell the host to forget about it. + * In other words, we don't want a callback any more. + */ + if (SCpnt->eh_state == SCSI_STATE_TIMEOUT) { + SCpnt->eh_state = FAILED; + } + SCSI_LOG_ERROR_RECOVERY(5, printk("send_eh_cmnd: %p eh_state:%x\n", + SCpnt, SCpnt->eh_state)); + } else { + int temp; + + /* + * We damn well had better never use this code. There is no timeout + * protection here, since we would end up waiting in the actual low + * level driver, we don't know how to wake it up. + */ + temp = host->hostt->command(SCpnt); + SCpnt->result = temp; + if (scsi_eh_completed_normally(SCpnt)) { + SCpnt->eh_state = SUCCESS; + } else { + SCpnt->eh_state = FAILED; + } + } /* - * We damn well had better never use this code. There is no timeout - * protection here, since we would end up waiting in the actual low - * level driver, we don't know how to wake it up. + * Now examine the actual status codes to see whether the command actually + * did complete normally. */ - temp = host->hostt->command (SCpnt); - SCpnt->result = temp; - if( scsi_eh_completed_normally(SCpnt) ) - { - SCpnt->eh_state = SUCCESS; - } - else - { - SCpnt->eh_state = FAILED; - } - } - - /* - * Now examine the actual status codes to see whether the command actually - * did complete normally. - */ - if( SCpnt->eh_state == SUCCESS ) - { - switch( scsi_eh_completed_normally(SCpnt) ) - { - case SUCCESS: - SCpnt->eh_state = SUCCESS; - break; - case NEEDS_RETRY: - goto retry; - case FAILED: - default: - SCpnt->eh_state = FAILED; - break; - } - } - else - { - SCpnt->eh_state = FAILED; - } + if (SCpnt->eh_state == SUCCESS) { + switch (scsi_eh_completed_normally(SCpnt)) { + case SUCCESS: + SCpnt->eh_state = SUCCESS; + break; + case NEEDS_RETRY: + goto retry; + case FAILED: + default: + SCpnt->eh_state = FAILED; + break; + } + } else { + SCpnt->eh_state = FAILED; + } } /* - * Function: scsi_unit_is_ready() + * Function: scsi_unit_is_ready() * - * Purpose: Called after TEST_UNIT_READY is run, to test to see if - * the unit responded in a way that indicates it is ready. + * Purpose: Called after TEST_UNIT_READY is run, to test to see if + * the unit responded in a way that indicates it is ready. */ -STATIC int -scsi_unit_is_ready(Scsi_Cmnd * SCpnt) -{ - if (SCpnt->result) - { - if (((driver_byte (SCpnt->result) & DRIVER_SENSE) || - (status_byte (SCpnt->result) & CHECK_CONDITION)) && - ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) - { - if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) && - ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) && - ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST)) - { - return 0; - } - } - } - - return 1; +STATIC int scsi_unit_is_ready(Scsi_Cmnd * SCpnt) +{ + if (SCpnt->result) { + if (((driver_byte(SCpnt->result) & DRIVER_SENSE) || + (status_byte(SCpnt->result) & CHECK_CONDITION)) && + ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) { + if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) && + ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) && + ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST)) { + return 0; + } + } + } + return 1; } /* @@ -727,206 +697,190 @@ * a list of pending commands for final completion, and once we * are ready to leave error handling we handle completion for real. */ -STATIC void -scsi_eh_finish_command(Scsi_Cmnd **SClist, Scsi_Cmnd * SCpnt) +STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt) { - SCpnt->state = SCSI_STATE_BHQUEUE; - SCpnt->bh_next = *SClist; - /* - * Set this back so that the upper level can correctly free up - * things. - */ - SCpnt->use_sg = SCpnt->old_use_sg; - *SClist = SCpnt; + SCpnt->state = SCSI_STATE_BHQUEUE; + SCpnt->bh_next = *SClist; + /* + * Set this back so that the upper level can correctly free up + * things. + */ + SCpnt->use_sg = SCpnt->old_use_sg; + *SClist = SCpnt; } /* - * Function: scsi_try_to_abort_command + * Function: scsi_try_to_abort_command * - * Purpose: Ask host adapter to abort a running command. + * Purpose: Ask host adapter to abort a running command. * - * Returns: FAILED Operation failed or not supported. - * SUCCESS Succeeded. + * Returns: FAILED Operation failed or not supported. + * SUCCESS Succeeded. * - * Notes: This function will not return until the user's completion - * function has been called. There is no timeout on this + * Notes: This function will not return until the user's completion + * function has been called. There is no timeout on this * operation. If the author of the low-level driver wishes * this operation to be timed, they can provide this facility * themselves. Helper functions in scsi_error.c can be supplied * to make this easier to do. * - * Notes: It may be possible to combine this with all of the reset - * handling to eliminate a lot of code duplication. I don't - * know what makes more sense at the moment - this is just a - * prototype. + * Notes: It may be possible to combine this with all of the reset + * handling to eliminate a lot of code duplication. I don't + * know what makes more sense at the moment - this is just a + * prototype. */ -STATIC int -scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout) +STATIC int scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout) { - SCpnt->eh_state = FAILED; /* Until we come up with something better */ - - if( SCpnt->host->hostt->eh_abort_handler == NULL ) - { - return FAILED; - } + SCpnt->eh_state = FAILED; /* Until we come up with something better */ - /* - * scsi_done was called just after the command timed out and before - * we had a chance to process it. (DB) - */ - if (SCpnt->serial_number == 0) return SUCCESS; + if (SCpnt->host->hostt->eh_abort_handler == NULL) { + return FAILED; + } + /* + * scsi_done was called just after the command timed out and before + * we had a chance to process it. (DB) + */ + if (SCpnt->serial_number == 0) + return SUCCESS; - SCpnt->owner = SCSI_OWNER_LOWLEVEL; + SCpnt->owner = SCSI_OWNER_LOWLEVEL; - return SCpnt->host->hostt->eh_abort_handler(SCpnt); + return SCpnt->host->hostt->eh_abort_handler(SCpnt); } /* - * Function: scsi_try_bus_device_reset + * Function: scsi_try_bus_device_reset * - * Purpose: Ask host adapter to perform a bus device reset for a given - * device. + * Purpose: Ask host adapter to perform a bus device reset for a given + * device. * - * Returns: FAILED Operation failed or not supported. - * SUCCESS Succeeded. + * Returns: FAILED Operation failed or not supported. + * SUCCESS Succeeded. * - * Notes: There is no timeout for this operation. If this operation is + * Notes: There is no timeout for this operation. If this operation is * unreliable for a given host, then the host itself needs to put a * timer on it, and set the host back to a consistent state prior * to returning. */ -STATIC int -scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout) +STATIC int scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout) { - int rtn; + int rtn; + + SCpnt->eh_state = FAILED; /* Until we come up with something better */ - SCpnt->eh_state = FAILED; /* Until we come up with something better */ + if (SCpnt->host->hostt->eh_device_reset_handler == NULL) { + return FAILED; + } + SCpnt->owner = SCSI_OWNER_LOWLEVEL; - if( SCpnt->host->hostt->eh_device_reset_handler == NULL ) - { - return FAILED; - } - - SCpnt->owner = SCSI_OWNER_LOWLEVEL; - - rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt); + rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt); - if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS; + if (rtn == SUCCESS) + SCpnt->eh_state = SUCCESS; - return SCpnt->eh_state; + return SCpnt->eh_state; } /* - * Function: scsi_try_bus_reset + * Function: scsi_try_bus_reset * - * Purpose: Ask host adapter to perform a bus reset for a host. + * Purpose: Ask host adapter to perform a bus reset for a host. * - * Returns: FAILED Operation failed or not supported. - * SUCCESS Succeeded. + * Returns: FAILED Operation failed or not supported. + * SUCCESS Succeeded. * - * Notes: + * Notes: */ -STATIC int -scsi_try_bus_reset(Scsi_Cmnd * SCpnt) +STATIC int scsi_try_bus_reset(Scsi_Cmnd * SCpnt) { - int rtn; - - SCpnt->eh_state = FAILED; /* Until we come up with something better */ - SCpnt->owner = SCSI_OWNER_LOWLEVEL; - SCpnt->serial_number_at_timeout = SCpnt->serial_number; + int rtn; - if( SCpnt->host->hostt->eh_bus_reset_handler == NULL ) - { - return FAILED; - } + SCpnt->eh_state = FAILED; /* Until we come up with something better */ + SCpnt->owner = SCSI_OWNER_LOWLEVEL; + SCpnt->serial_number_at_timeout = SCpnt->serial_number; - rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt); + if (SCpnt->host->hostt->eh_bus_reset_handler == NULL) { + return FAILED; + } + rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt); - if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS; + if (rtn == SUCCESS) + SCpnt->eh_state = SUCCESS; - /* - * If we had a successful bus reset, mark the command blocks to expect - * a condition code of unit attention. - */ - scsi_sleep(BUS_RESET_SETTLE_TIME); - if( SCpnt->eh_state == SUCCESS ) - { - Scsi_Device * SDloop; - for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) - { - if( SCpnt->channel == SDloop->channel ) - { - SDloop->was_reset = 1; - SDloop->expecting_cc_ua = 1; - } + /* + * If we had a successful bus reset, mark the command blocks to expect + * a condition code of unit attention. + */ + scsi_sleep(BUS_RESET_SETTLE_TIME); + if (SCpnt->eh_state == SUCCESS) { + Scsi_Device *SDloop; + for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) { + if (SCpnt->channel == SDloop->channel) { + SDloop->was_reset = 1; + SDloop->expecting_cc_ua = 1; + } + } } - } - - return SCpnt->eh_state; + return SCpnt->eh_state; } /* - * Function: scsi_try_host_reset + * Function: scsi_try_host_reset * - * Purpose: Ask host adapter to reset itself, and the bus. + * Purpose: Ask host adapter to reset itself, and the bus. * - * Returns: FAILED Operation failed or not supported. - * SUCCESS Succeeded. + * Returns: FAILED Operation failed or not supported. + * SUCCESS Succeeded. * * Notes: */ -STATIC int -scsi_try_host_reset(Scsi_Cmnd * SCpnt) +STATIC int scsi_try_host_reset(Scsi_Cmnd * SCpnt) { - int rtn; + int rtn; - SCpnt->eh_state = FAILED; /* Until we come up with something better */ - SCpnt->owner = SCSI_OWNER_LOWLEVEL; - SCpnt->serial_number_at_timeout = SCpnt->serial_number; - - if( SCpnt->host->hostt->eh_host_reset_handler == NULL ) - { - return FAILED; - } - - rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt); - - if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS; - - /* - * If we had a successful host reset, mark the command blocks to expect - * a condition code of unit attention. - */ - scsi_sleep(HOST_RESET_SETTLE_TIME); - if( SCpnt->eh_state == SUCCESS ) - { - Scsi_Device * SDloop; - for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) - { - SDloop->was_reset = 1; - SDloop->expecting_cc_ua = 1; - } - } - - return SCpnt->eh_state; + SCpnt->eh_state = FAILED; /* Until we come up with something better */ + SCpnt->owner = SCSI_OWNER_LOWLEVEL; + SCpnt->serial_number_at_timeout = SCpnt->serial_number; + + if (SCpnt->host->hostt->eh_host_reset_handler == NULL) { + return FAILED; + } + rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt); + + if (rtn == SUCCESS) + SCpnt->eh_state = SUCCESS; + + /* + * If we had a successful host reset, mark the command blocks to expect + * a condition code of unit attention. + */ + scsi_sleep(HOST_RESET_SETTLE_TIME); + if (SCpnt->eh_state == SUCCESS) { + Scsi_Device *SDloop; + for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) { + SDloop->was_reset = 1; + SDloop->expecting_cc_ua = 1; + } + } + return SCpnt->eh_state; } /* - * Function: scsi_decide_disposition - * - * Purpose: Examine a command block that has come back from the low-level - * and figure out what to do next. - * - * Returns: SUCCESS - pass on to upper level. - * FAILED - pass on to error handler thread. - * RETRY - command should be retried. - * SOFTERR - command succeeded, but we need to log - * a soft error. - * - * Notes: This is *ONLY* called when we are examining the status - * after sending out the actual data command. Any commands - * that are queued for error recovery (i.e. TEST_UNIT_READY) - * do *NOT* come through here. + * Function: scsi_decide_disposition + * + * Purpose: Examine a command block that has come back from the low-level + * and figure out what to do next. + * + * Returns: SUCCESS - pass on to upper level. + * FAILED - pass on to error handler thread. + * RETRY - command should be retried. + * SOFTERR - command succeeded, but we need to log + * a soft error. + * + * Notes: This is *ONLY* called when we are examining the status + * after sending out the actual data command. Any commands + * that are queued for error recovery (i.e. TEST_UNIT_READY) + * do *NOT* come through here. * * NOTE - When this routine returns FAILED, it means the error * handler thread is woken. In cases where the error code @@ -934,419 +888,383 @@ * thread (i.e. we don't need to abort/reset), then this function * should return SUCCESS. */ -int scsi_decide_disposition (Scsi_Cmnd * SCpnt) +int scsi_decide_disposition(Scsi_Cmnd * SCpnt) { - int rtn; + int rtn; + + /* + * If the device is offline, then we clearly just pass the result back + * up to the top level. + */ + if (SCpnt->device->online == FALSE) { + SCSI_LOG_ERROR_RECOVERY(5, printk("scsi_error.c: device offline - report as SUCCESS\n")); + return SUCCESS; + } + /* + * First check the host byte, to see if there is anything in there + * that would indicate what we need to do. + */ + + switch (host_byte(SCpnt->result)) { + case DID_PASSTHROUGH: + /* + * No matter what, pass this through to the upper layer. + * Nuke this special code so that it looks like we are saying + * DID_OK. + */ + SCpnt->result &= 0xff00ffff; + return SUCCESS; + case DID_OK: + /* + * Looks good. Drop through, and check the next byte. + */ + break; + case DID_NO_CONNECT: + case DID_BAD_TARGET: + case DID_ABORT: + /* + * Note - this means that we just report the status back to the + * top level driver, not that we actually think that it indicates + * success. + */ + return SUCCESS; + /* + * When the low level driver returns DID_SOFT_ERROR, + * it is responsible for keeping an internal retry counter + * in order to avoid endless loops (DB) + */ + case DID_SOFT_ERROR: + return NEEDS_RETRY; + + case DID_BUS_BUSY: + case DID_PARITY: + case DID_ERROR: + goto maybe_retry; + case DID_TIME_OUT: + /* + * When we scan the bus, we get timeout messages for + * these commands if there is no device available. + * Other hosts report DID_NO_CONNECT for the same thing. + */ + if ((SCpnt->cmnd[0] == TEST_UNIT_READY || + SCpnt->cmnd[0] == INQUIRY)) { + return SUCCESS; + } else { + return FAILED; + } + case DID_RESET: + /* + * In the normal case where we haven't initiated a reset, this is + * a failure. + */ + if (SCpnt->flags & IS_RESETTING) { + SCpnt->flags &= ~IS_RESETTING; + goto maybe_retry; + } + /* + * Examine the sense data to figure out how to proceed from here. + * If there is no sense data, we will be forced into the error + * handler thread, where we get to examine the thing in a lot more + * detail. + */ + return scsi_check_sense(SCpnt); + default: + return FAILED; + } + + /* + * Next, check the message byte. + */ + if (msg_byte(SCpnt->result) != COMMAND_COMPLETE) { + return FAILED; + } + /* + * Now, check the status byte to see if this indicates anything special. + */ + switch (status_byte(SCpnt->result)) { + case QUEUE_FULL: + /* + * The case of trying to send too many commands to a tagged queueing + * device. + */ + return ADD_TO_MLQUEUE; + case GOOD: + case COMMAND_TERMINATED: + return SUCCESS; + case CHECK_CONDITION: + rtn = scsi_check_sense(SCpnt); + if (rtn == NEEDS_RETRY) { + goto maybe_retry; + } + return rtn; + case CONDITION_GOOD: + case INTERMEDIATE_GOOD: + case INTERMEDIATE_C_GOOD: + /* + * Who knows? FIXME(eric) + */ + return SUCCESS; + case BUSY: + case RESERVATION_CONFLICT: + goto maybe_retry; + default: + return FAILED; + } + return FAILED; + + maybe_retry: + + if ((++SCpnt->retries) < SCpnt->allowed) { + return NEEDS_RETRY; + } else { + return FAILED; + } +} - /* - * If the device is offline, then we clearly just pass the result back - * up to the top level. - */ - if( SCpnt->device->online == FALSE ) - { - SCSI_LOG_ERROR_RECOVERY(5,printk("scsi_error.c: device offline - report as SUCCESS\n")); - return SUCCESS; - } - - /* - * First check the host byte, to see if there is anything in there - * that would indicate what we need to do. - */ - - switch(host_byte(SCpnt->result)) - { - case DID_PASSTHROUGH: - /* - * No matter what, pass this through to the upper layer. - * Nuke this special code so that it looks like we are saying - * DID_OK. - */ - SCpnt->result &= 0xff00ffff; - return SUCCESS; - case DID_OK: - /* - * Looks good. Drop through, and check the next byte. - */ - break; - case DID_NO_CONNECT: - case DID_BAD_TARGET: - case DID_ABORT: - /* - * Note - this means that we just report the status back to the - * top level driver, not that we actually think that it indicates - * success. - */ - return SUCCESS; - /* - * When the low level driver returns DID_SOFT_ERROR, - * it is responsible for keeping an internal retry counter - * in order to avoid endless loops (DB) - */ - case DID_SOFT_ERROR: - return NEEDS_RETRY; - - case DID_BUS_BUSY: - case DID_PARITY: - case DID_ERROR: - goto maybe_retry; - case DID_TIME_OUT: - /* - * When we scan the bus, we get timeout messages for - * these commands if there is no device available. - * Other hosts report DID_NO_CONNECT for the same thing. - */ - if( (SCpnt->cmnd[0] == TEST_UNIT_READY || - SCpnt->cmnd[0] == INQUIRY) ) - { - return SUCCESS; - } - else - { - return FAILED; - } - case DID_RESET: - /* - * In the normal case where we haven't initiated a reset, this is - * a failure. - */ - if( SCpnt->flags & IS_RESETTING ) - { - SCpnt->flags &= ~IS_RESETTING; - goto maybe_retry; - } - - /* - * Examine the sense data to figure out how to proceed from here. - * If there is no sense data, we will be forced into the error - * handler thread, where we get to examine the thing in a lot more - * detail. - */ - return scsi_check_sense (SCpnt); - default: - return FAILED; - } - - /* - * Next, check the message byte. - */ - if( msg_byte(SCpnt->result) != COMMAND_COMPLETE ) - { - return FAILED; - } - - /* - * Now, check the status byte to see if this indicates anything special. - */ - switch (status_byte(SCpnt->result)) - { - case QUEUE_FULL: - /* - * The case of trying to send too many commands to a tagged queueing - * device. - */ - return ADD_TO_MLQUEUE; - case GOOD: - case COMMAND_TERMINATED: - return SUCCESS; - case CHECK_CONDITION: - rtn = scsi_check_sense(SCpnt); - if( rtn == NEEDS_RETRY ) - { - goto maybe_retry; - } - return rtn; - case CONDITION_GOOD: - case INTERMEDIATE_GOOD: - case INTERMEDIATE_C_GOOD: - /* - * Who knows? FIXME(eric) - */ - return SUCCESS; - case BUSY: - case RESERVATION_CONFLICT: - goto maybe_retry; - default: - return FAILED; - } - return FAILED; - -maybe_retry: - - if ((++SCpnt->retries) < SCpnt->allowed) - { - return NEEDS_RETRY; - } - else - { - return FAILED; - } -} - -/* - * Function: scsi_eh_completed_normally - * - * Purpose: Examine a command block that has come back from the low-level - * and figure out what to do next. - * - * Returns: SUCCESS - pass on to upper level. - * FAILED - pass on to error handler thread. - * RETRY - command should be retried. - * SOFTERR - command succeeded, but we need to log - * a soft error. - * - * Notes: This is *ONLY* called when we are examining the status - * of commands queued during error recovery. The main - * difference here is that we don't allow for the possibility - * of retries here, and we are a lot more restrictive about what +/* + * Function: scsi_eh_completed_normally + * + * Purpose: Examine a command block that has come back from the low-level + * and figure out what to do next. + * + * Returns: SUCCESS - pass on to upper level. + * FAILED - pass on to error handler thread. + * RETRY - command should be retried. + * SOFTERR - command succeeded, but we need to log + * a soft error. + * + * Notes: This is *ONLY* called when we are examining the status + * of commands queued during error recovery. The main + * difference here is that we don't allow for the possibility + * of retries here, and we are a lot more restrictive about what * we consider acceptable. */ -STATIC int scsi_eh_completed_normally (Scsi_Cmnd * SCpnt) +STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt) { - int rtn; - /* - * First check the host byte, to see if there is anything in there - * that would indicate what we need to do. - */ - if( host_byte(SCpnt->result) == DID_RESET ) - { - if (SCpnt->flags & IS_RESETTING ) - { - /* - * OK, this is normal. We don't know whether in fact the - * command in question really needs to be rerun or not - - * if this was the original data command then the answer is yes, - * otherwise we just flag it as success. - */ - SCpnt->flags &= ~IS_RESETTING; - return NEEDS_RETRY; - } - - /* - * Rats. We are already in the error handler, so we now get to try - * and figure out what to do next. If the sense is valid, we have - * a pretty good idea of what to do. If not, we mark it as failed. - */ - return scsi_check_sense (SCpnt); - } - - if(host_byte(SCpnt->result) != DID_OK ) - { - return FAILED; - } - - /* - * Next, check the message byte. - */ - if( msg_byte(SCpnt->result) != COMMAND_COMPLETE ) - { - return FAILED; - } - - /* - * Now, check the status byte to see if this indicates anything special. - */ - switch (status_byte(SCpnt->result)) - { - case GOOD: - case COMMAND_TERMINATED: - return SUCCESS; - case CHECK_CONDITION: - rtn = scsi_check_sense(SCpnt); - if( rtn == NEEDS_RETRY ) - { - return FAILED; - } - return rtn; - case CONDITION_GOOD: - case INTERMEDIATE_GOOD: - case INTERMEDIATE_C_GOOD: - /* - * Who knows? FIXME(eric) - */ - return SUCCESS; - case BUSY: - case QUEUE_FULL: - case RESERVATION_CONFLICT: - default: - return FAILED; - } - return FAILED; -} - -/* - * Function: scsi_check_sense + int rtn; + /* + * First check the host byte, to see if there is anything in there + * that would indicate what we need to do. + */ + if (host_byte(SCpnt->result) == DID_RESET) { + if (SCpnt->flags & IS_RESETTING) { + /* + * OK, this is normal. We don't know whether in fact the + * command in question really needs to be rerun or not - + * if this was the original data command then the answer is yes, + * otherwise we just flag it as success. + */ + SCpnt->flags &= ~IS_RESETTING; + return NEEDS_RETRY; + } + /* + * Rats. We are already in the error handler, so we now get to try + * and figure out what to do next. If the sense is valid, we have + * a pretty good idea of what to do. If not, we mark it as failed. + */ + return scsi_check_sense(SCpnt); + } + if (host_byte(SCpnt->result) != DID_OK) { + return FAILED; + } + /* + * Next, check the message byte. + */ + if (msg_byte(SCpnt->result) != COMMAND_COMPLETE) { + return FAILED; + } + /* + * Now, check the status byte to see if this indicates anything special. + */ + switch (status_byte(SCpnt->result)) { + case GOOD: + case COMMAND_TERMINATED: + return SUCCESS; + case CHECK_CONDITION: + rtn = scsi_check_sense(SCpnt); + if (rtn == NEEDS_RETRY) { + return FAILED; + } + return rtn; + case CONDITION_GOOD: + case INTERMEDIATE_GOOD: + case INTERMEDIATE_C_GOOD: + /* + * Who knows? FIXME(eric) + */ + return SUCCESS; + case BUSY: + case QUEUE_FULL: + case RESERVATION_CONFLICT: + default: + return FAILED; + } + return FAILED; +} + +/* + * Function: scsi_check_sense * - * Purpose: Examine sense information - give suggestion as to what - * we should do with it. + * Purpose: Examine sense information - give suggestion as to what + * we should do with it. */ -STATIC int scsi_check_sense (Scsi_Cmnd * SCpnt) +STATIC int scsi_check_sense(Scsi_Cmnd * SCpnt) { - if ( !scsi_sense_valid(SCpnt) ) - { - return FAILED; - } - - if (SCpnt->sense_buffer[2] & 0xe0) - return SUCCESS; - - switch (SCpnt->sense_buffer[2] & 0xf) - { - case NO_SENSE: - return SUCCESS; - case RECOVERED_ERROR: - return /* SOFT_ERROR */ SUCCESS; - - case ABORTED_COMMAND: - return NEEDS_RETRY; - case NOT_READY: - case UNIT_ATTENTION: - /* - * If we are expecting a CC/UA because of a bus reset that we - * performed, treat this just as a retry. Otherwise this is - * information that we should pass up to the upper-level driver - * so that we can deal with it there. - */ - if( SCpnt->device->expecting_cc_ua ) - { - SCpnt->device->expecting_cc_ua = 0; - return NEEDS_RETRY; - } - return SUCCESS; - - /* these three are not supported */ - case COPY_ABORTED: - case VOLUME_OVERFLOW: - case MISCOMPARE: - return SUCCESS; - - case MEDIUM_ERROR: - return NEEDS_RETRY; + if (!scsi_sense_valid(SCpnt)) { + return FAILED; + } + if (SCpnt->sense_buffer[2] & 0xe0) + return SUCCESS; - case ILLEGAL_REQUEST: - case BLANK_CHECK: - case DATA_PROTECT: - case HARDWARE_ERROR: - default: - return SUCCESS; - } + switch (SCpnt->sense_buffer[2] & 0xf) { + case NO_SENSE: + return SUCCESS; + case RECOVERED_ERROR: + return /* SOFT_ERROR */ SUCCESS; + + case ABORTED_COMMAND: + return NEEDS_RETRY; + case NOT_READY: + case UNIT_ATTENTION: + /* + * If we are expecting a CC/UA because of a bus reset that we + * performed, treat this just as a retry. Otherwise this is + * information that we should pass up to the upper-level driver + * so that we can deal with it there. + */ + if (SCpnt->device->expecting_cc_ua) { + SCpnt->device->expecting_cc_ua = 0; + return NEEDS_RETRY; + } + return SUCCESS; + + /* these three are not supported */ + case COPY_ABORTED: + case VOLUME_OVERFLOW: + case MISCOMPARE: + return SUCCESS; + + case MEDIUM_ERROR: + return NEEDS_RETRY; + + case ILLEGAL_REQUEST: + case BLANK_CHECK: + case DATA_PROTECT: + case HARDWARE_ERROR: + default: + return SUCCESS; + } } /* - * Function: scsi_restart_operations + * Function: scsi_restart_operations * - * Purpose: Restart IO operations to the specified host. + * Purpose: Restart IO operations to the specified host. * - * Arguments: host - host that we are restarting + * Arguments: host - host that we are restarting * - * Returns: Nothing + * Returns: Nothing * - * Notes: When we entered the error handler, we blocked all further - * I/O to this device. We need to 'reverse' this process. + * Notes: When we entered the error handler, we blocked all further + * I/O to this device. We need to 'reverse' this process. */ -STATIC void -scsi_restart_operations(struct Scsi_Host * host) +STATIC void scsi_restart_operations(struct Scsi_Host *host) { - Scsi_Device * SDpnt; + Scsi_Device *SDpnt; - /* - * Next free up anything directly waiting upon the host. This will be - * requests for character device operations, and also for ioctls to queued - * block devices. - */ - SCSI_LOG_ERROR_RECOVERY(5,printk("scsi_error.c: Waking up host to restart\n")); + /* + * Next free up anything directly waiting upon the host. This will be + * requests for character device operations, and also for ioctls to queued + * block devices. + */ + SCSI_LOG_ERROR_RECOVERY(5, printk("scsi_error.c: Waking up host to restart\n")); - wake_up(&host->host_wait); + wake_up(&host->host_wait); - /* - * Finally, block devices need an extra kick in the pants. This is because - * the request queueing mechanism may have queued lots of pending requests - * and there won't be a process waiting in a place where we can simply wake - * it up. Thus we simply go through and call the request function to goose - * the various top level drivers and get things moving again. - */ - for( SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next ) - { - SCSI_LOG_ERROR_RECOVERY(5,printk("Calling request function to restart things...\n")); + /* + * Finally, block devices need an extra kick in the pants. This is because + * the request queueing mechanism may have queued lots of pending requests + * and there won't be a process waiting in a place where we can simply wake + * it up. Thus we simply go through and call the request function to goose + * the various top level drivers and get things moving again. + */ + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + SCSI_LOG_ERROR_RECOVERY(5, printk("Calling request function to restart things...\n")); - if( SDpnt->scsi_request_fn != NULL ) - (*SDpnt->scsi_request_fn)(); - } + if (SDpnt->scsi_request_fn != NULL) + (*SDpnt->scsi_request_fn) (); + } } /* - * Function: scsi_unjam_host + * Function: scsi_unjam_host * - * Purpose: Attempt to fix a host which has a command that failed for - * some reason. + * Purpose: Attempt to fix a host which has a command that failed for + * some reason. * - * Arguments: host - host that needs unjamming. + * Arguments: host - host that needs unjamming. * - * Returns: Nothing + * Returns: Nothing * - * Notes: When we come in here, we *know* that all commands on the - * bus have either completed, failed or timed out. We also - * know that no further commands are being sent to the host, - * so things are relatively quiet and we have freedom to - * fiddle with things as we wish. + * Notes: When we come in here, we *know* that all commands on the + * bus have either completed, failed or timed out. We also + * know that no further commands are being sent to the host, + * so things are relatively quiet and we have freedom to + * fiddle with things as we wish. * * Additional note: This is only the *default* implementation. It is possible - * for individual drivers to supply their own version of this - * function, and if the maintainer wishes to do this, it is - * strongly suggested that this function be taken as a template - * and modified. This function was designed to correctly handle - * problems for about 95% of the different cases out there, and - * it should always provide at least a reasonable amount of error - * recovery. + * for individual drivers to supply their own version of this + * function, and if the maintainer wishes to do this, it is + * strongly suggested that this function be taken as a template + * and modified. This function was designed to correctly handle + * problems for about 95% of the different cases out there, and + * it should always provide at least a reasonable amount of error + * recovery. * * Note3: Any command marked 'FAILED' or 'TIMEOUT' must eventually * have scsi_finish_command() called for it. We do all of * the retry stuff here, so when we restart the host after we * return it should have an empty queue. */ -STATIC int -scsi_unjam_host(struct Scsi_Host * host) +STATIC int scsi_unjam_host(struct Scsi_Host *host) { - int devices_failed; - int numfailed; - int ourrtn; - int rtn = FALSE; - int result; - Scsi_Cmnd * SCloop; - Scsi_Cmnd * SCpnt; - Scsi_Device * SDpnt; - Scsi_Device * SDloop; - Scsi_Cmnd * SCdone; - int timed_out; - - SCdone = NULL; - - /* - * First, protect against any sort of race condition. If any of the outstanding - * commands are in states that indicate that we are not yet blocked (i.e. we are - * not in a quiet state) then we got woken up in error. If we ever end up here, - * we need to re-examine some of the assumptions. - */ - for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) - { - if( SCpnt->state == SCSI_STATE_FAILED - || SCpnt->state == SCSI_STATE_TIMEOUT - || SCpnt->state == SCSI_STATE_INITIALIZING - || SCpnt->state == SCSI_STATE_UNUSED) - { - continue; - } - - /* - * Rats. Something is still floating around out there. This could - * be the result of the fact that the upper level drivers are still frobbing - * commands that might have succeeded. There are two outcomes. One is that - * the command block will eventually be freed, and the other one is that - * the command will be queued and will be finished along the way. - */ - SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target)); + int devices_failed; + int numfailed; + int ourrtn; + int rtn = FALSE; + int result; + Scsi_Cmnd *SCloop; + Scsi_Cmnd *SCpnt; + Scsi_Device *SDpnt; + Scsi_Device *SDloop; + Scsi_Cmnd *SCdone; + int timed_out; + + SCdone = NULL; + + /* + * First, protect against any sort of race condition. If any of the outstanding + * commands are in states that indicate that we are not yet blocked (i.e. we are + * not in a quiet state) then we got woken up in error. If we ever end up here, + * we need to re-examine some of the assumptions. + */ + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { + if (SCpnt->state == SCSI_STATE_FAILED + || SCpnt->state == SCSI_STATE_TIMEOUT + || SCpnt->state == SCSI_STATE_INITIALIZING + || SCpnt->state == SCSI_STATE_UNUSED) { + continue; + } + /* + * Rats. Something is still floating around out there. This could + * be the result of the fact that the upper level drivers are still frobbing + * commands that might have succeeded. There are two outcomes. One is that + * the command block will eventually be freed, and the other one is that + * the command will be queued and will be finished along the way. + */ + SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target)); /* * panic("SCSI Error handler woken too early\n"); @@ -1365,572 +1283,486 @@ * state=SCSI_STATE_INITIALIZING and the driver module cannot be released. * (DB, 17 May 1998) */ - } - } + } + } + + /* + * Next, see if we need to request sense information. if so, + * then get it now, so we have a better idea of what to do. + * FIXME(eric) this has the unfortunate side effect that if a host + * adapter does not automatically request sense information, that we end + * up shutting it down before we request it. All hosts should be doing this + * anyways, so for now all I have to say is tough noogies if you end up in here. + * On second thought, this is probably a good idea. We *really* want to give + * authors an incentive to automatically request this. + */ + SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we need to request sense\n")); - /* - * Next, see if we need to request sense information. if so, - * then get it now, so we have a better idea of what to do. - * FIXME(eric) this has the unfortunate side effect that if a host - * adapter does not automatically request sense information, that we end - * up shutting it down before we request it. All hosts should be doing this - * anyways, so for now all I have to say is tough noogies if you end up in here. - * On second thought, this is probably a good idea. We *really* want to give - * authors an incentive to automatically request this. - */ - SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we need to request sense\n")); - - for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) - { - if( SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt) ) - { - continue; - } - - SCSI_LOG_ERROR_RECOVERY(2,printk("scsi_unjam_host: Requesting sense for %d\n", - SCpnt->target)); - rtn = scsi_request_sense(SCpnt); - if( rtn != SUCCESS ) - { - continue; - } - - SCSI_LOG_ERROR_RECOVERY(3,printk("Sense requested for %p - result %x\n", - SCpnt, SCpnt->result)); - SCSI_LOG_ERROR_RECOVERY(3,print_sense("bh",SCpnt)); - - result = scsi_decide_disposition(SCpnt); - - /* - * If the result was normal, then just pass it along to the - * upper level. - */ - if( result == SUCCESS ) - { - SCpnt->host->host_failed--; - scsi_eh_finish_command(&SCdone, SCpnt); - } - - if( result != NEEDS_RETRY ) - { - continue; - } - - /* - * We only come in here if we want to retry a - * command. The test to see whether the command - * should be retried should be keeping track of the - * number of tries, so we don't end up looping, of - * course. - */ - SCpnt->state = NEEDS_RETRY; - rtn = scsi_eh_retry_command(SCpnt); - if( rtn != SUCCESS ) - { - continue; - } - - /* - * We eventually hand this one back to the top level. - */ - SCpnt->host->host_failed--; - scsi_eh_finish_command(&SCdone, SCpnt); - } - } - - /* - * Go through the list of commands and figure out where we stand and how bad things - * really are. - */ - numfailed = 0; - timed_out = 0; - devices_failed = 0; - for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - unsigned int device_error = 0; - - for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) - { - if( SCpnt->state == SCSI_STATE_FAILED ) - { - SCSI_LOG_ERROR_RECOVERY(5,printk("Command to ID %d failed\n", - SCpnt->target)); - numfailed++; - device_error++; - } - if( SCpnt->state == SCSI_STATE_TIMEOUT ) - { - SCSI_LOG_ERROR_RECOVERY(5,printk("Command to ID %d timedout\n", - SCpnt->target)); - timed_out++; - device_error++; - } - } - if( device_error > 0 ) - { - devices_failed++; - } - } - - SCSI_LOG_ERROR_RECOVERY(2,printk("Total of %d+%d commands on %d devices require eh work\n", - numfailed, timed_out, devices_failed)); - - if( host->host_failed == 0 ) - { - ourrtn = TRUE; - goto leave; - } - - - /* - * Next, try and see whether or not it makes sense to try and abort - * the running command. This only works out to be the case if we have - * one command that has timed out. If the command simply failed, it - * makes no sense to try and abort the command, since as far as the - * host adapter is concerned, it isn't running. - */ - - SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we want to try abort\n")); - - for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next) - { - if( SCloop->state != SCSI_STATE_TIMEOUT ) - { - continue; - } - - rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT); - if( rtn == SUCCESS ) - { - rtn = scsi_test_unit_ready(SCloop); - - if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) ) - { - rtn = scsi_eh_retry_command(SCloop); - - if( rtn == SUCCESS ) - { - SCloop->host->host_failed--; - scsi_eh_finish_command(&SCdone,SCloop); - } - } - } - } - } - - /* - * If we have corrected all of the problems, then we are done. - */ - if( host->host_failed == 0 ) - { - ourrtn = TRUE; - goto leave; - } - - /* - * Either the abort wasn't appropriate, or it didn't succeed. - * Now try a bus device reset. Still, look to see whether we have - * multiple devices that are jammed or not - if we have multiple devices, - * it makes no sense to try BUS_DEVICE_RESET - we really would need - * to try a BUS_RESET instead. - * - * Does this make sense - should we try BDR on each device individually? - * Yes, definitely. - */ - SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we want to try BDR\n")); - - for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next) - { - if( SCloop->state == SCSI_STATE_FAILED - || SCloop->state == SCSI_STATE_TIMEOUT ) - { - break; - } - } - - if( SCloop == NULL ) - { - continue; - } - - /* - * OK, we have a device that is having problems. Try and send - * a bus device reset to it. - * - * FIXME(eric) - make sure we handle the case where multiple - * commands to the same device have failed. They all must - * get properly restarted. - */ - rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT); - - if( rtn == SUCCESS ) - { - rtn = scsi_test_unit_ready(SCloop); - - if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) ) - { - rtn = scsi_eh_retry_command(SCloop); - - if( rtn == SUCCESS ) - { - SCloop->host->host_failed--; - scsi_eh_finish_command(&SCdone,SCloop); - } - } - } - - } - - if( host->host_failed == 0 ) - { - ourrtn = TRUE; - goto leave; - } - - /* - * If we ended up here, we have serious problems. The only thing left - * to try is a full bus reset. If someone has grabbed the bus and isn't - * letting go, then perhaps this will help. - */ - SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Try hard bus reset\n")); - - /* - * We really want to loop over the various channels, and do this on - * a channel by channel basis. We should also check to see if any - * of the failed commands are on soft_reset devices, and if so, skip - * the reset. - */ - for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) - { -next_device: - for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) - { - if( SCpnt->state != SCSI_STATE_FAILED - && SCpnt->state != SCSI_STATE_TIMEOUT ) - { - continue; - } - /* - * We have a failed command. Make sure there are no other failed - * commands on the same channel that are timed out and implement a - * soft reset. - */ - for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next) - { - for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next) - { - if( SCloop->channel != SCpnt->channel ) - { - continue; - } - - if( SCloop->state != SCSI_STATE_FAILED - && SCloop->state != SCSI_STATE_TIMEOUT ) - { - continue; - } - - if( SDloop->soft_reset && SCloop->state == SCSI_STATE_TIMEOUT ) - { - /* - * If this device uses the soft reset option, and this - * is one of the devices acting up, then our only - * option is to wait a bit, since the command is - * supposedly still running. - * - * FIXME(eric) - right now we will just end up falling - * through to the 'take device offline' case. - * - * FIXME(eric) - It is possible that the command completed - * *after* the error recovery procedure started, and if this - * is the case, we are worrying about nothing here. - */ - - /* - * Due to the spinlock, we will never get out of this - * loop without a proper wait (DB) - */ - scsi_sleep(1 * HZ); - - goto next_device; - } - } - } - - /* - * We now know that we are able to perform a reset for the - * bus that SCpnt points to. There are no soft-reset devices - * with outstanding timed out commands. - */ - rtn = scsi_try_bus_reset(SCpnt); - if( rtn == SUCCESS ) - { - for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next) - { - for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next) - { - if( SCloop->channel != SCpnt->channel ) - { - continue; - } - - if( SCloop->state != SCSI_STATE_FAILED - && SCloop->state != SCSI_STATE_TIMEOUT ) - { - continue; - } - - rtn = scsi_test_unit_ready(SCloop); - - if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) ) - { - rtn = scsi_eh_retry_command(SCloop); - - if( rtn == SUCCESS ) - { - SCpnt->host->host_failed--; - scsi_eh_finish_command(&SCdone,SCloop); - } - } - - /* - * If the bus reset worked, but we are still unable to - * talk to the device, take it offline. - * FIXME(eric) - is this really the correct thing to do? - */ - if( rtn != SUCCESS ) - { - SCloop->device->online = FALSE; - SCloop->host->host_failed--; - scsi_eh_finish_command(&SCdone,SCloop); - } - } - } - } - } - } - - if( host->host_failed == 0 ) - { - ourrtn = TRUE; - goto leave; - } - /* - * If we ended up here, we have serious problems. The only thing left - * to try is a full host reset - perhaps the firmware on the device - * crashed, or something like that. - * - * It is assumed that a succesful host reset will cause *all* information - * about the command to be flushed from both the host adapter *and* the - * device. - * - * FIXME(eric) - it isn't clear that devices that implement the soft reset - * option can ever be cleared except via cycling the power. The problem is - * that sending the host reset command will cause the host to forget - * about the pending command, but the device won't forget. For now, we - * skip the host reset option if any of the failed devices are configured - * to use the soft reset option. - */ - for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) - { -next_device2: - for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) - { - if( SCpnt->state != SCSI_STATE_FAILED - && SCpnt->state != SCSI_STATE_TIMEOUT ) - { - continue; - } - if( SDpnt->soft_reset && SCpnt->state == SCSI_STATE_TIMEOUT ) - { - /* - * If this device uses the soft reset option, and this - * is one of the devices acting up, then our only - * option is to wait a bit, since the command is - * supposedly still running. - * - * FIXME(eric) - right now we will just end up falling - * through to the 'take device offline' case. - */ - SCSI_LOG_ERROR_RECOVERY(3, - printk("scsi_unjam_host: Unable to try hard host reset\n")); - - /* - * Due to the spinlock, we will never get out of this - * loop without a proper wait. (DB) - */ - scsi_sleep(1 * HZ); - - goto next_device2; - } - - SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Try hard host reset\n")); - - /* - * FIXME(eric) - we need to obtain a valid SCpnt to perform this call. - */ - rtn = scsi_try_host_reset(SCpnt); - if( rtn == SUCCESS ) - { - /* - * FIXME(eric) we assume that all commands are flushed from the - * controller. We should get a DID_RESET for all of the commands - * that were pending. We should ignore these so that we can - * guarantee that we are in a consistent state. - * - * I believe this to be the case right now, but this needs to be - * tested. - */ - for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next) - { - for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next) - { - if( SCloop->state != SCSI_STATE_FAILED - && SCloop->state != SCSI_STATE_TIMEOUT ) - { - continue; - } - - rtn = scsi_test_unit_ready(SCloop); - - if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) ) - { - rtn = scsi_eh_retry_command(SCloop); - - if( rtn == SUCCESS ) - { - SCpnt->host->host_failed--; - scsi_eh_finish_command(&SCdone,SCloop); - } - } - if( rtn != SUCCESS ) - { - SCloop->device->online = FALSE; - SCloop->host->host_failed--; - scsi_eh_finish_command(&SCdone,SCloop); - } - } - } - } - } - } - - /* - * If we solved all of the problems, then let's rev up the engines again. - */ - if( host->host_failed == 0 ) - { - ourrtn = TRUE; - goto leave; - } - - /* - * If the HOST RESET failed, then for now we assume that the entire host - * adapter is too hosed to be of any use. For our purposes, however, it is - * easier to simply take the devices offline that correspond to commands - * that failed. - */ - SCSI_LOG_ERROR_RECOVERY(1,printk("scsi_unjam_host: Take device offline\n")); - - for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next) - { - if( SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT ) - { - SCloop->device->online = FALSE; - - /* - * This should pass the failure up to the top level driver, and - * it will have to try and do something intelligent with it. - */ - SCloop->host->host_failed--; - - if( SCloop->state == SCSI_STATE_TIMEOUT ) - { - SCloop->result |= (DRIVER_TIMEOUT << 24); - } - - SCSI_LOG_ERROR_RECOVERY(3,printk("Finishing command for device %d %x\n", - SCloop->device->id, SCloop->result)); - - scsi_eh_finish_command(&SCdone,SCloop); - } - } - } - - if( host->host_failed != 0 ) - { - panic("scsi_unjam_host: Miscount of number of failed commands.\n"); - } - - SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Returning\n")); - - ourrtn = FALSE; - -leave: - - /* - * We should have a list of commands that we 'finished' during the course of - * error recovery. This should be the same as the list of commands that timed out - * or failed. We are currently holding these things in a linked list - we didn't - * put them in the bottom half queue because we wanted to keep things quiet while - * we were working on recovery, and passing them up to the top level could easily - * cause the top level to try and queue something else again. - * - * Start by marking that the host is no longer in error recovery. - */ - host->in_recovery = 0; - - /* - * Take the list of commands, and stick them in the bottom half queue. - * The current implementation of scsi_done will do this for us - if need - * be we can create a special version of this function to do the - * same job for us. - */ - for(SCpnt = SCdone; SCpnt != NULL; SCpnt = SCdone) - { - SCdone = SCpnt->bh_next; - SCpnt->bh_next = NULL; - scsi_done(SCpnt); - } - - return (ourrtn); -} - - -/* - * Function: scsi_error_handler - * - * Purpose: Handle errors/timeouts of scsi commands, try and clean up - * and unjam the bus, and restart things. - * - * Arguments: host - host for which we are running. - * - * Returns: Never returns. - * - * Notes: This is always run in the context of a kernel thread. The - * idea is that we start this thing up when the kernel starts - * up (one per host that we detect), and it immediately goes to - * sleep and waits for some event (i.e. failure). When this - * takes place, we have the job of trying to unjam the bus - * and restarting things. - * - */ -void -scsi_error_handler(void * data) -{ - struct Scsi_Host * host = (struct Scsi_Host *) data; - int rtn; - DECLARE_MUTEX_LOCKED(sem); - unsigned long flags; - struct fs_struct *fs; + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { + if (SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt)) { + continue; + } + SCSI_LOG_ERROR_RECOVERY(2, printk("scsi_unjam_host: Requesting sense for %d\n", + SCpnt->target)); + rtn = scsi_request_sense(SCpnt); + if (rtn != SUCCESS) { + continue; + } + SCSI_LOG_ERROR_RECOVERY(3, printk("Sense requested for %p - result %x\n", + SCpnt, SCpnt->result)); + SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", SCpnt)); + + result = scsi_decide_disposition(SCpnt); + + /* + * If the result was normal, then just pass it along to the + * upper level. + */ + if (result == SUCCESS) { + SCpnt->host->host_failed--; + scsi_eh_finish_command(&SCdone, SCpnt); + } + if (result != NEEDS_RETRY) { + continue; + } + /* + * We only come in here if we want to retry a + * command. The test to see whether the command + * should be retried should be keeping track of the + * number of tries, so we don't end up looping, of + * course. + */ + SCpnt->state = NEEDS_RETRY; + rtn = scsi_eh_retry_command(SCpnt); + if (rtn != SUCCESS) { + continue; + } + /* + * We eventually hand this one back to the top level. + */ + SCpnt->host->host_failed--; + scsi_eh_finish_command(&SCdone, SCpnt); + } + } + + /* + * Go through the list of commands and figure out where we stand and how bad things + * really are. + */ + numfailed = 0; + timed_out = 0; + devices_failed = 0; + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + unsigned int device_error = 0; + + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { + if (SCpnt->state == SCSI_STATE_FAILED) { + SCSI_LOG_ERROR_RECOVERY(5, printk("Command to ID %d failed\n", + SCpnt->target)); + numfailed++; + device_error++; + } + if (SCpnt->state == SCSI_STATE_TIMEOUT) { + SCSI_LOG_ERROR_RECOVERY(5, printk("Command to ID %d timedout\n", + SCpnt->target)); + timed_out++; + device_error++; + } + } + if (device_error > 0) { + devices_failed++; + } + } + + SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d+%d commands on %d devices require eh work\n", + numfailed, timed_out, devices_failed)); + + if (host->host_failed == 0) { + ourrtn = TRUE; + goto leave; + } + /* + * Next, try and see whether or not it makes sense to try and abort + * the running command. This only works out to be the case if we have + * one command that has timed out. If the command simply failed, it + * makes no sense to try and abort the command, since as far as the + * host adapter is concerned, it isn't running. + */ + + SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we want to try abort\n")); + + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) { + if (SCloop->state != SCSI_STATE_TIMEOUT) { + continue; + } + rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT); + if (rtn == SUCCESS) { + rtn = scsi_test_unit_ready(SCloop); + + if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) { + rtn = scsi_eh_retry_command(SCloop); + + if (rtn == SUCCESS) { + SCloop->host->host_failed--; + scsi_eh_finish_command(&SCdone, SCloop); + } + } + } + } + } + + /* + * If we have corrected all of the problems, then we are done. + */ + if (host->host_failed == 0) { + ourrtn = TRUE; + goto leave; + } + /* + * Either the abort wasn't appropriate, or it didn't succeed. + * Now try a bus device reset. Still, look to see whether we have + * multiple devices that are jammed or not - if we have multiple devices, + * it makes no sense to try BUS_DEVICE_RESET - we really would need + * to try a BUS_RESET instead. + * + * Does this make sense - should we try BDR on each device individually? + * Yes, definitely. + */ + SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we want to try BDR\n")); + + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) { + if (SCloop->state == SCSI_STATE_FAILED + || SCloop->state == SCSI_STATE_TIMEOUT) { + break; + } + } + + if (SCloop == NULL) { + continue; + } + /* + * OK, we have a device that is having problems. Try and send + * a bus device reset to it. + * + * FIXME(eric) - make sure we handle the case where multiple + * commands to the same device have failed. They all must + * get properly restarted. + */ + rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT); + + if (rtn == SUCCESS) { + rtn = scsi_test_unit_ready(SCloop); + + if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) { + rtn = scsi_eh_retry_command(SCloop); + + if (rtn == SUCCESS) { + SCloop->host->host_failed--; + scsi_eh_finish_command(&SCdone, SCloop); + } + } + } + } + + if (host->host_failed == 0) { + ourrtn = TRUE; + goto leave; + } + /* + * If we ended up here, we have serious problems. The only thing left + * to try is a full bus reset. If someone has grabbed the bus and isn't + * letting go, then perhaps this will help. + */ + SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard bus reset\n")); + + /* + * We really want to loop over the various channels, and do this on + * a channel by channel basis. We should also check to see if any + * of the failed commands are on soft_reset devices, and if so, skip + * the reset. + */ + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + next_device: + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { + if (SCpnt->state != SCSI_STATE_FAILED + && SCpnt->state != SCSI_STATE_TIMEOUT) { + continue; + } + /* + * We have a failed command. Make sure there are no other failed + * commands on the same channel that are timed out and implement a + * soft reset. + */ + for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) { + for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) { + if (SCloop->channel != SCpnt->channel) { + continue; + } + if (SCloop->state != SCSI_STATE_FAILED + && SCloop->state != SCSI_STATE_TIMEOUT) { + continue; + } + if (SDloop->soft_reset && SCloop->state == SCSI_STATE_TIMEOUT) { + /* + * If this device uses the soft reset option, and this + * is one of the devices acting up, then our only + * option is to wait a bit, since the command is + * supposedly still running. + * + * FIXME(eric) - right now we will just end up falling + * through to the 'take device offline' case. + * + * FIXME(eric) - It is possible that the command completed + * *after* the error recovery procedure started, and if this + * is the case, we are worrying about nothing here. + */ + + /* + * Due to the spinlock, we will never get out of this + * loop without a proper wait (DB) + */ + scsi_sleep(1 * HZ); + + goto next_device; + } + } + } + + /* + * We now know that we are able to perform a reset for the + * bus that SCpnt points to. There are no soft-reset devices + * with outstanding timed out commands. + */ + rtn = scsi_try_bus_reset(SCpnt); + if (rtn == SUCCESS) { + for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) { + for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) { + if (SCloop->channel != SCpnt->channel) { + continue; + } + if (SCloop->state != SCSI_STATE_FAILED + && SCloop->state != SCSI_STATE_TIMEOUT) { + continue; + } + rtn = scsi_test_unit_ready(SCloop); + + if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) { + rtn = scsi_eh_retry_command(SCloop); + + if (rtn == SUCCESS) { + SCpnt->host->host_failed--; + scsi_eh_finish_command(&SCdone, SCloop); + } + } + /* + * If the bus reset worked, but we are still unable to + * talk to the device, take it offline. + * FIXME(eric) - is this really the correct thing to do? + */ + if (rtn != SUCCESS) { + SCloop->device->online = FALSE; + SCloop->host->host_failed--; + scsi_eh_finish_command(&SCdone, SCloop); + } + } + } + } + } + } + + if (host->host_failed == 0) { + ourrtn = TRUE; + goto leave; + } + /* + * If we ended up here, we have serious problems. The only thing left + * to try is a full host reset - perhaps the firmware on the device + * crashed, or something like that. + * + * It is assumed that a succesful host reset will cause *all* information + * about the command to be flushed from both the host adapter *and* the + * device. + * + * FIXME(eric) - it isn't clear that devices that implement the soft reset + * option can ever be cleared except via cycling the power. The problem is + * that sending the host reset command will cause the host to forget + * about the pending command, but the device won't forget. For now, we + * skip the host reset option if any of the failed devices are configured + * to use the soft reset option. + */ + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + next_device2: + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { + if (SCpnt->state != SCSI_STATE_FAILED + && SCpnt->state != SCSI_STATE_TIMEOUT) { + continue; + } + if (SDpnt->soft_reset && SCpnt->state == SCSI_STATE_TIMEOUT) { + /* + * If this device uses the soft reset option, and this + * is one of the devices acting up, then our only + * option is to wait a bit, since the command is + * supposedly still running. + * + * FIXME(eric) - right now we will just end up falling + * through to the 'take device offline' case. + */ + SCSI_LOG_ERROR_RECOVERY(3, + printk("scsi_unjam_host: Unable to try hard host reset\n")); + + /* + * Due to the spinlock, we will never get out of this + * loop without a proper wait. (DB) + */ + scsi_sleep(1 * HZ); + + goto next_device2; + } + SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard host reset\n")); + + /* + * FIXME(eric) - we need to obtain a valid SCpnt to perform this call. + */ + rtn = scsi_try_host_reset(SCpnt); + if (rtn == SUCCESS) { + /* + * FIXME(eric) we assume that all commands are flushed from the + * controller. We should get a DID_RESET for all of the commands + * that were pending. We should ignore these so that we can + * guarantee that we are in a consistent state. + * + * I believe this to be the case right now, but this needs to be + * tested. + */ + for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) { + for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) { + if (SCloop->state != SCSI_STATE_FAILED + && SCloop->state != SCSI_STATE_TIMEOUT) { + continue; + } + rtn = scsi_test_unit_ready(SCloop); + + if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) { + rtn = scsi_eh_retry_command(SCloop); + + if (rtn == SUCCESS) { + SCpnt->host->host_failed--; + scsi_eh_finish_command(&SCdone, SCloop); + } + } + if (rtn != SUCCESS) { + SCloop->device->online = FALSE; + SCloop->host->host_failed--; + scsi_eh_finish_command(&SCdone, SCloop); + } + } + } + } + } + } + + /* + * If we solved all of the problems, then let's rev up the engines again. + */ + if (host->host_failed == 0) { + ourrtn = TRUE; + goto leave; + } + /* + * If the HOST RESET failed, then for now we assume that the entire host + * adapter is too hosed to be of any use. For our purposes, however, it is + * easier to simply take the devices offline that correspond to commands + * that failed. + */ + SCSI_LOG_ERROR_RECOVERY(1, printk("scsi_unjam_host: Take device offline\n")); + + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) { + if (SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT) { + SCloop->device->online = FALSE; + + /* + * This should pass the failure up to the top level driver, and + * it will have to try and do something intelligent with it. + */ + SCloop->host->host_failed--; + + if (SCloop->state == SCSI_STATE_TIMEOUT) { + SCloop->result |= (DRIVER_TIMEOUT << 24); + } + SCSI_LOG_ERROR_RECOVERY(3, printk("Finishing command for device %d %x\n", + SCloop->device->id, SCloop->result)); + + scsi_eh_finish_command(&SCdone, SCloop); + } + } + } + + if (host->host_failed != 0) { + panic("scsi_unjam_host: Miscount of number of failed commands.\n"); + } + SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Returning\n")); + + ourrtn = FALSE; + + leave: + + /* + * We should have a list of commands that we 'finished' during the course of + * error recovery. This should be the same as the list of commands that timed out + * or failed. We are currently holding these things in a linked list - we didn't + * put them in the bottom half queue because we wanted to keep things quiet while + * we were working on recovery, and passing them up to the top level could easily + * cause the top level to try and queue something else again. + * + * Start by marking that the host is no longer in error recovery. + */ + host->in_recovery = 0; + + /* + * Take the list of commands, and stick them in the bottom half queue. + * The current implementation of scsi_done will do this for us - if need + * be we can create a special version of this function to do the + * same job for us. + */ + for (SCpnt = SCdone; SCpnt != NULL; SCpnt = SCdone) { + SCdone = SCpnt->bh_next; + SCpnt->bh_next = NULL; + scsi_done(SCpnt); + } + + return (ourrtn); +} + + +/* + * Function: scsi_error_handler + * + * Purpose: Handle errors/timeouts of scsi commands, try and clean up + * and unjam the bus, and restart things. + * + * Arguments: host - host for which we are running. + * + * Returns: Never returns. + * + * Notes: This is always run in the context of a kernel thread. The + * idea is that we start this thing up when the kernel starts + * up (one per host that we detect), and it immediately goes to + * sleep and waits for some event (i.e. failure). When this + * takes place, we have the job of trying to unjam the bus + * and restarting things. + * + */ +void scsi_error_handler(void *data) +{ + struct Scsi_Host *host = (struct Scsi_Host *) data; + int rtn; + DECLARE_MUTEX_LOCKED(sem); + unsigned long flags; + struct fs_struct *fs; lock_kernel(); @@ -1943,9 +1775,9 @@ current->session = 1; current->pgrp = 1; - + /* Become as one with the init task */ - + exit_fs(current); /* current->fs->count--; */ fs = init_task.fs; current->fs = fs; @@ -1961,64 +1793,60 @@ host->eh_wait = &sem; host->ehandler = current; - + unlock_kernel(); - /* - * Wake up the thread that created us. - */ - SCSI_LOG_ERROR_RECOVERY(3,printk("Wake up parent %d\n", host->eh_notify->count.counter)); - - up(host->eh_notify); - - while(1) - { - /* - * If we get a signal, it means we are supposed to go - * away and die. This typically happens if the user is - * trying to unload a module. - */ - SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler sleeping\n")); - down_interruptible (&sem); - - if (signal_pending(current) ) - break; - - SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler waking up\n")); - - spin_lock_irqsave(&io_request_lock, flags); - host->eh_active = 1; - - /* - * We have a host that is failing for some reason. Figure out - * what we need to do to get it up and online again (if we can). - * If we fail, we end up taking the thing offline. - */ - if( host->hostt->eh_strategy_handler != NULL ) - { - rtn = host->hostt->eh_strategy_handler(host); - } - else - { - rtn = scsi_unjam_host(host); - } - - host->eh_active = 0; - - /* - * Note - if the above fails completely, the action is to take - * individual devices offline and flush the queue of any - * outstanding requests that may have been pending. When we - * restart, we restart any I/O to any other devices on the bus - * which are still online. - */ - scsi_restart_operations(host); - - /* The spinlock is really needed up to this point. (DB) */ - spin_unlock_irqrestore(&io_request_lock, flags); - } + /* + * Wake up the thread that created us. + */ + SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", host->eh_notify->count.counter)); + + up(host->eh_notify); + + while (1) { + /* + * If we get a signal, it means we are supposed to go + * away and die. This typically happens if the user is + * trying to unload a module. + */ + SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler sleeping\n")); + down_interruptible(&sem); + + if (signal_pending(current)) + break; + + SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler waking up\n")); + + spin_lock_irqsave(&io_request_lock, flags); + host->eh_active = 1; + + /* + * We have a host that is failing for some reason. Figure out + * what we need to do to get it up and online again (if we can). + * If we fail, we end up taking the thing offline. + */ + if (host->hostt->eh_strategy_handler != NULL) { + rtn = host->hostt->eh_strategy_handler(host); + } else { + rtn = scsi_unjam_host(host); + } + + host->eh_active = 0; + + /* + * Note - if the above fails completely, the action is to take + * individual devices offline and flush the queue of any + * outstanding requests that may have been pending. When we + * restart, we restart any I/O to any other devices on the bus + * which are still online. + */ + scsi_restart_operations(host); + + /* The spinlock is really needed up to this point. (DB) */ + spin_unlock_irqrestore(&io_request_lock, flags); + } - SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler exiting\n")); + SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler exiting\n")); /* * Make sure that nobody tries to wake us up again. @@ -2032,7 +1860,7 @@ * potentially in real danger. */ host->in_recovery = 0; - host->eh_active = 0; + host->eh_active = 0; host->ehandler = NULL; /* @@ -2043,8 +1871,8 @@ * the error handling thread wakes up that it would just exit without * needing to touch any memory associated with the driver itself. */ - if( host->eh_notify != NULL ) - up(host->eh_notify); + if (host->eh_notify != NULL) + up(host->eh_notify); } /* diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c --- v2.3.16/linux/drivers/scsi/scsi_ioctl.c Tue May 11 14:37:40 1999 +++ linux/drivers/scsi/scsi_ioctl.c Sat Sep 4 10:48:46 1999 @@ -18,12 +18,12 @@ #include "hosts.h" #include -#define NORMAL_RETRIES 5 -#define NORMAL_TIMEOUT (10 * HZ) -#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ) -#define START_STOP_TIMEOUT (60 * HZ) -#define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ) -#define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ) +#define NORMAL_RETRIES 5 +#define NORMAL_TIMEOUT (10 * HZ) +#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ) +#define START_STOP_TIMEOUT (60 * HZ) +#define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ) +#define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ) #define MAX_BUF PAGE_SIZE @@ -36,36 +36,38 @@ * (int *) arg */ -static int ioctl_probe(struct Scsi_Host * host, void *buffer) +static int ioctl_probe(struct Scsi_Host *host, void *buffer) { - int temp, result; - unsigned int len,slen; - const char * string; - - if ((temp = host->hostt->present) && buffer) { - result = verify_area(VERIFY_READ, buffer, sizeof(long)); - if (result) return result; - - get_user(len, (unsigned int *) buffer); - if(host->hostt->info) - string = host->hostt->info(host); - else - string = host->hostt->name; - if(string) { - slen = strlen(string); - if (len > slen) - len = slen + 1; - result = verify_area(VERIFY_WRITE, buffer, len); - if (result) return result; + int temp, result; + unsigned int len, slen; + const char *string; + + if ((temp = host->hostt->present) && buffer) { + result = verify_area(VERIFY_READ, buffer, sizeof(long)); + if (result) + return result; + + get_user(len, (unsigned int *) buffer); + if (host->hostt->info) + string = host->hostt->info(host); + else + string = host->hostt->name; + if (string) { + slen = strlen(string); + if (len > slen) + len = slen + 1; + result = verify_area(VERIFY_WRITE, buffer, len); + if (result) + return result; - copy_to_user (buffer, string, len); + copy_to_user(buffer, string, len); + } } - } - return temp; + return temp; } /* - * + * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host. * The NORMAL_TIMEOUT and NORMAL_RETRIES variables are used. * @@ -88,87 +90,89 @@ * The output area is then filled in starting from the command byte. */ -static void scsi_ioctl_done (Scsi_Cmnd * SCpnt) +static void scsi_ioctl_done(Scsi_Cmnd * SCpnt) { - struct request * req; - - req = &SCpnt->request; - req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ - - if (req->sem != NULL) { - up(req->sem); - } -} + struct request *req; + + req = &SCpnt->request; + req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ + + if (req->sem != NULL) { + up(req->sem); + } +} -static int ioctl_internal_command(Scsi_Device *dev, char * cmd, +static int ioctl_internal_command(Scsi_Device * dev, char *cmd, int timeout, int retries) { - unsigned long flags; - int result; - Scsi_Cmnd * SCpnt; - Scsi_Device * SDpnt; - - spin_lock_irqsave(&io_request_lock, flags); - - SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0])); - SCpnt = scsi_allocate_device(NULL, dev, 1); - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.sem = &sem; - scsi_do_cmd(SCpnt, cmd, NULL, 0, scsi_ioctl_done, timeout, retries); + unsigned long flags; + int result; + Scsi_Cmnd *SCpnt; + Scsi_Device *SDpnt; + + spin_lock_irqsave(&io_request_lock, flags); + + SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0])); + SCpnt = scsi_allocate_device(NULL, dev, 1); + { + DECLARE_MUTEX_LOCKED(sem); + SCpnt->request.sem = &sem; + scsi_do_cmd(SCpnt, cmd, NULL, 0, scsi_ioctl_done, timeout, retries); + spin_unlock_irqrestore(&io_request_lock, flags); + down(&sem); + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->request.sem = NULL; + } + + SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SCpnt->result)); + + if (driver_byte(SCpnt->result) != 0) + switch (SCpnt->sense_buffer[2] & 0xf) { + case ILLEGAL_REQUEST: + if (cmd[0] == ALLOW_MEDIUM_REMOVAL) + dev->lockable = 0; + else + printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); + break; + case NOT_READY: /* This happens if there is no disc in drive */ + if (dev->removable && (cmd[0] != TEST_UNIT_READY)) { + printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); + break; + } + case UNIT_ATTENTION: + if (dev->removable) { + dev->changed = 1; + SCpnt->result = 0; /* This is no longer considered an error */ + /* gag this error, VFS will log it anyway /axboe */ + /* printk(KERN_INFO "Disc change detected.\n"); */ + break; + }; + default: /* Fall through for non-removable media */ + printk("SCSI error: host %d id %d lun %d return code = %x\n", + dev->host->host_no, + dev->id, + dev->lun, + SCpnt->result); + printk("\tSense class %x, sense error %x, extended sense %x\n", + sense_class(SCpnt->sense_buffer[0]), + sense_error(SCpnt->sense_buffer[0]), + SCpnt->sense_buffer[2] & 0xf); + + }; + + result = SCpnt->result; + + SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); + SDpnt = SCpnt->device; + scsi_release_command(SCpnt); + SCpnt = NULL; + + if (!SDpnt->was_reset && SDpnt->scsi_request_fn) + (*SDpnt->scsi_request_fn) (); + + wake_up(&SDpnt->device_wait); spin_unlock_irqrestore(&io_request_lock, flags); - down(&sem); - spin_lock_irqsave(&io_request_lock, flags); - SCpnt->request.sem = NULL; - } - - SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SCpnt->result)); - - if(driver_byte(SCpnt->result) != 0) - switch(SCpnt->sense_buffer[2] & 0xf) { - case ILLEGAL_REQUEST: - if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0; - else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); - break; - case NOT_READY: /* This happens if there is no disc in drive */ - if(dev->removable && (cmd[0] != TEST_UNIT_READY)){ - printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); - break; - } - case UNIT_ATTENTION: - if (dev->removable){ - dev->changed = 1; - SCpnt->result = 0; /* This is no longer considered an error */ - /* gag this error, VFS will log it anyway /axboe */ - /* printk(KERN_INFO "Disc change detected.\n"); */ - break; - }; - default: /* Fall through for non-removable media */ - printk("SCSI error: host %d id %d lun %d return code = %x\n", - dev->host->host_no, - dev->id, - dev->lun, - SCpnt->result); - printk("\tSense class %x, sense error %x, extended sense %x\n", - sense_class(SCpnt->sense_buffer[0]), - sense_error(SCpnt->sense_buffer[0]), - SCpnt->sense_buffer[2] & 0xf); - - }; - - result = SCpnt->result; - - SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); - SDpnt = SCpnt->device; - scsi_release_command(SCpnt); - SCpnt = NULL; - - if (!SDpnt->was_reset && SDpnt->scsi_request_fn) - (*SDpnt->scsi_request_fn)(); - - wake_up(&SDpnt->device_wait); - spin_unlock_irqrestore(&io_request_lock, flags); - return result; + return result; } /* @@ -176,175 +180,183 @@ * interface instead, as this is a more flexible approach to performing * generic SCSI commands on a device. */ -int scsi_ioctl_send_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic) +int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic) { - unsigned long flags; - char * buf; - unsigned char cmd[12]; - char * cmd_in; - Scsi_Cmnd * SCpnt; - Scsi_Device * SDpnt; - unsigned char opcode; - int inlen, outlen, cmdlen; - int needed, buf_needed; - int timeout, retries, result; - - if (!sic) - return -EINVAL; - - - /* - * Verify that we can read at least this much. - */ - result = verify_area(VERIFY_READ, sic, sizeof (Scsi_Ioctl_Command)); - if (result) return result; - - /* - * The structure that we are passed should look like: - * - * struct sdata { - * unsigned int inlen; - * unsigned int outlen; - * unsigned char cmd[]; # However many bytes are used for cmd. - * unsigned char data[]; - * }; - */ - get_user(inlen, &sic->inlen); - get_user(outlen, &sic->outlen); - - /* - * We do not transfer more than MAX_BUF with this interface. - * If the user needs to transfer more data than this, they - * should use scsi_generics instead. - */ - if( inlen > MAX_BUF ) return -EINVAL; - if( outlen > MAX_BUF ) return -EINVAL; - - cmd_in = sic->data; - get_user(opcode, cmd_in); - - needed = buf_needed = (inlen > outlen ? inlen : outlen); - if(buf_needed){ - buf_needed = (buf_needed + 511) & ~511; - if (buf_needed > MAX_BUF) buf_needed = MAX_BUF; - spin_lock_irqsave(&io_request_lock, flags); - buf = (char *) scsi_malloc(buf_needed); - spin_unlock_irqrestore(&io_request_lock, flags); - if (!buf) return -ENOMEM; - memset(buf, 0, buf_needed); - } else - buf = NULL; - - /* - * Obtain the command from the user's address space. - */ - cmdlen = COMMAND_SIZE(opcode); - - result = verify_area(VERIFY_READ, cmd_in, - cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen); - if (result) return result; - - copy_from_user ((void *) cmd, cmd_in, cmdlen); - - /* - * Obtain the data to be sent to the device (if any). - */ - copy_from_user ((void *) buf, - (void *) (cmd_in + cmdlen), - inlen); - - /* - * Set the lun field to the correct value. - */ - cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5); - - switch (opcode) - { - case FORMAT_UNIT: - timeout = FORMAT_UNIT_TIMEOUT; - retries = 1; - break; - case START_STOP: - timeout = START_STOP_TIMEOUT; - retries = NORMAL_RETRIES; - break; - case MOVE_MEDIUM: - timeout = MOVE_MEDIUM_TIMEOUT; - retries = NORMAL_RETRIES; - break; - case READ_ELEMENT_STATUS: - timeout = READ_ELEMENT_STATUS_TIMEOUT; - retries = NORMAL_RETRIES; - break; - default: - timeout = NORMAL_TIMEOUT; - retries = NORMAL_RETRIES; - break; - } + unsigned long flags; + char *buf; + unsigned char cmd[12]; + char *cmd_in; + Scsi_Cmnd *SCpnt; + Scsi_Device *SDpnt; + unsigned char opcode; + int inlen, outlen, cmdlen; + int needed, buf_needed; + int timeout, retries, result; + + if (!sic) + return -EINVAL; + + + /* + * Verify that we can read at least this much. + */ + result = verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)); + if (result) + return result; + + /* + * The structure that we are passed should look like: + * + * struct sdata { + * unsigned int inlen; + * unsigned int outlen; + * unsigned char cmd[]; # However many bytes are used for cmd. + * unsigned char data[]; + * }; + */ + get_user(inlen, &sic->inlen); + get_user(outlen, &sic->outlen); + + /* + * We do not transfer more than MAX_BUF with this interface. + * If the user needs to transfer more data than this, they + * should use scsi_generics instead. + */ + if (inlen > MAX_BUF) + return -EINVAL; + if (outlen > MAX_BUF) + return -EINVAL; + + cmd_in = sic->data; + get_user(opcode, cmd_in); + + needed = buf_needed = (inlen > outlen ? inlen : outlen); + if (buf_needed) { + buf_needed = (buf_needed + 511) & ~511; + if (buf_needed > MAX_BUF) + buf_needed = MAX_BUF; + spin_lock_irqsave(&io_request_lock, flags); + buf = (char *) scsi_malloc(buf_needed); + spin_unlock_irqrestore(&io_request_lock, flags); + if (!buf) + return -ENOMEM; + memset(buf, 0, buf_needed); + } else + buf = NULL; + + /* + * Obtain the command from the user's address space. + */ + cmdlen = COMMAND_SIZE(opcode); + + result = verify_area(VERIFY_READ, cmd_in, + cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen); + if (result) + return result; + + copy_from_user((void *) cmd, cmd_in, cmdlen); + + /* + * Obtain the data to be sent to the device (if any). + */ + copy_from_user((void *) buf, + (void *) (cmd_in + cmdlen), + inlen); + + /* + * Set the lun field to the correct value. + */ + cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5); + + switch (opcode) { + case FORMAT_UNIT: + timeout = FORMAT_UNIT_TIMEOUT; + retries = 1; + break; + case START_STOP: + timeout = START_STOP_TIMEOUT; + retries = NORMAL_RETRIES; + break; + case MOVE_MEDIUM: + timeout = MOVE_MEDIUM_TIMEOUT; + retries = NORMAL_RETRIES; + break; + case READ_ELEMENT_STATUS: + timeout = READ_ELEMENT_STATUS_TIMEOUT; + retries = NORMAL_RETRIES; + break; + default: + timeout = NORMAL_TIMEOUT; + retries = NORMAL_RETRIES; + break; + } #ifndef DEBUG_NO_CMD - spin_lock_irqsave(&io_request_lock, flags); - - SCpnt = scsi_allocate_device(NULL, dev, 1); - - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.sem = &sem; - scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, - timeout, retries); + spin_lock_irqsave(&io_request_lock, flags); + + SCpnt = scsi_allocate_device(NULL, dev, 1); + + { + DECLARE_MUTEX_LOCKED(sem); + SCpnt->request.sem = &sem; + scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, + timeout, retries); + spin_unlock_irqrestore(&io_request_lock, flags); + down(&sem); + SCpnt->request.sem = NULL; + } + + /* + * If there was an error condition, pass the info back to the user. + */ + if (SCpnt->result) { + result = verify_area(VERIFY_WRITE, + cmd_in, + sizeof(SCpnt->sense_buffer)); + if (result) + return result; + copy_to_user((void *) cmd_in, + SCpnt->sense_buffer, + sizeof(SCpnt->sense_buffer)); + } else { + result = verify_area(VERIFY_WRITE, cmd_in, outlen); + if (result) + return result; + copy_to_user((void *) cmd_in, buf, outlen); + } + result = SCpnt->result; + + spin_lock_irqsave(&io_request_lock, flags); + + wake_up(&SCpnt->device->device_wait); + SDpnt = SCpnt->device; + scsi_release_command(SCpnt); + SCpnt = NULL; + + if (buf) + scsi_free(buf, buf_needed); + + if (SDpnt->scsi_request_fn) + (*SDpnt->scsi_request_fn) (); + spin_unlock_irqrestore(&io_request_lock, flags); - down(&sem); - SCpnt->request.sem = NULL; - } - - /* - * If there was an error condition, pass the info back to the user. - */ - if(SCpnt->result) { - result = verify_area(VERIFY_WRITE, - cmd_in, - sizeof(SCpnt->sense_buffer)); - if (result) return result; - copy_to_user((void *) cmd_in, - SCpnt->sense_buffer, - sizeof(SCpnt->sense_buffer)); - } else { - result = verify_area(VERIFY_WRITE, cmd_in, outlen); - if (result) return result; - copy_to_user ((void *) cmd_in, buf, outlen); - } - result = SCpnt->result; - - spin_lock_irqsave(&io_request_lock, flags); - - wake_up(&SCpnt->device->device_wait); - SDpnt = SCpnt->device; - scsi_release_command(SCpnt); - SCpnt = NULL; - - if (buf) scsi_free(buf, buf_needed); - - if(SDpnt->scsi_request_fn) - (*SDpnt->scsi_request_fn)(); - - spin_unlock_irqrestore(&io_request_lock, flags); - return result; + return result; #else - { - int i; - printk("scsi_ioctl : device %d. command = ", dev->id); - for (i = 0; i < 12; ++i) - printk("%02x ", cmd[i]); - printk("\nbuffer ="); - for (i = 0; i < 20; ++i) - printk("%02x ", buf[i]); - printk("\n"); - printk("inlen = %d, outlen = %d, cmdlen = %d\n", - inlen, outlen, cmdlen); - printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); - } - return 0; + { + int i; + printk("scsi_ioctl : device %d. command = ", dev->id); + for (i = 0; i < 12; ++i) + printk("%02x ", cmd[i]); + printk("\nbuffer ="); + for (i = 0; i < 20; ++i) + printk("%02x ", buf[i]); + printk("\n"); + printk("inlen = %d, outlen = %d, cmdlen = %d\n", + inlen, outlen, cmdlen); + printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); + } + return 0; #endif } @@ -353,107 +365,115 @@ * not take a major/minor number as the dev field. Rather, it takes * a pointer to a scsi_devices[] element, a structure. */ -int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) +int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) { - int result; - char scsi_cmd[12]; - - /* No idea how this happens.... */ - if (!dev) return -ENXIO; - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(dev) ) - { - return -ENODEV; - } - - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - result = verify_area(VERIFY_WRITE, arg, sizeof (Scsi_Idlun)); - if (result) return result; - - put_user(dev->id - + (dev->lun << 8) - + (dev->channel << 16) - + ((dev->host->hostt->proc_dir->low_ino & 0xff) << 24), - &((Scsi_Idlun *) arg)->dev_id); - put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id); - return 0; - case SCSI_IOCTL_GET_BUS_NUMBER: - result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); - if (result) return result; - put_user( dev->host->host_no, (int *) arg); - return 0; - case SCSI_IOCTL_TAGGED_ENABLE: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!dev->tagged_supported) return -EINVAL; - dev->tagged_queue = 1; - dev->current_tag = 1; - return 0; - case SCSI_IOCTL_TAGGED_DISABLE: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!dev->tagged_supported) return -EINVAL; - dev->tagged_queue = 0; - dev->current_tag = 0; - return 0; - case SCSI_IOCTL_PROBE_HOST: - return ioctl_probe(dev->host, arg); - case SCSI_IOCTL_SEND_COMMAND: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - return scsi_ioctl_send_command((Scsi_Device *) dev, - (Scsi_Ioctl_Command *) arg); - case SCSI_IOCTL_DOORLOCK: - if (!dev->removable || !dev->lockable) return 0; - scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; - scsi_cmd[1] = dev->lun << 5; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = SCSI_REMOVAL_PREVENT; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, - NORMAL_TIMEOUT, NORMAL_RETRIES); - break; - case SCSI_IOCTL_DOORUNLOCK: - if (!dev->removable || !dev->lockable) return 0; - scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; - scsi_cmd[1] = dev->lun << 5; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = SCSI_REMOVAL_ALLOW; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, - NORMAL_TIMEOUT, NORMAL_RETRIES); - case SCSI_IOCTL_TEST_UNIT_READY: - scsi_cmd[0] = TEST_UNIT_READY; - scsi_cmd[1] = dev->lun << 5; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = 0; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, - NORMAL_TIMEOUT, NORMAL_RETRIES); - break; - case SCSI_IOCTL_START_UNIT: - scsi_cmd[0] = START_STOP; - scsi_cmd[1] = dev->lun << 5; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = 1; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, - START_STOP_TIMEOUT, NORMAL_RETRIES); - break; - case SCSI_IOCTL_STOP_UNIT: - scsi_cmd[0] = START_STOP; - scsi_cmd[1] = dev->lun << 5; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = 0; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, - START_STOP_TIMEOUT, NORMAL_RETRIES); - break; - default : - if (dev->host->hostt->ioctl) - return dev->host->hostt->ioctl(dev, cmd, arg); + int result; + char scsi_cmd[12]; + + /* No idea how this happens.... */ + if (!dev) + return -ENXIO; + + /* + * If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. + */ + if (!scsi_block_when_processing_errors(dev)) { + return -ENODEV; + } + switch (cmd) { + case SCSI_IOCTL_GET_IDLUN: + result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun)); + if (result) + return result; + + put_user(dev->id + + (dev->lun << 8) + + (dev->channel << 16) + + ((dev->host->hostt->proc_dir->low_ino & 0xff) << 24), + &((Scsi_Idlun *) arg)->dev_id); + put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id); + return 0; + case SCSI_IOCTL_GET_BUS_NUMBER: + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (result) + return result; + put_user(dev->host->host_no, (int *) arg); + return 0; + case SCSI_IOCTL_TAGGED_ENABLE: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (!dev->tagged_supported) + return -EINVAL; + dev->tagged_queue = 1; + dev->current_tag = 1; + return 0; + case SCSI_IOCTL_TAGGED_DISABLE: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (!dev->tagged_supported) + return -EINVAL; + dev->tagged_queue = 0; + dev->current_tag = 0; + return 0; + case SCSI_IOCTL_PROBE_HOST: + return ioctl_probe(dev->host, arg); + case SCSI_IOCTL_SEND_COMMAND: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return scsi_ioctl_send_command((Scsi_Device *) dev, + (Scsi_Ioctl_Command *) arg); + case SCSI_IOCTL_DOORLOCK: + if (!dev->removable || !dev->lockable) + return 0; + scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; + scsi_cmd[1] = dev->lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; + scsi_cmd[4] = SCSI_REMOVAL_PREVENT; + return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + NORMAL_TIMEOUT, NORMAL_RETRIES); + break; + case SCSI_IOCTL_DOORUNLOCK: + if (!dev->removable || !dev->lockable) + return 0; + scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; + scsi_cmd[1] = dev->lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; + scsi_cmd[4] = SCSI_REMOVAL_ALLOW; + return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + NORMAL_TIMEOUT, NORMAL_RETRIES); + case SCSI_IOCTL_TEST_UNIT_READY: + scsi_cmd[0] = TEST_UNIT_READY; + scsi_cmd[1] = dev->lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; + scsi_cmd[4] = 0; + return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + NORMAL_TIMEOUT, NORMAL_RETRIES); + break; + case SCSI_IOCTL_START_UNIT: + scsi_cmd[0] = START_STOP; + scsi_cmd[1] = dev->lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; + scsi_cmd[4] = 1; + return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + START_STOP_TIMEOUT, NORMAL_RETRIES); + break; + case SCSI_IOCTL_STOP_UNIT: + scsi_cmd[0] = START_STOP; + scsi_cmd[1] = dev->lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; + scsi_cmd[4] = 0; + return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + START_STOP_TIMEOUT, NORMAL_RETRIES); + break; + default: + if (dev->host->hostt->ioctl) + return dev->host->hostt->ioctl(dev, cmd, arg); + return -EINVAL; + } return -EINVAL; - } - return -EINVAL; } /* @@ -461,14 +481,15 @@ * fs segment fiddling. */ -int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) { - mm_segment_t oldfs; - int tmp; - oldfs = get_fs(); - set_fs(get_ds()); - tmp = scsi_ioctl (dev, cmd, arg); - set_fs(oldfs); - return tmp; +int kernel_scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) +{ + mm_segment_t oldfs; + int tmp; + oldfs = get_fs(); + set_fs(get_ds()); + tmp = scsi_ioctl(dev, cmd, arg); + set_fs(oldfs); + return tmp; } /* diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_module.c linux/drivers/scsi/scsi_module.c --- v2.3.16/linux/drivers/scsi/scsi_module.c Sat Sep 20 11:42:33 1997 +++ linux/drivers/scsi/scsi_module.c Sat Sep 4 10:48:46 1999 @@ -31,18 +31,20 @@ #include -int init_module(void) { - driver_template.module = &__this_module; - scsi_register_module(MODULE_SCSI_HA, &driver_template); - if (driver_template.present) - return 0; +int init_module(void) +{ + driver_template.module = &__this_module; + scsi_register_module(MODULE_SCSI_HA, &driver_template); + if (driver_template.present) + return 0; - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); - return -1; + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + return -1; } -void cleanup_module( void) { - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); +void cleanup_module(void) +{ + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); } /* diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.3.16/linux/drivers/scsi/scsi_obsolete.c Sun Jan 17 18:29:54 1999 +++ linux/drivers/scsi/scsi_obsolete.c Sat Sep 4 10:48:46 1999 @@ -33,7 +33,7 @@ *######################################################################### *######################################################################### *######################################################################### - * NOTE - NOTE - NOTE - NOTE - NOTE - NOTE - NOTE + * NOTE - NOTE - NOTE - NOTE - NOTE - NOTE - NOTE * *######################################################################### *######################################################################### @@ -71,26 +71,26 @@ #undef USE_STATIC_SCSI_MEMORY /* -static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_obsolete.c,v 1.1 1997/05/18 23:27:21 eric Exp $"; -*/ + static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_obsolete.c,v 1.1 1997/05/18 23:27:21 eric Exp $"; + */ #define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__)) -static int scsi_abort (Scsi_Cmnd *, int code); -static int scsi_reset (Scsi_Cmnd *, unsigned int); +static int scsi_abort(Scsi_Cmnd *, int code); +static int scsi_reset(Scsi_Cmnd *, unsigned int); -extern void scsi_old_done (Scsi_Cmnd *SCpnt); -int update_timeout (Scsi_Cmnd *, int); -extern void scsi_old_times_out (Scsi_Cmnd * SCpnt); -extern void internal_cmnd (Scsi_Cmnd * SCpnt); +extern void scsi_old_done(Scsi_Cmnd * SCpnt); +int update_timeout(Scsi_Cmnd *, int); +extern void scsi_old_times_out(Scsi_Cmnd * SCpnt); +extern void internal_cmnd(Scsi_Cmnd * SCpnt); -extern volatile struct Scsi_Host * host_active; +extern volatile struct Scsi_Host *host_active; #define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \ || (HOST->can_queue && HOST->host_busy >= HOST->can_queue)) -static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0}; +static unsigned char generic_sense[6] = {REQUEST_SENSE, 0, 0, 0, 255, 0}; /* * This is the number of clock ticks we should wait before we time out @@ -108,19 +108,19 @@ #ifdef DEBUG - #define SCSI_TIMEOUT (5*HZ) +#define SCSI_TIMEOUT (5*HZ) #else - #define SCSI_TIMEOUT (2*HZ) +#define SCSI_TIMEOUT (2*HZ) #endif #ifdef DEBUG - #define SENSE_TIMEOUT SCSI_TIMEOUT - #define ABORT_TIMEOUT SCSI_TIMEOUT - #define RESET_TIMEOUT SCSI_TIMEOUT +#define SENSE_TIMEOUT SCSI_TIMEOUT +#define ABORT_TIMEOUT SCSI_TIMEOUT +#define RESET_TIMEOUT SCSI_TIMEOUT #else - #define SENSE_TIMEOUT (5*HZ/10) - #define RESET_TIMEOUT (5*HZ/10) - #define ABORT_TIMEOUT (5*HZ/10) +#define SENSE_TIMEOUT (5*HZ/10) +#define RESET_TIMEOUT (5*HZ/10) +#define ABORT_TIMEOUT (5*HZ/10) #endif @@ -144,67 +144,66 @@ * command, that failing perform a kernel panic. */ -void scsi_old_times_out (Scsi_Cmnd * SCpnt) +void scsi_old_times_out(Scsi_Cmnd * SCpnt) { - unsigned long flags; + unsigned long flags; - spin_lock_irqsave(&io_request_lock, flags); + spin_lock_irqsave(&io_request_lock, flags); - /* Set the serial_number_at_timeout to the current serial_number */ - SCpnt->serial_number_at_timeout = SCpnt->serial_number; + /* Set the serial_number_at_timeout to the current serial_number */ + SCpnt->serial_number_at_timeout = SCpnt->serial_number; - switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3)) - { - case NORMAL_TIMEOUT: - { + switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3)) { + case NORMAL_TIMEOUT: + { #ifdef DEBUG_TIMEOUT - scsi_dump_status(); + scsi_dump_status(); #endif - } + } - if (!scsi_abort (SCpnt, DID_TIME_OUT)) - break; - case IN_ABORT: - printk("SCSI host %d abort (pid %ld) timed out - resetting\n", - SCpnt->host->host_no, SCpnt->pid); - if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS)) - break; - case IN_RESET: - case (IN_ABORT | IN_RESET): - /* This might be controversial, but if there is a bus hang, - * you might conceivably want the machine up and running - * esp if you have an ide disk. - */ - printk("SCSI host %d channel %d reset (pid %ld) timed out - " - "trying harder\n", - SCpnt->host->host_no, SCpnt->channel, SCpnt->pid); - SCpnt->internal_timeout &= ~IN_RESET; - SCpnt->internal_timeout |= IN_RESET2; - scsi_reset (SCpnt, - SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET); - break; - case IN_RESET2: - case (IN_ABORT | IN_RESET2): - /* Obviously the bus reset didn't work. - * Let's try even harder and call for an HBA reset. - * Maybe the HBA itself crashed and this will shake it loose. - */ - printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n", - SCpnt->host->host_no, SCpnt->pid); - SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2); - SCpnt->internal_timeout |= IN_RESET3; - scsi_reset (SCpnt, - SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET); - break; - - default: - printk("SCSI host %d reset (pid %ld) timed out again -\n", - SCpnt->host->host_no, SCpnt->pid); - printk("probably an unrecoverable SCSI bus or device hang.\n"); - break; + if (!scsi_abort(SCpnt, DID_TIME_OUT)) + break; + case IN_ABORT: + printk("SCSI host %d abort (pid %ld) timed out - resetting\n", + SCpnt->host->host_no, SCpnt->pid); + if (!scsi_reset(SCpnt, SCSI_RESET_ASYNCHRONOUS)) + break; + case IN_RESET: + case (IN_ABORT | IN_RESET): + /* This might be controversial, but if there is a bus hang, + * you might conceivably want the machine up and running + * esp if you have an ide disk. + */ + printk("SCSI host %d channel %d reset (pid %ld) timed out - " + "trying harder\n", + SCpnt->host->host_no, SCpnt->channel, SCpnt->pid); + SCpnt->internal_timeout &= ~IN_RESET; + SCpnt->internal_timeout |= IN_RESET2; + scsi_reset(SCpnt, + SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET); + break; + case IN_RESET2: + case (IN_ABORT | IN_RESET2): + /* Obviously the bus reset didn't work. + * Let's try even harder and call for an HBA reset. + * Maybe the HBA itself crashed and this will shake it loose. + */ + printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n", + SCpnt->host->host_no, SCpnt->pid); + SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2); + SCpnt->internal_timeout |= IN_RESET3; + scsi_reset(SCpnt, + SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET); + break; - } - spin_unlock_irqrestore(&io_request_lock, flags); + default: + printk("SCSI host %d reset (pid %ld) timed out again -\n", + SCpnt->host->host_no, SCpnt->pid); + printk("probably an unrecoverable SCSI bus or device hang.\n"); + break; + + } + spin_unlock_irqrestore(&io_request_lock, flags); } @@ -214,92 +213,89 @@ * io_request_lock already held, so we need do nothing here about grabbing * any locks. */ -static void scsi_request_sense (Scsi_Cmnd * SCpnt) +static void scsi_request_sense(Scsi_Cmnd * SCpnt) { - SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE; - update_timeout(SCpnt, SENSE_TIMEOUT); + SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE; + update_timeout(SCpnt, SENSE_TIMEOUT); - memcpy ((void *) SCpnt->cmnd , (void *) generic_sense, - sizeof(generic_sense)); - memset ((void *) SCpnt->sense_buffer, 0, - sizeof(SCpnt->sense_buffer)); - - SCpnt->cmnd[1] = SCpnt->lun << 5; - SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer); - - SCpnt->request_buffer = &SCpnt->sense_buffer; - SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); - SCpnt->use_sg = 0; - SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); - SCpnt->result = 0; - internal_cmnd (SCpnt); + memcpy((void *) SCpnt->cmnd, (void *) generic_sense, + sizeof(generic_sense)); + memset((void *) SCpnt->sense_buffer, 0, + sizeof(SCpnt->sense_buffer)); + + SCpnt->cmnd[1] = SCpnt->lun << 5; + SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer); + + SCpnt->request_buffer = &SCpnt->sense_buffer; + SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); + SCpnt->use_sg = 0; + SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); + SCpnt->result = 0; + internal_cmnd(SCpnt); } -static int check_sense (Scsi_Cmnd * SCpnt) +static int check_sense(Scsi_Cmnd * SCpnt) { - /* If there is no sense information, request it. If we have already - * requested it, there is no point in asking again - the firmware must - * be confused. - */ - if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) { - if(!(SCpnt->flags & ASKED_FOR_SENSE)) - return SUGGEST_SENSE; - else - return SUGGEST_RETRY; - } - - SCpnt->flags &= ~ASKED_FOR_SENSE; + /* If there is no sense information, request it. If we have already + * requested it, there is no point in asking again - the firmware must + * be confused. + */ + if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) { + if (!(SCpnt->flags & ASKED_FOR_SENSE)) + return SUGGEST_SENSE; + else + return SUGGEST_RETRY; + } + SCpnt->flags &= ~ASKED_FOR_SENSE; #ifdef DEBUG_INIT - printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel); - print_sense("", SCpnt); - printk("\n"); -#endif - if (SCpnt->sense_buffer[2] & 0xe0) - return SUGGEST_ABORT; - - switch (SCpnt->sense_buffer[2] & 0xf) - { - case NO_SENSE: - return 0; - case RECOVERED_ERROR: - return SUGGEST_IS_OK; - - case ABORTED_COMMAND: - return SUGGEST_RETRY; - case NOT_READY: - case UNIT_ATTENTION: - /* - * If we are expecting a CC/UA because of a bus reset that we - * performed, treat this just as a retry. Otherwise this is - * information that we should pass up to the upper-level driver - * so that we can deal with it there. - */ - if( SCpnt->device->expecting_cc_ua ) - { - SCpnt->device->expecting_cc_ua = 0; - return SUGGEST_RETRY; - } - return SUGGEST_ABORT; - - /* these three are not supported */ - case COPY_ABORTED: - case VOLUME_OVERFLOW: - case MISCOMPARE: - - case MEDIUM_ERROR: - return SUGGEST_REMAP; - case BLANK_CHECK: - case DATA_PROTECT: - case HARDWARE_ERROR: - case ILLEGAL_REQUEST: - default: - return SUGGEST_ABORT; - } + printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel); + print_sense("", SCpnt); + printk("\n"); +#endif + if (SCpnt->sense_buffer[2] & 0xe0) + return SUGGEST_ABORT; + + switch (SCpnt->sense_buffer[2] & 0xf) { + case NO_SENSE: + return 0; + case RECOVERED_ERROR: + return SUGGEST_IS_OK; + + case ABORTED_COMMAND: + return SUGGEST_RETRY; + case NOT_READY: + case UNIT_ATTENTION: + /* + * If we are expecting a CC/UA because of a bus reset that we + * performed, treat this just as a retry. Otherwise this is + * information that we should pass up to the upper-level driver + * so that we can deal with it there. + */ + if (SCpnt->device->expecting_cc_ua) { + SCpnt->device->expecting_cc_ua = 0; + return SUGGEST_RETRY; + } + return SUGGEST_ABORT; + + /* these three are not supported */ + case COPY_ABORTED: + case VOLUME_OVERFLOW: + case MISCOMPARE: + + case MEDIUM_ERROR: + return SUGGEST_REMAP; + case BLANK_CHECK: + case DATA_PROTECT: + case HARDWARE_ERROR: + case ILLEGAL_REQUEST: + default: + return SUGGEST_ABORT; + } } /* This function is the mid-level interrupt routine, which decides how @@ -323,29 +319,30 @@ * will hang. If more than one of the above actions are taken by * scsi_done, then unpredictable behavior will result. */ -void scsi_old_done (Scsi_Cmnd * SCpnt) +void scsi_old_done(Scsi_Cmnd * SCpnt) { - int status=0; - int exit=0; - int checked; - int oldto; - struct Scsi_Host * host = SCpnt->host; - int result = SCpnt->result; - SCpnt->serial_number = 0; - SCpnt->serial_number_at_timeout = 0; - oldto = update_timeout(SCpnt, 0); + int status = 0; + int exit = 0; + int checked; + int oldto; + struct Scsi_Host *host = SCpnt->host; + int result = SCpnt->result; + SCpnt->serial_number = 0; + SCpnt->serial_number_at_timeout = 0; + oldto = update_timeout(SCpnt, 0); #ifdef DEBUG_TIMEOUT - if(result) printk("Non-zero result in scsi_done %x %d:%d\n", - result, SCpnt->target, SCpnt->lun); + if (result) + printk("Non-zero result in scsi_done %x %d:%d\n", + result, SCpnt->target, SCpnt->lun); #endif - /* If we requested an abort, (and we got it) then fix up the return - * status to say why - */ - if(host_byte(result) == DID_ABORT && SCpnt->abort_reason) - SCpnt->result = result = (result & 0xff00ffff) | - (SCpnt->abort_reason << 16); + /* If we requested an abort, (and we got it) then fix up the return + * status to say why + */ + if (host_byte(result) == DID_ABORT && SCpnt->abort_reason) + SCpnt->result = result = (result & 0xff00ffff) | + (SCpnt->abort_reason << 16); #define CMD_FINISHED 0 @@ -354,339 +351,313 @@ #define PENDING 4 #ifdef DEBUG - printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result); + printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result); #endif - if(SCpnt->flags & SYNC_RESET) - { - /* - * The behaviou of scsi_reset(SYNC) was changed in 2.1.? . - * The scsi mid-layer does a REDO after every sync reset, the driver - * must not do that any more. In order to prevent old drivers from - * crashing, all scsi_done() calls during sync resets are ignored. - */ - printk("scsi%d: device driver called scsi_done() " - "for a syncronous reset.\n", SCpnt->host->host_no); - return; - } - if(SCpnt->flags & WAS_SENSE) - { - SCpnt->use_sg = SCpnt->old_use_sg; - SCpnt->cmd_len = SCpnt->old_cmd_len; - } - - switch (host_byte(result)) - { - case DID_OK: - if (status_byte(result) && (SCpnt->flags & WAS_SENSE)) - /* Failed to obtain sense information */ - { - SCpnt->flags &= ~WAS_SENSE; -#if 0 /* This cannot possibly be correct. */ - SCpnt->internal_timeout &= ~SENSE_TIMEOUT; -#endif - - if (!(SCpnt->flags & WAS_RESET)) - { - printk("scsi%d : channel %d target %d lun %d request sense" - " failed, performing reset.\n", - SCpnt->host->host_no, SCpnt->channel, SCpnt->target, - SCpnt->lun); - scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); - status = REDO; - break; - } - else - { - exit = (DRIVER_HARD | SUGGEST_ABORT); - status = CMD_FINISHED; - } + if (SCpnt->flags & SYNC_RESET) { + /* + * The behaviou of scsi_reset(SYNC) was changed in 2.1.? . + * The scsi mid-layer does a REDO after every sync reset, the driver + * must not do that any more. In order to prevent old drivers from + * crashing, all scsi_done() calls during sync resets are ignored. + */ + printk("scsi%d: device driver called scsi_done() " + "for a syncronous reset.\n", SCpnt->host->host_no); + return; } - else switch(msg_byte(result)) - { - case COMMAND_COMPLETE: - switch (status_byte(result)) - { - case GOOD: - if (SCpnt->flags & WAS_SENSE) + if (SCpnt->flags & WAS_SENSE) { + SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; + } + switch (host_byte(result)) { + case DID_OK: + if (status_byte(result) && (SCpnt->flags & WAS_SENSE)) + /* Failed to obtain sense information */ { + SCpnt->flags &= ~WAS_SENSE; +#if 0 /* This cannot possibly be correct. */ + SCpnt->internal_timeout &= ~SENSE_TIMEOUT; +#endif + + if (!(SCpnt->flags & WAS_RESET)) { + printk("scsi%d : channel %d target %d lun %d request sense" + " failed, performing reset.\n", + SCpnt->host->host_no, SCpnt->channel, SCpnt->target, + SCpnt->lun); + scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); + status = REDO; + break; + } else { + exit = (DRIVER_HARD | SUGGEST_ABORT); + status = CMD_FINISHED; + } + } else + switch (msg_byte(result)) { + case COMMAND_COMPLETE: + switch (status_byte(result)) { + case GOOD: + if (SCpnt->flags & WAS_SENSE) { #ifdef DEBUG - printk ("In scsi_done, GOOD status, COMMAND COMPLETE, " - "parsing sense information.\n"); + printk("In scsi_done, GOOD status, COMMAND COMPLETE, " + "parsing sense information.\n"); #endif - SCpnt->flags &= ~WAS_SENSE; -#if 0 /* This cannot possibly be correct. */ - SCpnt->internal_timeout &= ~SENSE_TIMEOUT; + SCpnt->flags &= ~WAS_SENSE; +#if 0 /* This cannot possibly be correct. */ + SCpnt->internal_timeout &= ~SENSE_TIMEOUT; #endif - switch (checked = check_sense(SCpnt)) - { - case SUGGEST_SENSE: - case 0: + switch (checked = check_sense(SCpnt)) { + case SUGGEST_SENSE: + case 0: #ifdef DEBUG - printk("NO SENSE. status = REDO\n"); + printk("NO SENSE. status = REDO\n"); #endif - update_timeout(SCpnt, oldto); - status = REDO; - break; - case SUGGEST_IS_OK: - break; - case SUGGEST_REMAP: + update_timeout(SCpnt, oldto); + status = REDO; + break; + case SUGGEST_IS_OK: + break; + case SUGGEST_REMAP: #ifdef DEBUG - printk("SENSE SUGGEST REMAP - status = CMD_FINISHED\n"); + printk("SENSE SUGGEST REMAP - status = CMD_FINISHED\n"); #endif - status = CMD_FINISHED; - exit = DRIVER_SENSE | SUGGEST_ABORT; - break; - case SUGGEST_RETRY: + status = CMD_FINISHED; + exit = DRIVER_SENSE | SUGGEST_ABORT; + break; + case SUGGEST_RETRY: #ifdef DEBUG - printk("SENSE SUGGEST RETRY - status = MAYREDO\n"); + printk("SENSE SUGGEST RETRY - status = MAYREDO\n"); #endif - status = MAYREDO; - exit = DRIVER_SENSE | SUGGEST_RETRY; - break; - case SUGGEST_ABORT: + status = MAYREDO; + exit = DRIVER_SENSE | SUGGEST_RETRY; + break; + case SUGGEST_ABORT: #ifdef DEBUG - printk("SENSE SUGGEST ABORT - status = CMD_FINISHED"); + printk("SENSE SUGGEST ABORT - status = CMD_FINISHED"); #endif - status = CMD_FINISHED; - exit = DRIVER_SENSE | SUGGEST_ABORT; - break; - default: - printk ("Internal error %s %d \n", __FILE__, - __LINE__); - } - } /* end WAS_SENSE */ - else - { + status = CMD_FINISHED; + exit = DRIVER_SENSE | SUGGEST_ABORT; + break; + default: + printk("Internal error %s %d \n", __FILE__, + __LINE__); + } + } + /* end WAS_SENSE */ + else { #ifdef DEBUG - printk("COMMAND COMPLETE message returned, " - "status = CMD_FINISHED. \n"); + printk("COMMAND COMPLETE message returned, " + "status = CMD_FINISHED. \n"); #endif - exit = DRIVER_OK; - status = CMD_FINISHED; - } - break; - - case CHECK_CONDITION: - case COMMAND_TERMINATED: - switch (check_sense(SCpnt)) - { - case 0: - update_timeout(SCpnt, oldto); - status = REDO; - break; - case SUGGEST_REMAP: - status = CMD_FINISHED; - exit = DRIVER_SENSE | SUGGEST_ABORT; - break; - case SUGGEST_RETRY: - status = MAYREDO; - exit = DRIVER_SENSE | SUGGEST_RETRY; - break; - case SUGGEST_ABORT: - status = CMD_FINISHED; - exit = DRIVER_SENSE | SUGGEST_ABORT; - break; - case SUGGEST_SENSE: - scsi_request_sense (SCpnt); - status = PENDING; - break; - } - break; - - case CONDITION_GOOD: - case INTERMEDIATE_GOOD: - case INTERMEDIATE_C_GOOD: + exit = DRIVER_OK; + status = CMD_FINISHED; + } + break; + + case CHECK_CONDITION: + case COMMAND_TERMINATED: + switch (check_sense(SCpnt)) { + case 0: + update_timeout(SCpnt, oldto); + status = REDO; + break; + case SUGGEST_REMAP: + status = CMD_FINISHED; + exit = DRIVER_SENSE | SUGGEST_ABORT; + break; + case SUGGEST_RETRY: + status = MAYREDO; + exit = DRIVER_SENSE | SUGGEST_RETRY; + break; + case SUGGEST_ABORT: + status = CMD_FINISHED; + exit = DRIVER_SENSE | SUGGEST_ABORT; + break; + case SUGGEST_SENSE: + scsi_request_sense(SCpnt); + status = PENDING; + break; + } + break; + + case CONDITION_GOOD: + case INTERMEDIATE_GOOD: + case INTERMEDIATE_C_GOOD: + break; + + case BUSY: + case QUEUE_FULL: + update_timeout(SCpnt, oldto); + status = REDO; + break; + + case RESERVATION_CONFLICT: + printk("scsi%d, channel %d : RESERVATION CONFLICT performing" + " reset.\n", SCpnt->host->host_no, SCpnt->channel); + scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); + status = REDO; + break; + default: + printk("Internal error %s %d \n" + "status byte = %d \n", __FILE__, + __LINE__, status_byte(result)); + + } + break; + default: + panic("scsi: unsupported message byte %d received\n", + msg_byte(result)); + } break; - - case BUSY: - case QUEUE_FULL: - update_timeout(SCpnt, oldto); - status = REDO; - break; - - case RESERVATION_CONFLICT: - printk("scsi%d, channel %d : RESERVATION CONFLICT performing" - " reset.\n", SCpnt->host->host_no, SCpnt->channel); - scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); - status = REDO; - break; - default: - printk ("Internal error %s %d \n" - "status byte = %d \n", __FILE__, - __LINE__, status_byte(result)); - - } - break; - default: - panic("scsi: unsupported message byte %d received\n", - msg_byte(result)); - } - break; - case DID_TIME_OUT: + case DID_TIME_OUT: #ifdef DEBUG - printk("Host returned DID_TIME_OUT - "); + printk("Host returned DID_TIME_OUT - "); #endif - if (SCpnt->flags & WAS_TIMEDOUT) - { + if (SCpnt->flags & WAS_TIMEDOUT) { #ifdef DEBUG - printk("Aborting\n"); + printk("Aborting\n"); #endif - /* - Allow TEST_UNIT_READY and INQUIRY commands to timeout early - without causing resets. All other commands should be retried. - */ - if (SCpnt->cmnd[0] != TEST_UNIT_READY && - SCpnt->cmnd[0] != INQUIRY) - status = MAYREDO; - exit = (DRIVER_TIMEOUT | SUGGEST_ABORT); - } - else - { + /* + Allow TEST_UNIT_READY and INQUIRY commands to timeout early + without causing resets. All other commands should be retried. + */ + if (SCpnt->cmnd[0] != TEST_UNIT_READY && + SCpnt->cmnd[0] != INQUIRY) + status = MAYREDO; + exit = (DRIVER_TIMEOUT | SUGGEST_ABORT); + } else { #ifdef DEBUG - printk ("Retrying.\n"); + printk("Retrying.\n"); #endif - SCpnt->flags |= WAS_TIMEDOUT; - SCpnt->internal_timeout &= ~IN_ABORT; - status = REDO; - } - break; - case DID_BUS_BUSY: - case DID_PARITY: - status = REDO; - break; - case DID_NO_CONNECT: + SCpnt->flags |= WAS_TIMEDOUT; + SCpnt->internal_timeout &= ~IN_ABORT; + status = REDO; + } + break; + case DID_BUS_BUSY: + case DID_PARITY: + status = REDO; + break; + case DID_NO_CONNECT: #ifdef DEBUG - printk("Couldn't connect.\n"); + printk("Couldn't connect.\n"); #endif - exit = (DRIVER_HARD | SUGGEST_ABORT); - break; - case DID_ERROR: - status = MAYREDO; - exit = (DRIVER_HARD | SUGGEST_ABORT); - break; - case DID_BAD_TARGET: - case DID_ABORT: - exit = (DRIVER_INVALID | SUGGEST_ABORT); - break; - case DID_RESET: - if (SCpnt->flags & IS_RESETTING) - { - SCpnt->flags &= ~IS_RESETTING; - status = REDO; - break; - } - - if(msg_byte(result) == GOOD && - status_byte(result) == CHECK_CONDITION) { - switch (check_sense(SCpnt)) { - case 0: - update_timeout(SCpnt, oldto); - status = REDO; + exit = (DRIVER_HARD | SUGGEST_ABORT); break; - case SUGGEST_REMAP: - case SUGGEST_RETRY: + case DID_ERROR: status = MAYREDO; - exit = DRIVER_SENSE | SUGGEST_RETRY; + exit = (DRIVER_HARD | SUGGEST_ABORT); break; - case SUGGEST_ABORT: - status = CMD_FINISHED; - exit = DRIVER_SENSE | SUGGEST_ABORT; + case DID_BAD_TARGET: + case DID_ABORT: + exit = (DRIVER_INVALID | SUGGEST_ABORT); break; - case SUGGEST_SENSE: - scsi_request_sense (SCpnt); - status = PENDING; + case DID_RESET: + if (SCpnt->flags & IS_RESETTING) { + SCpnt->flags &= ~IS_RESETTING; + status = REDO; + break; + } + if (msg_byte(result) == GOOD && + status_byte(result) == CHECK_CONDITION) { + switch (check_sense(SCpnt)) { + case 0: + update_timeout(SCpnt, oldto); + status = REDO; + break; + case SUGGEST_REMAP: + case SUGGEST_RETRY: + status = MAYREDO; + exit = DRIVER_SENSE | SUGGEST_RETRY; + break; + case SUGGEST_ABORT: + status = CMD_FINISHED; + exit = DRIVER_SENSE | SUGGEST_ABORT; + break; + case SUGGEST_SENSE: + scsi_request_sense(SCpnt); + status = PENDING; + break; + } + } else { + status = REDO; + exit = SUGGEST_RETRY; + } break; - } - } else { - status=REDO; - exit = SUGGEST_RETRY; + default: + exit = (DRIVER_ERROR | SUGGEST_DIE); } - break; - default : - exit = (DRIVER_ERROR | SUGGEST_DIE); - } - - switch (status) - { - case CMD_FINISHED: - case PENDING: - break; - case MAYREDO: + + switch (status) { + case CMD_FINISHED: + case PENDING: + break; + case MAYREDO: #ifdef DEBUG - printk("In MAYREDO, allowing %d retries, have %d\n", - SCpnt->allowed, SCpnt->retries); + printk("In MAYREDO, allowing %d retries, have %d\n", + SCpnt->allowed, SCpnt->retries); #endif - if ((++SCpnt->retries) < SCpnt->allowed) - { - if ((SCpnt->retries >= (SCpnt->allowed >> 1)) - && !(SCpnt->host->resetting && time_before(jiffies, SCpnt->host->last_reset + MIN_RESET_PERIOD)) - && !(SCpnt->flags & WAS_RESET)) - { - printk("scsi%d channel %d : resetting for second half of retries.\n", - SCpnt->host->host_no, SCpnt->channel); - scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); + if ((++SCpnt->retries) < SCpnt->allowed) { + if ((SCpnt->retries >= (SCpnt->allowed >> 1)) + && !(SCpnt->host->resetting && time_before(jiffies, SCpnt->host->last_reset + MIN_RESET_PERIOD)) + && !(SCpnt->flags & WAS_RESET)) { + printk("scsi%d channel %d : resetting for second half of retries.\n", + SCpnt->host->host_no, SCpnt->channel); + scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); + /* fall through to REDO */ + } + } else { + status = CMD_FINISHED; + break; + } /* fall through to REDO */ - } - } - else - { - status = CMD_FINISHED; - break; - } - /* fall through to REDO */ - case REDO: + case REDO: - if (SCpnt->flags & WAS_SENSE) - scsi_request_sense(SCpnt); - else - { - memcpy ((void *) SCpnt->cmnd, - (void*) SCpnt->data_cmnd, - sizeof(SCpnt->data_cmnd)); - memset ((void *) SCpnt->sense_buffer, 0, - sizeof(SCpnt->sense_buffer)); - SCpnt->request_buffer = SCpnt->buffer; - SCpnt->request_bufflen = SCpnt->bufflen; - SCpnt->use_sg = SCpnt->old_use_sg; - SCpnt->cmd_len = SCpnt->old_cmd_len; - SCpnt->result = 0; - internal_cmnd (SCpnt); + if (SCpnt->flags & WAS_SENSE) + scsi_request_sense(SCpnt); + else { + memcpy((void *) SCpnt->cmnd, + (void *) SCpnt->data_cmnd, + sizeof(SCpnt->data_cmnd)); + memset((void *) SCpnt->sense_buffer, 0, + sizeof(SCpnt->sense_buffer)); + SCpnt->request_buffer = SCpnt->buffer; + SCpnt->request_bufflen = SCpnt->bufflen; + SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->result = 0; + internal_cmnd(SCpnt); + } + break; + default: + INTERNAL_ERROR; } - break; - default: - INTERNAL_ERROR; - } - if (status == CMD_FINISHED) { + if (status == CMD_FINISHED) { #ifdef DEBUG - printk("Calling done function - at address %p\n", SCpnt->done); + printk("Calling done function - at address %p\n", SCpnt->done); #endif - host->host_busy--; /* Indicate that we are free */ - - if (host->block && host->host_busy == 0) { - host_active = NULL; + host->host_busy--; /* Indicate that we are free */ - /* For block devices "wake_up" is done in end_scsi_request */ - if (!SCSI_BLK_MAJOR(MAJOR(SCpnt->request.rq_dev))) { - struct Scsi_Host * next; + if (host->block && host->host_busy == 0) { + host_active = NULL; - for (next = host->block; next != host; next = next->block) - wake_up(&next->host_wait); - } + /* For block devices "wake_up" is done in end_scsi_request */ + if (!SCSI_BLK_MAJOR(MAJOR(SCpnt->request.rq_dev))) { + struct Scsi_Host *next; + for (next = host->block; next != host; next = next->block) + wake_up(&next->host_wait); + } + } + wake_up(&host->host_wait); + SCpnt->result = result | ((exit & 0xff) << 24); + SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->done(SCpnt); } - - wake_up(&host->host_wait); - SCpnt->result = result | ((exit & 0xff) << 24); - SCpnt->use_sg = SCpnt->old_use_sg; - SCpnt->cmd_len = SCpnt->old_cmd_len; - SCpnt->done (SCpnt); - } - #undef CMD_FINISHED #undef REDO #undef MAYREDO @@ -709,110 +680,104 @@ */ -static int scsi_abort (Scsi_Cmnd * SCpnt, int why) +static int scsi_abort(Scsi_Cmnd * SCpnt, int why) { - int oldto; - struct Scsi_Host * host = SCpnt->host; - - while(1) - { + int oldto; + struct Scsi_Host *host = SCpnt->host; - /* - * Protect against races here. If the command is done, or we are - * on a different command forget it. - */ - if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) { - return 0; - } + while (1) { - if (SCpnt->internal_timeout & IN_ABORT) - { - spin_unlock_irq(&io_request_lock); - while (SCpnt->internal_timeout & IN_ABORT) - barrier(); - spin_lock_irq(&io_request_lock); - } - else - { - SCpnt->internal_timeout |= IN_ABORT; - oldto = update_timeout(SCpnt, ABORT_TIMEOUT); - - if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) { - /* OK, this command must have died when we did the - * reset. The device itself must have lied. - */ - printk("Stale command on %d %d:%d appears to have died when" - " the bus was reset\n", - SCpnt->channel, SCpnt->target, SCpnt->lun); - } - - if (!host->host_busy) { - SCpnt->internal_timeout &= ~IN_ABORT; - update_timeout(SCpnt, oldto); - return 0; - } - printk("scsi : aborting command due to timeout : pid %lu, scsi%d," - " channel %d, id %d, lun %d ", - SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel, - (int) SCpnt->target, (int) SCpnt->lun); - print_command (SCpnt->cmnd); - if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) - return 0; - SCpnt->abort_reason = why; - switch(host->hostt->abort(SCpnt)) { - /* We do not know how to abort. Try waiting another - * time increment and see if this helps. Set the - * WAS_TIMEDOUT flag set so we do not try this twice + /* + * Protect against races here. If the command is done, or we are + * on a different command forget it. */ - case SCSI_ABORT_BUSY: /* Tough call - returning 1 from - * this is too severe - */ - case SCSI_ABORT_SNOOZE: - if(why == DID_TIME_OUT) { - SCpnt->internal_timeout &= ~IN_ABORT; - if(SCpnt->flags & WAS_TIMEDOUT) { - return 1; /* Indicate we cannot handle this. - * We drop down into the reset handler - * and try again - */ - } else { - SCpnt->flags |= WAS_TIMEDOUT; - oldto = SCpnt->timeout_per_command; - update_timeout(SCpnt, oldto); - } + if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) { + return 0; } - return 0; - case SCSI_ABORT_PENDING: - if(why != DID_TIME_OUT) { - update_timeout(SCpnt, oldto); + if (SCpnt->internal_timeout & IN_ABORT) { + spin_unlock_irq(&io_request_lock); + while (SCpnt->internal_timeout & IN_ABORT) + barrier(); + spin_lock_irq(&io_request_lock); + } else { + SCpnt->internal_timeout |= IN_ABORT; + oldto = update_timeout(SCpnt, ABORT_TIMEOUT); + + if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) { + /* OK, this command must have died when we did the + * reset. The device itself must have lied. + */ + printk("Stale command on %d %d:%d appears to have died when" + " the bus was reset\n", + SCpnt->channel, SCpnt->target, SCpnt->lun); + } + if (!host->host_busy) { + SCpnt->internal_timeout &= ~IN_ABORT; + update_timeout(SCpnt, oldto); + return 0; + } + printk("scsi : aborting command due to timeout : pid %lu, scsi%d," + " channel %d, id %d, lun %d ", + SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel, + (int) SCpnt->target, (int) SCpnt->lun); + print_command(SCpnt->cmnd); + if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) + return 0; + SCpnt->abort_reason = why; + switch (host->hostt->abort(SCpnt)) { + /* We do not know how to abort. Try waiting another + * time increment and see if this helps. Set the + * WAS_TIMEDOUT flag set so we do not try this twice + */ + case SCSI_ABORT_BUSY: /* Tough call - returning 1 from + * this is too severe + */ + case SCSI_ABORT_SNOOZE: + if (why == DID_TIME_OUT) { + SCpnt->internal_timeout &= ~IN_ABORT; + if (SCpnt->flags & WAS_TIMEDOUT) { + return 1; /* Indicate we cannot handle this. + * We drop down into the reset handler + * and try again + */ + } else { + SCpnt->flags |= WAS_TIMEDOUT; + oldto = SCpnt->timeout_per_command; + update_timeout(SCpnt, oldto); + } + } + return 0; + case SCSI_ABORT_PENDING: + if (why != DID_TIME_OUT) { + update_timeout(SCpnt, oldto); + } + return 0; + case SCSI_ABORT_SUCCESS: + /* We should have already aborted this one. No + * need to adjust timeout + */ + SCpnt->internal_timeout &= ~IN_ABORT; + return 0; + case SCSI_ABORT_NOT_RUNNING: + SCpnt->internal_timeout &= ~IN_ABORT; + update_timeout(SCpnt, 0); + return 0; + case SCSI_ABORT_ERROR: + default: + SCpnt->internal_timeout &= ~IN_ABORT; + return 1; + } } - return 0; - case SCSI_ABORT_SUCCESS: - /* We should have already aborted this one. No - * need to adjust timeout - */ - SCpnt->internal_timeout &= ~IN_ABORT; - return 0; - case SCSI_ABORT_NOT_RUNNING: - SCpnt->internal_timeout &= ~IN_ABORT; - update_timeout(SCpnt, 0); - return 0; - case SCSI_ABORT_ERROR: - default: - SCpnt->internal_timeout &= ~IN_ABORT; - return 1; - } } - } } /* Mark a single SCSI Device as having been reset. */ -static inline void scsi_mark_device_reset(Scsi_Device *Device) +static inline void scsi_mark_device_reset(Scsi_Device * Device) { - Device->was_reset = 1; - Device->expecting_cc_ua = 1; + Device->was_reset = 1; + Device->expecting_cc_ua = 1; } @@ -820,14 +785,13 @@ void scsi_mark_host_reset(struct Scsi_Host *Host) { - Scsi_Cmnd * SCpnt; - Scsi_Device * SDpnt; + Scsi_Cmnd *SCpnt; + Scsi_Device *SDpnt; - for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) - scsi_mark_device_reset(SCpnt->device); - } + for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next) { + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) + scsi_mark_device_reset(SCpnt->device); + } } @@ -835,251 +799,243 @@ static void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel) { - Scsi_Cmnd *SCpnt; - Scsi_Device * SDpnt; + Scsi_Cmnd *SCpnt; + Scsi_Device *SDpnt; - for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) - if (SCpnt->channel == channel) - scsi_mark_device_reset(SCpnt->device); - } + for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next) { + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) + if (SCpnt->channel == channel) + scsi_mark_device_reset(SCpnt->device); + } } -static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) +static int scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) { - int temp; - Scsi_Cmnd * SCpnt1; - Scsi_Device * SDpnt; - struct Scsi_Host * host = SCpnt->host; + int temp; + Scsi_Cmnd *SCpnt1; + Scsi_Device *SDpnt; + struct Scsi_Host *host = SCpnt->host; - printk("SCSI bus is being reset for host %d channel %d.\n", - host->host_no, SCpnt->channel); + printk("SCSI bus is being reset for host %d channel %d.\n", + host->host_no, SCpnt->channel); #if 0 - /* - * First of all, we need to make a recommendation to the low-level - * driver as to whether a BUS_DEVICE_RESET should be performed, - * or whether we should do a full BUS_RESET. There is no simple - * algorithm here - we basically use a series of heuristics - * to determine what we should do. - */ - SCpnt->host->suggest_bus_reset = FALSE; - - /* - * First see if all of the active devices on the bus have - * been jammed up so that we are attempting resets. If so, - * then suggest a bus reset. Forcing a bus reset could - * result in some race conditions, but no more than - * you would usually get with timeouts. We will cross - * that bridge when we come to it. - * - * This is actually a pretty bad idea, since a sequence of - * commands will often timeout together and this will cause a - * Bus Device Reset followed immediately by a SCSI Bus Reset. - * If all of the active devices really are jammed up, the - * Bus Device Reset will quickly timeout and scsi_times_out - * will follow up with a SCSI Bus Reset anyway. - */ - SCpnt1 = host->host_queue; - while(SCpnt1) { - if( SCpnt1->request.rq_status != RQ_INACTIVE - && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 ) - break; - SCpnt1 = SCpnt1->next; - } - if( SCpnt1 == NULL ) { - reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET; - } - - /* - * If the code that called us is suggesting a hard reset, then - * definitely request it. This usually occurs because a - * BUS_DEVICE_RESET times out. - * - * Passing reset_flags along takes care of this automatically. - */ - if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) { - SCpnt->host->suggest_bus_reset = TRUE; - } -#endif - - while (1) { + /* + * First of all, we need to make a recommendation to the low-level + * driver as to whether a BUS_DEVICE_RESET should be performed, + * or whether we should do a full BUS_RESET. There is no simple + * algorithm here - we basically use a series of heuristics + * to determine what we should do. + */ + SCpnt->host->suggest_bus_reset = FALSE; /* - * Protect against races here. If the command is done, or we are - * on a different command forget it. + * First see if all of the active devices on the bus have + * been jammed up so that we are attempting resets. If so, + * then suggest a bus reset. Forcing a bus reset could + * result in some race conditions, but no more than + * you would usually get with timeouts. We will cross + * that bridge when we come to it. + * + * This is actually a pretty bad idea, since a sequence of + * commands will often timeout together and this will cause a + * Bus Device Reset followed immediately by a SCSI Bus Reset. + * If all of the active devices really are jammed up, the + * Bus Device Reset will quickly timeout and scsi_times_out + * will follow up with a SCSI Bus Reset anyway. */ - if (reset_flags & SCSI_RESET_ASYNCHRONOUS) - if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) { - return 0; - } - - if (SCpnt->internal_timeout & IN_RESET) - { - spin_unlock_irq(&io_request_lock); - while (SCpnt->internal_timeout & IN_RESET) - barrier(); - spin_lock_irq(&io_request_lock); + SCpnt1 = host->host_queue; + while (SCpnt1) { + if (SCpnt1->request.rq_status != RQ_INACTIVE + && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0) + break; + SCpnt1 = SCpnt1->next; } - else - { - SCpnt->internal_timeout |= IN_RESET; - update_timeout(SCpnt, RESET_TIMEOUT); - - if (reset_flags & SCSI_RESET_SYNCHRONOUS) - SCpnt->flags |= SYNC_RESET; - if (host->host_busy) - { - for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - SCpnt1 = SDpnt->device_queue; - while(SCpnt1) { - if (SCpnt1->request.rq_status != RQ_INACTIVE) { -#if 0 - if (!(SCpnt1->flags & IS_RESETTING) && - !(SCpnt1->internal_timeout & IN_ABORT)) - scsi_abort(SCpnt1, DID_RESET); -#endif - SCpnt1->flags |= (WAS_RESET | IS_RESETTING); - } - SCpnt1 = SCpnt1->next; - } - } + if (SCpnt1 == NULL) { + reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET; + } + /* + * If the code that called us is suggesting a hard reset, then + * definitely request it. This usually occurs because a + * BUS_DEVICE_RESET times out. + * + * Passing reset_flags along takes care of this automatically. + */ + if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) { + SCpnt->host->suggest_bus_reset = TRUE; + } +#endif + + while (1) { - host->last_reset = jiffies; - host->resetting = 1; - /* - * I suppose that the host reset callback will not play - * with the resetting field. We have just set the resetting - * flag here. -arca - */ - temp = host->hostt->reset(SCpnt, reset_flags); - /* - This test allows the driver to introduce an additional bus - settle time delay by setting last_reset up to 20 seconds in - the future. In the normal case where the driver does not - modify last_reset, it must be assumed that the actual bus - reset occurred immediately prior to the return to this code, - and so last_reset must be updated to the current time, so - that the delay in internal_cmnd will guarantee at least a - MIN_RESET_DELAY bus settle time. - */ - if (host->last_reset - jiffies > 20UL * HZ) - host->last_reset = jiffies; - } - else - { - if (!host->block) host->host_busy++; - host->last_reset = jiffies; - host->resetting = 1; - SCpnt->flags |= (WAS_RESET | IS_RESETTING); /* - * I suppose that the host reset callback will not play - * with the resetting field. We have just set the resetting - * flag here. -arca + * Protect against races here. If the command is done, or we are + * on a different command forget it. */ - temp = host->hostt->reset(SCpnt, reset_flags); - if (time_before(host->last_reset, jiffies) || - (time_after(host->last_reset, jiffies + 20 * HZ))) - host->last_reset = jiffies; - if (!host->block) host->host_busy--; - } - if (reset_flags & SCSI_RESET_SYNCHRONOUS) - SCpnt->flags &= ~SYNC_RESET; + if (reset_flags & SCSI_RESET_ASYNCHRONOUS) + if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) { + return 0; + } + if (SCpnt->internal_timeout & IN_RESET) { + spin_unlock_irq(&io_request_lock); + while (SCpnt->internal_timeout & IN_RESET) + barrier(); + spin_lock_irq(&io_request_lock); + } else { + SCpnt->internal_timeout |= IN_RESET; + update_timeout(SCpnt, RESET_TIMEOUT); + + if (reset_flags & SCSI_RESET_SYNCHRONOUS) + SCpnt->flags |= SYNC_RESET; + if (host->host_busy) { + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + SCpnt1 = SDpnt->device_queue; + while (SCpnt1) { + if (SCpnt1->request.rq_status != RQ_INACTIVE) { +#if 0 + if (!(SCpnt1->flags & IS_RESETTING) && + !(SCpnt1->internal_timeout & IN_ABORT)) + scsi_abort(SCpnt1, DID_RESET); +#endif + SCpnt1->flags |= (WAS_RESET | IS_RESETTING); + } + SCpnt1 = SCpnt1->next; + } + } + + host->last_reset = jiffies; + host->resetting = 1; + /* + * I suppose that the host reset callback will not play + * with the resetting field. We have just set the resetting + * flag here. -arca + */ + temp = host->hostt->reset(SCpnt, reset_flags); + /* + This test allows the driver to introduce an additional bus + settle time delay by setting last_reset up to 20 seconds in + the future. In the normal case where the driver does not + modify last_reset, it must be assumed that the actual bus + reset occurred immediately prior to the return to this code, + and so last_reset must be updated to the current time, so + that the delay in internal_cmnd will guarantee at least a + MIN_RESET_DELAY bus settle time. + */ + if (host->last_reset - jiffies > 20UL * HZ) + host->last_reset = jiffies; + } else { + if (!host->block) + host->host_busy++; + host->last_reset = jiffies; + host->resetting = 1; + SCpnt->flags |= (WAS_RESET | IS_RESETTING); + /* + * I suppose that the host reset callback will not play + * with the resetting field. We have just set the resetting + * flag here. -arca + */ + temp = host->hostt->reset(SCpnt, reset_flags); + if (time_before(host->last_reset, jiffies) || + (time_after(host->last_reset, jiffies + 20 * HZ))) + host->last_reset = jiffies; + if (!host->block) + host->host_busy--; + } + if (reset_flags & SCSI_RESET_SYNCHRONOUS) + SCpnt->flags &= ~SYNC_RESET; #ifdef DEBUG - printk("scsi reset function returned %d\n", temp); + printk("scsi reset function returned %d\n", temp); #endif - /* - * Now figure out what we need to do, based upon - * what the low level driver said that it did. - * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING, - * or SCSI_RESET_WAKEUP, then the low level driver did a - * bus device reset or bus reset, so we should go through - * and mark one or all of the devices on that bus - * as having been reset. - */ - switch(temp & SCSI_RESET_ACTION) { - case SCSI_RESET_SUCCESS: - if (temp & SCSI_RESET_HOST_RESET) - scsi_mark_host_reset(host); - else if (temp & SCSI_RESET_BUS_RESET) - scsi_mark_bus_reset(host, SCpnt->channel); - else scsi_mark_device_reset(SCpnt->device); - SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3); - return 0; - case SCSI_RESET_PENDING: - if (temp & SCSI_RESET_HOST_RESET) - scsi_mark_host_reset(host); - else if (temp & SCSI_RESET_BUS_RESET) - scsi_mark_bus_reset(host, SCpnt->channel); - else scsi_mark_device_reset(SCpnt->device); - case SCSI_RESET_NOT_RUNNING: - return 0; - case SCSI_RESET_PUNT: - SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3); - scsi_request_sense (SCpnt); - return 0; - case SCSI_RESET_WAKEUP: - if (temp & SCSI_RESET_HOST_RESET) - scsi_mark_host_reset(host); - else if (temp & SCSI_RESET_BUS_RESET) - scsi_mark_bus_reset(host, SCpnt->channel); - else scsi_mark_device_reset(SCpnt->device); - SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3); - scsi_request_sense (SCpnt); - /* - * If a bus reset was performed, we - * need to wake up each and every command - * that was active on the bus or if it was a HBA - * reset all active commands on all channels - */ - if( temp & SCSI_RESET_HOST_RESET ) - { - for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - SCpnt1 = SDpnt->device_queue; - while(SCpnt1) { - if (SCpnt1->request.rq_status != RQ_INACTIVE - && SCpnt1 != SCpnt) - scsi_request_sense (SCpnt1); - SCpnt1 = SCpnt1->next; - } - } - } else if( temp & SCSI_RESET_BUS_RESET ) { - for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) - { - SCpnt1 = SDpnt->device_queue; - while(SCpnt1) { - if(SCpnt1->request.rq_status != RQ_INACTIVE - && SCpnt1 != SCpnt - && SCpnt1->channel == SCpnt->channel) - scsi_request_sense (SCpnt); - SCpnt1 = SCpnt1->next; - } - } - } - return 0; - case SCSI_RESET_SNOOZE: - /* In this case, we set the timeout field to 0 - * so that this command does not time out any more, - * and we return 1 so that we get a message on the - * screen. - */ - SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3); - update_timeout(SCpnt, 0); - /* If you snooze, you lose... */ - case SCSI_RESET_ERROR: - default: - return 1; - } + /* + * Now figure out what we need to do, based upon + * what the low level driver said that it did. + * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING, + * or SCSI_RESET_WAKEUP, then the low level driver did a + * bus device reset or bus reset, so we should go through + * and mark one or all of the devices on that bus + * as having been reset. + */ + switch (temp & SCSI_RESET_ACTION) { + case SCSI_RESET_SUCCESS: + if (temp & SCSI_RESET_HOST_RESET) + scsi_mark_host_reset(host); + else if (temp & SCSI_RESET_BUS_RESET) + scsi_mark_bus_reset(host, SCpnt->channel); + else + scsi_mark_device_reset(SCpnt->device); + SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2 | IN_RESET3); + return 0; + case SCSI_RESET_PENDING: + if (temp & SCSI_RESET_HOST_RESET) + scsi_mark_host_reset(host); + else if (temp & SCSI_RESET_BUS_RESET) + scsi_mark_bus_reset(host, SCpnt->channel); + else + scsi_mark_device_reset(SCpnt->device); + case SCSI_RESET_NOT_RUNNING: + return 0; + case SCSI_RESET_PUNT: + SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2 | IN_RESET3); + scsi_request_sense(SCpnt); + return 0; + case SCSI_RESET_WAKEUP: + if (temp & SCSI_RESET_HOST_RESET) + scsi_mark_host_reset(host); + else if (temp & SCSI_RESET_BUS_RESET) + scsi_mark_bus_reset(host, SCpnt->channel); + else + scsi_mark_device_reset(SCpnt->device); + SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2 | IN_RESET3); + scsi_request_sense(SCpnt); + /* + * If a bus reset was performed, we + * need to wake up each and every command + * that was active on the bus or if it was a HBA + * reset all active commands on all channels + */ + if (temp & SCSI_RESET_HOST_RESET) { + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + SCpnt1 = SDpnt->device_queue; + while (SCpnt1) { + if (SCpnt1->request.rq_status != RQ_INACTIVE + && SCpnt1 != SCpnt) + scsi_request_sense(SCpnt1); + SCpnt1 = SCpnt1->next; + } + } + } else if (temp & SCSI_RESET_BUS_RESET) { + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { + SCpnt1 = SDpnt->device_queue; + while (SCpnt1) { + if (SCpnt1->request.rq_status != RQ_INACTIVE + && SCpnt1 != SCpnt + && SCpnt1->channel == SCpnt->channel) + scsi_request_sense(SCpnt); + SCpnt1 = SCpnt1->next; + } + } + } + return 0; + case SCSI_RESET_SNOOZE: + /* In this case, we set the timeout field to 0 + * so that this command does not time out any more, + * and we return 1 so that we get a message on the + * screen. + */ + SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2 | IN_RESET3); + update_timeout(SCpnt, 0); + /* If you snooze, you lose... */ + case SCSI_RESET_ERROR: + default: + return 1; + } - return temp; + return temp; + } } - } } /* @@ -1092,32 +1048,26 @@ int update_timeout(Scsi_Cmnd * SCset, int timeout) { - int rtn; + int rtn; - /* - * We are using the new error handling code to actually register/deregister - * timers for timeout. - */ - - if( !timer_pending(&SCset->eh_timeout) ) - { - rtn = 0; - } - else - { - rtn = SCset->eh_timeout.expires - jiffies; - } - - if( timeout == 0 ) - { - scsi_delete_timer(SCset); - } - else - { - scsi_add_timer(SCset, timeout, scsi_old_times_out); - } + /* + * We are using the new error handling code to actually register/deregister + * timers for timeout. + */ + + if (!timer_pending(&SCset->eh_timeout)) { + rtn = 0; + } else { + rtn = SCset->eh_timeout.expires - jiffies; + } + + if (timeout == 0) { + scsi_delete_timer(SCset); + } else { + scsi_add_timer(SCset, timeout, scsi_old_times_out); + } - return rtn; + return rtn; } diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_obsolete.h linux/drivers/scsi/scsi_obsolete.h --- v2.3.16/linux/drivers/scsi/scsi_obsolete.h Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/scsi_obsolete.h Sat Sep 4 10:48:46 1999 @@ -17,7 +17,7 @@ /* We did not do anything. * Wait some more for this command to complete, and if this does not work, - * try something more serious. */ + * try something more serious. */ #define SCSI_ABORT_SNOOZE 0 /* This means that we were able to abort the command. We have already @@ -103,4 +103,4 @@ */ #define SCSI_RESET_ACTION 0xff -#endif /* SCSI_OBSOLETE_H */ +#endif /* SCSI_OBSOLETE_H */ diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c --- v2.3.16/linux/drivers/scsi/scsi_proc.c Wed Jun 9 16:59:16 1999 +++ linux/drivers/scsi/scsi_proc.c Sat Sep 4 10:48:46 1999 @@ -16,7 +16,7 @@ * Michael A. Griffith */ -#include /* for CONFIG_PROC_FS */ +#include /* for CONFIG_PROC_FS */ #define __NO_VERSION__ #include @@ -37,284 +37,275 @@ #ifdef CONFIG_PROC_FS extern int scsi_proc_info(char *, char **, off_t, int, int, int); - + struct scsi_dir { - struct proc_dir_entry entry; - char name[4]; + struct proc_dir_entry entry; + char name[4]; }; /* generic_proc_info * Used if the driver currently has no own support for /proc/scsi */ -int generic_proc_info(char *buffer, char **start, off_t offset, - int length, int inode, int inout, - const char *(*info)(struct Scsi_Host *), - struct Scsi_Host *sh) +int generic_proc_info(char *buffer, char **start, off_t offset, + int length, int inode, int inout, + const char *(*info) (struct Scsi_Host *), + struct Scsi_Host *sh) { - int len, pos, begin; + int len, pos, begin; + + if (inout == TRUE) + return (-ENOSYS); /* This is a no-op */ + + begin = 0; + if (info && sh) { + pos = len = sprintf(buffer, "%s\n", info(sh)); + } else { + pos = len = sprintf(buffer, + "The driver does not yet support the proc-fs\n"); + } + if (pos < offset) { + len = 0; + begin = pos; + } + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); + if (len > length) + len = length; - if(inout == TRUE) - return(-ENOSYS); /* This is a no-op */ - - begin = 0; - if (info && sh) { - pos = len = sprintf(buffer, "%s\n", info(sh)); - } - else { - pos = len = sprintf(buffer, - "The driver does not yet support the proc-fs\n"); - } - if(pos < offset) { - len = 0; - begin = pos; - } - - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); - if(len > length) - len = length; - - return(len); + return (len); } /* dispatch_scsi_info is the central dispatcher * It is the interface between the proc-fs and the SCSI subsystem code */ -extern int dispatch_scsi_info(int ino, char *buffer, char **start, +extern int dispatch_scsi_info(int ino, char *buffer, char **start, off_t offset, int length, int func) { - struct Scsi_Host *hpnt = scsi_hostlist; - - if(ino == PROC_SCSI_SCSI) { - /* - * This is for the scsi core, rather than any specific - * lowlevel driver. - */ - return(scsi_proc_info(buffer, start, offset, length, 0, func)); - } - - while(hpnt) { - if (ino == (hpnt->host_no + PROC_SCSI_FILE)) { - if(hpnt->hostt->proc_info == NULL) - return generic_proc_info(buffer, start, offset, length, - hpnt->host_no, func, - hpnt->hostt->info, - hpnt); - else - return(hpnt->hostt->proc_info(buffer, start, offset, - length, hpnt->host_no, func)); - } - hpnt = hpnt->next; - } - return(-EBADF); + struct Scsi_Host *hpnt = scsi_hostlist; + + if (ino == PROC_SCSI_SCSI) { + /* + * This is for the scsi core, rather than any specific + * lowlevel driver. + */ + return (scsi_proc_info(buffer, start, offset, length, 0, func)); + } + while (hpnt) { + if (ino == (hpnt->host_no + PROC_SCSI_FILE)) { + if (hpnt->hostt->proc_info == NULL) + return generic_proc_info(buffer, start, offset, length, + hpnt->host_no, func, + hpnt->hostt->info, + hpnt); + else + return (hpnt->hostt->proc_info(buffer, start, offset, + length, hpnt->host_no, func)); + } + hpnt = hpnt->next; + } + return (-EBADF); } static void scsi_proc_fill_inode(struct inode *inode, int fill) { -Scsi_Host_Template *shpnt; + Scsi_Host_Template *shpnt; -shpnt = scsi_hosts; -while (shpnt && shpnt->proc_dir->low_ino != inode->i_ino) - shpnt = shpnt->next; -if (!shpnt || !shpnt->module) - return; -if (fill) - __MOD_INC_USE_COUNT(shpnt->module); -else - __MOD_DEC_USE_COUNT(shpnt->module); + shpnt = scsi_hosts; + while (shpnt && shpnt->proc_dir->low_ino != inode->i_ino) + shpnt = shpnt->next; + if (!shpnt || !shpnt->module) + return; + if (fill) + __MOD_INC_USE_COUNT(shpnt->module); + else + __MOD_DEC_USE_COUNT(shpnt->module); } -void build_proc_dir_entries(Scsi_Host_Template *tpnt) +void build_proc_dir_entries(Scsi_Host_Template * tpnt) { - struct Scsi_Host *hpnt; - struct scsi_dir *scsi_hba_dir; + struct Scsi_Host *hpnt; + struct scsi_dir *scsi_hba_dir; - proc_scsi_register(0, tpnt->proc_dir); - tpnt->proc_dir->fill_inode = &scsi_proc_fill_inode; + proc_scsi_register(0, tpnt->proc_dir); + tpnt->proc_dir->fill_inode = &scsi_proc_fill_inode; - hpnt = scsi_hostlist; - while (hpnt) { - if (tpnt == hpnt->hostt) { - scsi_hba_dir = scsi_init_malloc(sizeof(struct scsi_dir), GFP_KERNEL); - if(scsi_hba_dir == NULL) - panic("Not enough memory to register SCSI HBA in /proc/scsi !\n"); - memset(scsi_hba_dir, 0, sizeof(struct scsi_dir)); - scsi_hba_dir->entry.low_ino = PROC_SCSI_FILE + hpnt->host_no; - scsi_hba_dir->entry.namelen = sprintf(scsi_hba_dir->name,"%d", - hpnt->host_no); - scsi_hba_dir->entry.name = scsi_hba_dir->name; - scsi_hba_dir->entry.mode = S_IFREG | S_IRUGO | S_IWUSR; - proc_scsi_register(tpnt->proc_dir, &scsi_hba_dir->entry); - } - hpnt = hpnt->next; - } + hpnt = scsi_hostlist; + while (hpnt) { + if (tpnt == hpnt->hostt) { + scsi_hba_dir = scsi_init_malloc(sizeof(struct scsi_dir), GFP_KERNEL); + if (scsi_hba_dir == NULL) + panic("Not enough memory to register SCSI HBA in /proc/scsi !\n"); + memset(scsi_hba_dir, 0, sizeof(struct scsi_dir)); + scsi_hba_dir->entry.low_ino = PROC_SCSI_FILE + hpnt->host_no; + scsi_hba_dir->entry.namelen = sprintf(scsi_hba_dir->name, "%d", + hpnt->host_no); + scsi_hba_dir->entry.name = scsi_hba_dir->name; + scsi_hba_dir->entry.mode = S_IFREG | S_IRUGO | S_IWUSR; + proc_scsi_register(tpnt->proc_dir, &scsi_hba_dir->entry); + } + hpnt = hpnt->next; + } } /* * parseHandle *parseInit(char *buf, char *cmdList, int cmdNum); - * gets a pointer to a null terminated data buffer - * and a list of commands with blanks as delimiter + * gets a pointer to a null terminated data buffer + * and a list of commands with blanks as delimiter * in between. * The commands have to be alphanumerically sorted. * cmdNum has to contain the number of commands. - * On success, a pointer to a handle structure - * is returned, NULL on failure + * On success, a pointer to a handle structure + * is returned, NULL on failure * - * int parseOpt(parseHandle *handle, char **param); - * processes the next parameter. On success, the - * index of the appropriate command in the cmdList - * is returned, starting with zero. - * param points to the null terminated parameter string. - * On failure, -1 is returned. + * int parseOpt(parseHandle *handle, char **param); + * processes the next parameter. On success, the + * index of the appropriate command in the cmdList + * is returned, starting with zero. + * param points to the null terminated parameter string. + * On failure, -1 is returned. * - * The databuffer buf may only contain pairs of commands - * options, separated by blanks: - * [ ]* + * The databuffer buf may only contain pairs of commands + * options, separated by blanks: + * [ ]* */ -typedef struct -{ - char *buf, /* command buffer */ - *cmdList, /* command list */ - *bufPos, /* actual position */ - **cmdPos, /* cmdList index */ - cmdNum; /* cmd number */ +typedef struct { + char *buf, /* command buffer */ + *cmdList, /* command list */ + *bufPos, /* actual position */ + **cmdPos, /* cmdList index */ + cmdNum; /* cmd number */ } parseHandle; - -inline int parseFree (parseHandle *handle) /* free memory */ -{ - kfree (handle->cmdPos); - kfree (handle); - - return(-1); + +inline int parseFree(parseHandle * handle) +{ /* free memory */ + kfree(handle->cmdPos); + kfree(handle); + + return (-1); } - + parseHandle *parseInit(char *buf, char *cmdList, int cmdNum) { - char *ptr; /* temp pointer */ - parseHandle *handle; /* new handle */ - - if (!buf || !cmdList) /* bad input ? */ - return(NULL); - if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), GFP_KERNEL)) == 0) - return(NULL); /* out of memory */ - if ((handle->cmdPos = (char**) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL)) == 0) { - kfree(handle); - return(NULL); /* out of memory */ - } - - handle->buf = handle->bufPos = buf; /* init handle */ - handle->cmdList = cmdList; - handle->cmdNum = cmdNum; - - handle->cmdPos[cmdNum = 0] = cmdList; - for (ptr = cmdList; *ptr; ptr++) { /* scan command string */ - if(*ptr == ' ') { /* and insert zeroes */ - *ptr++ = 0; - handle->cmdPos[++cmdNum] = ptr++; - } - } - return(handle); + char *ptr; /* temp pointer */ + parseHandle *handle; /* new handle */ + + if (!buf || !cmdList) /* bad input ? */ + return (NULL); + if ((handle = (parseHandle *) kmalloc(sizeof(parseHandle), GFP_KERNEL)) == 0) + return (NULL); /* out of memory */ + if ((handle->cmdPos = (char **) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL)) == 0) { + kfree(handle); + return (NULL); /* out of memory */ + } + handle->buf = handle->bufPos = buf; /* init handle */ + handle->cmdList = cmdList; + handle->cmdNum = cmdNum; + + handle->cmdPos[cmdNum = 0] = cmdList; + for (ptr = cmdList; *ptr; ptr++) { /* scan command string */ + if (*ptr == ' ') { /* and insert zeroes */ + *ptr++ = 0; + handle->cmdPos[++cmdNum] = ptr++; + } + } + return (handle); } -int parseOpt(parseHandle *handle, char **param) +int parseOpt(parseHandle * handle, char **param) { - int cmdIndex = 0, - cmdLen = 0; - char *startPos; - - if (!handle) /* invalid handle */ - return(parseFree(handle)); - /* skip spaces */ - for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++); - if (!*(handle->bufPos)) - return(parseFree(handle)); /* end of data */ - - startPos = handle->bufPos; /* store cmd start */ - for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++) - { /* no string end? */ - for (;;) - { - if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen]) - break; /* char matches ? */ - else - if (memcmp(startPos, (char*)(handle->cmdPos[++cmdIndex]), cmdLen)) - return(parseFree(handle)); /* unknown command */ - - if (cmdIndex >= handle->cmdNum) - return(parseFree(handle)); /* unknown command */ - } - - cmdLen++; /* next char */ - } - - /* Get param. First skip all blanks, then insert zero after param */ - - for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++); - *param = handle->bufPos; - - for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++); - *(handle->bufPos++) = 0; - - return(cmdIndex); + int cmdIndex = 0, cmdLen = 0; + char *startPos; + + if (!handle) /* invalid handle */ + return (parseFree(handle)); + /* skip spaces */ + for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++); + if (!*(handle->bufPos)) + return (parseFree(handle)); /* end of data */ + + startPos = handle->bufPos; /* store cmd start */ + for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++) { /* no string end? */ + for (;;) { + if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen]) + break; /* char matches ? */ + else if (memcmp(startPos, (char *) (handle->cmdPos[++cmdIndex]), cmdLen)) + return (parseFree(handle)); /* unknown command */ + + if (cmdIndex >= handle->cmdNum) + return (parseFree(handle)); /* unknown command */ + } + + cmdLen++; /* next char */ + } + + /* Get param. First skip all blanks, then insert zero after param */ + + for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++); + *param = handle->bufPos; + + for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++); + *(handle->bufPos++) = 0; + + return (cmdIndex); } -void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len) -{ - - int x, y = *size; - extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; - - y = sprintf(buffer + len, - "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ", +void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len) +{ + + int x, y = *size; + extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; + + y = sprintf(buffer + len, + "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ", scd->host->host_no, scd->channel, scd->id, scd->lun); - for (x = 0; x < 8; x++) { - if (scd->vendor[x] >= 0x20) - y += sprintf(buffer + len + y, "%c", scd->vendor[x]); - else - y += sprintf(buffer + len + y," "); - } - y += sprintf(buffer + len + y, " Model: "); - for (x = 0; x < 16; x++) { - if (scd->model[x] >= 0x20) - y += sprintf(buffer + len + y, "%c", scd->model[x]); - else - y += sprintf(buffer + len + y, " "); - } - y += sprintf(buffer + len + y, " Rev: "); - for (x = 0; x < 4; x++) { - if (scd->rev[x] >= 0x20) - y += sprintf(buffer + len + y, "%c", scd->rev[x]); - else - y += sprintf(buffer + len + y, " "); - } - y += sprintf(buffer + len + y, "\n"); - - y += sprintf(buffer + len + y, " Type: %s ", - scd->type < MAX_SCSI_DEVICE_CODE ? - scsi_device_types[(int)scd->type] : "Unknown " ); - y += sprintf(buffer + len + y, " ANSI" - " SCSI revision: %02x", (scd->scsi_level - 1)?scd->scsi_level - 1:1); - if (scd->scsi_level == 2) - y += sprintf(buffer + len + y, " CCS\n"); - else + for (x = 0; x < 8; x++) { + if (scd->vendor[x] >= 0x20) + y += sprintf(buffer + len + y, "%c", scd->vendor[x]); + else + y += sprintf(buffer + len + y, " "); + } + y += sprintf(buffer + len + y, " Model: "); + for (x = 0; x < 16; x++) { + if (scd->model[x] >= 0x20) + y += sprintf(buffer + len + y, "%c", scd->model[x]); + else + y += sprintf(buffer + len + y, " "); + } + y += sprintf(buffer + len + y, " Rev: "); + for (x = 0; x < 4; x++) { + if (scd->rev[x] >= 0x20) + y += sprintf(buffer + len + y, "%c", scd->rev[x]); + else + y += sprintf(buffer + len + y, " "); + } y += sprintf(buffer + len + y, "\n"); - *size = y; - return; + y += sprintf(buffer + len + y, " Type: %s ", + scd->type < MAX_SCSI_DEVICE_CODE ? + scsi_device_types[(int) scd->type] : "Unknown "); + y += sprintf(buffer + len + y, " ANSI" + " SCSI revision: %02x", (scd->scsi_level - 1) ? scd->scsi_level - 1 : 1); + if (scd->scsi_level == 2) + y += sprintf(buffer + len + y, " CCS\n"); + else + y += sprintf(buffer + len + y, "\n"); + + *size = y; + return; } #else -void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len) +void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len) { } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_PROC_FS */ /* * Overrides for Emacs so that we get a uniform tabbing style. @@ -334,4 +325,3 @@ * tab-width: 8 * End: */ - diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_queue.c linux/drivers/scsi/scsi_queue.c --- v2.3.16/linux/drivers/scsi/scsi_queue.c Mon Jul 27 18:22:12 1998 +++ linux/drivers/scsi/scsi_queue.c Sat Sep 4 10:48:46 1999 @@ -39,19 +39,19 @@ /* * TODO: - * 1) Prevent multiple traversals of list to look for commands to - * queue. - * 2) Protect against multiple insertions of list at the same time. + * 1) Prevent multiple traversals of list to look for commands to + * queue. + * 2) Protect against multiple insertions of list at the same time. * DONE: - * 1) Set state of scsi command to a new state value for ml queue. - * 2) Insert into queue when host rejects command. - * 3) Make sure status code is properly passed from low-level queue func - * so that internal_cmnd properly returns the right value. - * 4) Insert into queue when QUEUE_FULL. - * 5) Cull queue in bottom half handler. - * 6) Check usage count prior to queue insertion. Requeue if usage - * count is 0. - * 7) Don't send down any more commands if the host/device is busy. + * 1) Set state of scsi command to a new state value for ml queue. + * 2) Insert into queue when host rejects command. + * 3) Make sure status code is properly passed from low-level queue func + * so that internal_cmnd properly returns the right value. + * 4) Insert into queue when QUEUE_FULL. + * 5) Cull queue in bottom half handler. + * 6) Check usage count prior to queue insertion. Requeue if usage + * count is 0. + * 7) Don't send down any more commands if the host/device is busy. */ static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_queue.c,v 1.1 1997/10/21 11:16:38 eric Exp $"; @@ -61,8 +61,9 @@ * same time. FIXME(eric) - there should be separate spinlocks for each host. * This will reduce contention. */ -spinlock_t scsi_mlqueue_lock = SPIN_LOCK_UNLOCKED; -spinlock_t scsi_mlqueue_remove_lock = SPIN_LOCK_UNLOCKED; + +spinlock_t scsi_mlqueue_lock = SPIN_LOCK_UNLOCKED; +spinlock_t scsi_mlqueue_remove_lock = SPIN_LOCK_UNLOCKED; /* * Function: scsi_mlqueue_insert() @@ -70,127 +71,110 @@ * Purpose: Insert a command in the midlevel queue. * * Arguments: cmd - command that we are adding to queue. - * reason - why we are inserting command to queue. + * reason - why we are inserting command to queue. * * Returns: Nothing. * - * Notes: We do this for one of two cases. Either the host is busy - * and it cannot accept any more commands for the time being, - * or the device returned QUEUE_FULL and can accept no more - * commands. - * Notes: This could be called either from an interrupt context or a - * normal process context. + * Notes: We do this for one of two cases. Either the host is busy + * and it cannot accept any more commands for the time being, + * or the device returned QUEUE_FULL and can accept no more + * commands. + * Notes: This could be called either from an interrupt context or a + * normal process context. */ -int -scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason) +int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason) { - Scsi_Cmnd * cpnt; - unsigned long flags; - struct Scsi_Host * host; - - SCSI_LOG_MLQUEUE(1,printk("Inserting command %p into mlqueue\n", cmd)); - - /* - * We are inserting the command into the ml queue. First, we - * cancel the timer, so it doesn't time out. - */ - scsi_delete_timer(cmd); - - host = cmd->host; - - /* - * Next, set the appropriate busy bit for the device/host. - */ - if( reason == SCSI_MLQUEUE_HOST_BUSY ) - { - /* - * Protect against race conditions. If the host isn't busy, - * assume that something actually completed, and that we should - * be able to queue a command now. Note that there is an implicit - * assumption that every host can always queue at least one command. - * If a host is inactive and cannot queue any commands, I don't see - * how things could possibly work anyways. - */ - if( host->host_busy == 0 ) - { - if( scsi_retry_command(cmd) == 0 ) - { - return 0; - } + Scsi_Cmnd *cpnt; + unsigned long flags; + struct Scsi_Host *host; + + SCSI_LOG_MLQUEUE(1, printk("Inserting command %p into mlqueue\n", cmd)); + + /* + * We are inserting the command into the ml queue. First, we + * cancel the timer, so it doesn't time out. + */ + scsi_delete_timer(cmd); + + host = cmd->host; + + /* + * Next, set the appropriate busy bit for the device/host. + */ + if (reason == SCSI_MLQUEUE_HOST_BUSY) { + /* + * Protect against race conditions. If the host isn't busy, + * assume that something actually completed, and that we should + * be able to queue a command now. Note that there is an implicit + * assumption that every host can always queue at least one command. + * If a host is inactive and cannot queue any commands, I don't see + * how things could possibly work anyways. + */ + if (host->host_busy == 0) { + if (scsi_retry_command(cmd) == 0) { + return 0; + } + } + host->host_blocked = TRUE; + cmd->host_wait = TRUE; + } else { + /* + * Protect against race conditions. If the device isn't busy, + * assume that something actually completed, and that we should + * be able to queue a command now. Note that there is an implicit + * assumption that every host can always queue at least one command. + * If a host is inactive and cannot queue any commands, I don't see + * how things could possibly work anyways. + */ + if (cmd->device->device_busy == 0) { + if (scsi_retry_command(cmd) == 0) { + return 0; + } + } + cmd->device->device_busy = TRUE; + cmd->device_wait = TRUE; + } + + /* + * Register the fact that we own the thing for now. + */ + cmd->state = SCSI_STATE_MLQUEUE; + cmd->owner = SCSI_OWNER_MIDLEVEL; + cmd->bh_next = NULL; + + /* + * As a performance enhancement, look to see whether the list is + * empty. If it is, then we can just atomicly insert the command + * in the list and return without locking. + */ + if (host->pending_commands == NULL) { + cpnt = xchg(&host->pending_commands, cmd); + if (cpnt == NULL) { + return 0; + } + /* + * Rats. Something slipped in while we were exchanging. + * Swap it back and fall through to do it the hard way. + */ + cmd = xchg(&host->pending_commands, cpnt); + + } + /* + * Next append the command to the list of pending commands. + */ + spin_lock_irqsave(&scsi_mlqueue_lock, flags); + for (cpnt = host->pending_commands; cpnt && cpnt->bh_next; + cpnt = cpnt->bh_next) { + continue; } - - host->host_blocked = TRUE; - cmd->host_wait = TRUE; - } - else - { - /* - * Protect against race conditions. If the device isn't busy, - * assume that something actually completed, and that we should - * be able to queue a command now. Note that there is an implicit - * assumption that every host can always queue at least one command. - * If a host is inactive and cannot queue any commands, I don't see - * how things could possibly work anyways. - */ - if( cmd->device->device_busy == 0 ) - { - if( scsi_retry_command(cmd) == 0 ) - { - return 0; - } + if (cpnt != NULL) { + cpnt->bh_next = cmd; + } else { + host->pending_commands = cmd; } - cmd->device->device_busy = TRUE; - cmd->device_wait = TRUE; - } - - /* - * Register the fact that we own the thing for now. - */ - cmd->state = SCSI_STATE_MLQUEUE; - cmd->owner = SCSI_OWNER_MIDLEVEL; - cmd->bh_next = NULL; - - /* - * As a performance enhancement, look to see whether the list is - * empty. If it is, then we can just atomicly insert the command - * in the list and return without locking. - */ - if( host->pending_commands == NULL ) - { - cpnt = xchg(&host->pending_commands, cmd); - if( cpnt == NULL ) - { - return 0; - } - /* - * Rats. Something slipped in while we were exchanging. - * Swap it back and fall through to do it the hard way. - */ - cmd = xchg(&host->pending_commands, cpnt); - - } - - /* - * Next append the command to the list of pending commands. - */ - spin_lock_irqsave(&scsi_mlqueue_lock, flags); - for(cpnt = host->pending_commands; cpnt && cpnt->bh_next; - cpnt = cpnt->bh_next) - { - continue; - } - if( cpnt != NULL ) - { - cpnt->bh_next = cmd; - } - else - { - host->pending_commands = cmd; - } - - spin_unlock_irqrestore(&scsi_mlqueue_lock, flags); - return 0; + spin_unlock_irqrestore(&scsi_mlqueue_lock, flags); + return 0; } /* @@ -199,118 +183,102 @@ * Purpose: Try and queue commands from the midlevel queue. * * Arguments: host - host that just finished a command. - * device - device that just finished a command. + * device - device that just finished a command. * * Returns: Nothing. * - * Notes: This could be called either from an interrupt context or a - * normal process context. + * Notes: This could be called either from an interrupt context or a + * normal process context. */ -int -scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device) +int scsi_mlqueue_finish(struct Scsi_Host *host, Scsi_Device * device) { - Scsi_Cmnd * cpnt; - unsigned long flags; - Scsi_Cmnd * next; - Scsi_Cmnd * prev; - int reason = 0; - int rtn; - - SCSI_LOG_MLQUEUE(2,printk("scsi_mlqueue_finish starting\n")); - /* - * First, clear the flag for the host/device. We will then start - * pushing commands through until either something else blocks, or - * the queue is empty. - */ - if( host->host_blocked ) - { - reason = SCSI_MLQUEUE_HOST_BUSY; - host->host_blocked = FALSE; - } - - if( device->device_busy ) - { - reason = SCSI_MLQUEUE_DEVICE_BUSY; - device->device_busy = FALSE; - } - - /* - * Walk the list of commands to see if there is anything we can - * queue. This probably needs to be optimized for performance at - * some point. - */ - prev = NULL; - spin_lock_irqsave(&scsi_mlqueue_remove_lock, flags); - for(cpnt = host->pending_commands; cpnt; cpnt = next) - { - next = cpnt->bh_next; - /* - * First, see if this command is suitable for being retried now. - */ - if( reason == SCSI_MLQUEUE_HOST_BUSY ) - { - /* - * The host was busy, but isn't any more. Thus we may be - * able to queue the command now, but we were waiting for - * the device, then we should keep waiting. Similarily, if - * the device is now busy, we should also keep waiting. - */ - if( (cpnt->host_wait == FALSE) - || (device->device_busy == TRUE) ) - { - prev = cpnt; - continue; - } - } - - if( reason == SCSI_MLQUEUE_DEVICE_BUSY ) - { - /* - * The device was busy, but isn't any more. Thus we may be - * able to queue the command now, but we were waiting for - * the host, then we should keep waiting. Similarily, if - * the host is now busy, we should also keep waiting. - */ - if( (cpnt->device_wait == FALSE) - || (host->host_blocked == TRUE) ) - { - prev = cpnt; - continue; - } - } - - /* - * First, remove the command from the list. - */ - if( prev == NULL ) - { - host->pending_commands = next; - } - else - { - prev->bh_next = next; - } - cpnt->bh_next = NULL; - - rtn = scsi_retry_command(cpnt); - - /* - * If we got a non-zero return value, it means that the host rejected - * the command. The internal_cmnd function will have added the - * command back to the end of the list, so we don't have anything - * more to do here except return. - */ - if( rtn ) - { - spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags); - SCSI_LOG_MLQUEUE(1,printk("Unable to remove command %p from mlqueue\n", cpnt)); - goto finish; + Scsi_Cmnd *cpnt; + unsigned long flags; + Scsi_Cmnd *next; + Scsi_Cmnd *prev; + int reason = 0; + int rtn; + + SCSI_LOG_MLQUEUE(2, printk("scsi_mlqueue_finish starting\n")); + /* + * First, clear the flag for the host/device. We will then start + * pushing commands through until either something else blocks, or + * the queue is empty. + */ + if (host->host_blocked) { + reason = SCSI_MLQUEUE_HOST_BUSY; + host->host_blocked = FALSE; + } + if (device->device_busy) { + reason = SCSI_MLQUEUE_DEVICE_BUSY; + device->device_busy = FALSE; + } + /* + * Walk the list of commands to see if there is anything we can + * queue. This probably needs to be optimized for performance at + * some point. + */ + prev = NULL; + spin_lock_irqsave(&scsi_mlqueue_remove_lock, flags); + for (cpnt = host->pending_commands; cpnt; cpnt = next) { + next = cpnt->bh_next; + /* + * First, see if this command is suitable for being retried now. + */ + if (reason == SCSI_MLQUEUE_HOST_BUSY) { + /* + * The host was busy, but isn't any more. Thus we may be + * able to queue the command now, but we were waiting for + * the device, then we should keep waiting. Similarily, if + * the device is now busy, we should also keep waiting. + */ + if ((cpnt->host_wait == FALSE) + || (device->device_busy == TRUE)) { + prev = cpnt; + continue; + } + } + if (reason == SCSI_MLQUEUE_DEVICE_BUSY) { + /* + * The device was busy, but isn't any more. Thus we may be + * able to queue the command now, but we were waiting for + * the host, then we should keep waiting. Similarily, if + * the host is now busy, we should also keep waiting. + */ + if ((cpnt->device_wait == FALSE) + || (host->host_blocked == TRUE)) { + prev = cpnt; + continue; + } + } + /* + * First, remove the command from the list. + */ + if (prev == NULL) { + host->pending_commands = next; + } else { + prev->bh_next = next; + } + cpnt->bh_next = NULL; + + rtn = scsi_retry_command(cpnt); + + /* + * If we got a non-zero return value, it means that the host rejected + * the command. The internal_cmnd function will have added the + * command back to the end of the list, so we don't have anything + * more to do here except return. + */ + if (rtn) { + spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags); + SCSI_LOG_MLQUEUE(1, printk("Unable to remove command %p from mlqueue\n", cpnt)); + goto finish; + } + SCSI_LOG_MLQUEUE(1, printk("Removed command %p from mlqueue\n", cpnt)); } - SCSI_LOG_MLQUEUE(1,printk("Removed command %p from mlqueue\n", cpnt)); - } - spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags); + spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags); finish: - SCSI_LOG_MLQUEUE(2,printk("scsi_mlqueue_finish returning\n")); - return 0; + SCSI_LOG_MLQUEUE(2, printk("scsi_mlqueue_finish returning\n")); + return 0; } diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c --- v2.3.16/linux/drivers/scsi/scsicam.c Wed Jun 9 16:59:16 1999 +++ linux/drivers/scsi/scsicam.c Sat Sep 4 10:48:46 1999 @@ -5,7 +5,7 @@ * Visionary Computing * (Unix and Linux consulting and custom programming) * drew@Colorado.EDU - * +1 (303) 786-7975 + * +1 (303) 786-7975 * * For more information, please consult the SCSI-CAM draft. */ @@ -23,59 +23,58 @@ #include "sd.h" #include -static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds, - unsigned int *secs); +static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, + unsigned int *secs); /* * Function : int scsicam_bios_param (Disk *disk, int dev, int *ip) * * Purpose : to determine the BIOS mapping used for a drive in a - * SCSI-CAM system, storing the results in ip as required - * by the HDIO_GETGEO ioctl(). + * SCSI-CAM system, storing the results in ip as required + * by the HDIO_GETGEO ioctl(). * * Returns : -1 on failure, 0 on success. * */ -int scsicam_bios_param (Disk *disk, /* SCSI disk */ - kdev_t dev, /* Device major, minor */ - int *ip /* Heads, sectors, cylinders in that order */) { - - struct buffer_head *bh; - int ret_code; - int size = disk->capacity; - unsigned long temp_cyl; - - if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024))) - return -1; - - /* try to infer mapping from partition table */ - ret_code = scsi_partsize (bh, (unsigned long) size, (unsigned int *) ip + 2, - (unsigned int *) ip + 0, (unsigned int *) ip + 1); - brelse (bh); - - if (ret_code == -1) { - /* pick some standard mapping with at most 1024 cylinders, - and at most 62 sectors per track - this works up to - 7905 MB */ - ret_code = setsize ((unsigned long) size, (unsigned int *) ip + 2, - (unsigned int *) ip + 0, (unsigned int *) ip + 1); - } - - /* if something went wrong, then apparently we have to return - a geometry with more than 1024 cylinders */ - if (ret_code || ip[0] > 255 || ip[1] > 63) { - ip[0] = 64; - ip[1] = 32; - temp_cyl = size / (ip[0] * ip[1]); - if (temp_cyl > 65534) { - ip[0] = 255; - ip[1] = 63; - } - ip[2] = size / (ip[0] * ip[1]); - } - - return 0; +int scsicam_bios_param(Disk * disk, /* SCSI disk */ + kdev_t dev, /* Device major, minor */ + int *ip /* Heads, sectors, cylinders in that order */ ) +{ + + struct buffer_head *bh; + int ret_code; + int size = disk->capacity; + unsigned long temp_cyl; + + if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024))) + return -1; + + /* try to infer mapping from partition table */ + ret_code = scsi_partsize(bh, (unsigned long) size, (unsigned int *) ip + 2, + (unsigned int *) ip + 0, (unsigned int *) ip + 1); + brelse(bh); + + if (ret_code == -1) { + /* pick some standard mapping with at most 1024 cylinders, + and at most 62 sectors per track - this works up to + 7905 MB */ + ret_code = setsize((unsigned long) size, (unsigned int *) ip + 2, + (unsigned int *) ip + 0, (unsigned int *) ip + 1); + } + /* if something went wrong, then apparently we have to return + a geometry with more than 1024 cylinders */ + if (ret_code || ip[0] > 255 || ip[1] > 63) { + ip[0] = 64; + ip[1] = 32; + temp_cyl = size / (ip[0] * ip[1]); + if (temp_cyl > 65534) { + ip[0] = 255; + ip[1] = 63; + } + ip[2] = size / (ip[0] * ip[1]); + } + return 0; } /* @@ -83,90 +82,90 @@ * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); * * Purpose : to determine the BIOS mapping used to create the partition - * table, storing the results in *cyls, *hds, and *secs + * table, storing the results in *cyls, *hds, and *secs * * Returns : -1 on failure, 0 on success. * */ int scsi_partsize(struct buffer_head *bh, unsigned long capacity, - unsigned int *cyls, unsigned int *hds, unsigned int *secs) { - struct partition *p, *largest = NULL; - int i, largest_cyl; - int cyl, ext_cyl, end_head, end_cyl, end_sector; - unsigned int logical_end, physical_end, ext_physical_end; - - - if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { - for (largest_cyl = -1, p = (struct partition *) - (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) { - if (!p->sys_ind) - continue; + unsigned int *cyls, unsigned int *hds, unsigned int *secs) +{ + struct partition *p, *largest = NULL; + int i, largest_cyl; + int cyl, ext_cyl, end_head, end_cyl, end_sector; + unsigned int logical_end, physical_end, ext_physical_end; + + + if (*(unsigned short *) (bh->b_data + 510) == 0xAA55) { + for (largest_cyl = -1, p = (struct partition *) + (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) { + if (!p->sys_ind) + continue; #ifdef DEBUG - printk ("scsicam_bios_param : partition %d has system \n", - i); + printk("scsicam_bios_param : partition %d has system \n", + i); #endif - cyl = p->cyl + ((p->sector & 0xc0) << 2); - if (cyl > largest_cyl) { - largest_cyl = cyl; - largest = p; - } - } - } - - if (largest) { - end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2); - end_head = largest->end_head; - end_sector = largest->end_sector & 0x3f; + cyl = p->cyl + ((p->sector & 0xc0) << 2); + if (cyl > largest_cyl) { + largest_cyl = cyl; + largest = p; + } + } + } + if (largest) { + end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2); + end_head = largest->end_head; + end_sector = largest->end_sector & 0x3f; - if( end_head + 1 == 0 || end_sector == 0 ) return -1; + if (end_head + 1 == 0 || end_sector == 0) + return -1; #ifdef DEBUG - printk ("scsicam_bios_param : end at h = %d, c = %d, s = %d\n", - end_head, end_cyl, end_sector); + printk("scsicam_bios_param : end at h = %d, c = %d, s = %d\n", + end_head, end_cyl, end_sector); #endif - physical_end = end_cyl * (end_head + 1) * end_sector + - end_head * end_sector + end_sector; + physical_end = end_cyl * (end_head + 1) * end_sector + + end_head * end_sector + end_sector; - /* This is the actual _sector_ number at the end */ - logical_end = get_unaligned(&largest->start_sect) - + get_unaligned(&largest->nr_sects); - - /* This is for >1023 cylinders */ - ext_cyl= (logical_end-(end_head * end_sector + end_sector)) - /(end_head + 1) / end_sector; - ext_physical_end = ext_cyl * (end_head + 1) * end_sector + - end_head * end_sector + end_sector; + /* This is the actual _sector_ number at the end */ + logical_end = get_unaligned(&largest->start_sect) + + get_unaligned(&largest->nr_sects); + + /* This is for >1023 cylinders */ + ext_cyl = (logical_end - (end_head * end_sector + end_sector)) + / (end_head + 1) / end_sector; + ext_physical_end = ext_cyl * (end_head + 1) * end_sector + + end_head * end_sector + end_sector; #ifdef DEBUG - printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%d\n" - ,logical_end,physical_end,ext_physical_end,ext_cyl); + printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%d\n" + ,logical_end, physical_end, ext_physical_end, ext_cyl); #endif - if ((logical_end == physical_end) || - (end_cyl==1023 && ext_physical_end==logical_end)) { - *secs = end_sector; - *hds = end_head + 1; - *cyls = capacity / ((end_head + 1) * end_sector); - return 0; - } - + if ((logical_end == physical_end) || + (end_cyl == 1023 && ext_physical_end == logical_end)) { + *secs = end_sector; + *hds = end_head + 1; + *cyls = capacity / ((end_head + 1) * end_sector); + return 0; + } #ifdef DEBUG - printk ("scsicam_bios_param : logical (%u) != physical (%u)\n", - logical_end, physical_end); + printk("scsicam_bios_param : logical (%u) != physical (%u)\n", + logical_end, physical_end); #endif - } - return -1; + } + return -1; } /* * Function : static int setsize(unsigned long capacity,unsigned int *cyls, - * unsigned int *hds, unsigned int *secs); + * unsigned int *hds, unsigned int *secs); * * Purpose : to determine a near-optimal int 0x13 mapping for a - * SCSI disk in terms of lost space of size capacity, storing - * the results in *cyls, *hds, and *secs. + * SCSI disk in terms of lost space of size capacity, storing + * the results in *cyls, *hds, and *secs. * * Returns : -1 on failure, 0 on success. * @@ -194,31 +193,33 @@ * accommodated. This algorithm does not use physical geometry. */ -static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds, - unsigned int *secs) { - unsigned int rv = 0; - unsigned long heads, sectors, cylinders, temp; - - cylinders = 1024L; /* Set number of cylinders to max */ - sectors = 62L; /* Maximize sectors per track */ - - temp = cylinders * sectors; /* Compute divisor for heads */ - heads = capacity / temp; /* Compute value for number of heads */ - if (capacity % temp) { /* If no remainder, done! */ - heads++; /* Else, increment number of heads */ - temp = cylinders * heads; /* Compute divisor for sectors */ - sectors = capacity / temp; /* Compute value for sectors per - track */ - if (capacity % temp) { /* If no remainder, done! */ - sectors++; /* Else, increment number of sectors */ - temp = heads * sectors; /* Compute divisor for cylinders */ - cylinders = capacity / temp;/* Compute number of cylinders */ - } - } - if (cylinders == 0) rv=(unsigned)-1;/* Give error if 0 cylinders */ - - *cyls = (unsigned int) cylinders; /* Stuff return values */ - *secs = (unsigned int) sectors; - *hds = (unsigned int) heads; - return(rv); -} +static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, + unsigned int *secs) +{ + unsigned int rv = 0; + unsigned long heads, sectors, cylinders, temp; + + cylinders = 1024L; /* Set number of cylinders to max */ + sectors = 62L; /* Maximize sectors per track */ + + temp = cylinders * sectors; /* Compute divisor for heads */ + heads = capacity / temp; /* Compute value for number of heads */ + if (capacity % temp) { /* If no remainder, done! */ + heads++; /* Else, increment number of heads */ + temp = cylinders * heads; /* Compute divisor for sectors */ + sectors = capacity / temp; /* Compute value for sectors per + track */ + if (capacity % temp) { /* If no remainder, done! */ + sectors++; /* Else, increment number of sectors */ + temp = heads * sectors; /* Compute divisor for cylinders */ + cylinders = capacity / temp; /* Compute number of cylinders */ + } + } + if (cylinders == 0) + rv = (unsigned) -1; /* Give error if 0 cylinders */ + + *cyls = (unsigned int) cylinders; /* Stuff return values */ + *secs = (unsigned int) sectors; + *hds = (unsigned int) heads; + return (rv); +} diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c --- v2.3.16/linux/drivers/scsi/scsiiom.c Fri Dec 25 16:41:39 1998 +++ linux/drivers/scsi/scsiiom.c Sat Sep 4 10:48:46 1999 @@ -7,165 +7,156 @@ /* $Id: scsiiom.c,v 2.15 1998/12/25 17:33:27 garloff Exp $ */ UCHAR -dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) +dc390_StartSCSI(PACB pACB, PDCB pDCB, PSRB pSRB) { - USHORT wlval; - UCHAR bval, bval1; + USHORT wlval; + UCHAR bval, bval1; - pSRB->TagNumber = 31; - DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID); - DC390_write8 (Sync_Period, pDCB->SyncPeriod); - DC390_write8 (Sync_Offset, pDCB->SyncOffset); - DC390_write8 (CtrlReg1, pDCB->CtrlR1); - DC390_write8 (CtrlReg3, pDCB->CtrlR3); - DC390_write8 (CtrlReg4, pDCB->CtrlR4); - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */ - DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\ - pSRB->CmdBlock[0], pDCB->SyncMode);) - pSRB->ScsiPhase = SCSI_NOP0; - //pSRB->MsgOutBuf[0] = MSG_NOP; - //pSRB->MsgCnt = 0; - bval = pDCB->IdentifyMsg; - if( !(pDCB->SyncMode & EN_ATN_STOP) ) /* Don't always try send Extended messages on arbitration */ - { - if( (pSRB->CmdBlock[0] == INQUIRY) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE) ) - { - bval &= 0xBF; /* No DisConn */ - DC390_write8 (ScsiFifo, bval); - bval1 = SEL_W_ATN; - pSRB->SRBState = SRB_START_; - DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);) - if( pDCB->SyncMode & SYNC_ENABLE ) - { - if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ - (pSRB->CmdBlock[0] != INQUIRY) ) - { - bval1 = SEL_W_ATN_STOP; /* Try to establish SYNC nego */ - pSRB->SRBState = SRB_MSGOUT; + pSRB->TagNumber = 31; + DC390_write8(Scsi_Dest_ID, pDCB->UnitSCSIID); + DC390_write8(Sync_Period, pDCB->SyncPeriod); + DC390_write8(Sync_Offset, pDCB->SyncOffset); + DC390_write8(CtrlReg1, pDCB->CtrlR1); + DC390_write8(CtrlReg3, pDCB->CtrlR3); + DC390_write8(CtrlReg4, pDCB->CtrlR4); + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */ + DEBUG1(printk(KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n", \ + pSRB->CmdBlock[0], pDCB->SyncMode); + ) + pSRB->ScsiPhase = SCSI_NOP0; + //pSRB->MsgOutBuf[0] = MSG_NOP; + //pSRB->MsgCnt = 0; + bval = pDCB->IdentifyMsg; + if (!(pDCB->SyncMode & EN_ATN_STOP)) { /* Don't always try send Extended messages on arbitration */ + if ((pSRB->CmdBlock[0] == INQUIRY) || + (pSRB->CmdBlock[0] == REQUEST_SENSE) || + (pSRB->SRBFlag & AUTO_REQSENSE)) { + bval &= 0xBF; /* No DisConn */ + DC390_write8(ScsiFifo, bval); + bval1 = SEL_W_ATN; + pSRB->SRBState = SRB_START_; + DEBUG1(printk(KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1); + ) + if (pDCB->SyncMode & SYNC_ENABLE) { + if (!(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ + (pSRB->CmdBlock[0] != INQUIRY)) { + bval1 = SEL_W_ATN_STOP; /* Try to establish SYNC nego */ + pSRB->SRBState = SRB_MSGOUT; + } + } + } else { /* TagQ ? */ + DC390_write8(ScsiFifo, bval); + if (pDCB->SyncMode & EN_TAG_QUEUEING) { + DC390_write8(ScsiFifo, MSG_SIMPLE_QTAG); + DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, SEL_W_ATN3, pDCB->TagMask); + ) + bval = 0; + wlval = 1; + while (wlval & pDCB->TagMask) { + bval++; + wlval <<= 1; + }; + pDCB->TagMask |= wlval; + DC390_write8(ScsiFifo, bval); + pSRB->TagNumber = bval; + DEBUG1(printk(KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval); + ) + bval1 = SEL_W_ATN3; + pSRB->SRBState = SRB_START_; + } else { /* No TagQ */ + bval1 = SEL_W_ATN; + DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, bval1, pDCB->TagMask); + ) + pSRB->SRBState = SRB_START_; + } } - } - } - else /* TagQ ? */ - { - DC390_write8 (ScsiFifo, bval); - if(pDCB->SyncMode & EN_TAG_QUEUEING) - { - DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG); - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);) - bval = 0; wlval = 1; - while (wlval & pDCB->TagMask) - { bval++; wlval <<= 1; }; - pDCB->TagMask |= wlval; - DC390_write8 (ScsiFifo, bval); - pSRB->TagNumber = bval; - DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);) - bval1 = SEL_W_ATN3; - pSRB->SRBState = SRB_START_; - } - else /* No TagQ */ - { - bval1 = SEL_W_ATN; - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);) - pSRB->SRBState = SRB_START_; - } - } - - } - else /* ATN_STOP: Always try to establish Sync nego */ - { - if( (pSRB->CmdBlock[0] == INQUIRY) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE) ) - { - bval &= 0xBF; /* No DisConn */ - DC390_write8 (ScsiFifo, bval); - bval1 = SEL_W_ATN; - DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);) - pSRB->SRBState = SRB_START_; - /* ??? */ - if( pDCB->SyncMode & SYNC_ENABLE ) - { - if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ - (pSRB->CmdBlock[0] != INQUIRY) ) - { - bval1 = SEL_W_ATN_STOP; /* Try to establish Sync nego */ - pSRB->SRBState = SRB_MSGOUT; + + } else { /* ATN_STOP: Always try to establish Sync nego */ + if ((pSRB->CmdBlock[0] == INQUIRY) || + (pSRB->CmdBlock[0] == REQUEST_SENSE) || + (pSRB->SRBFlag & AUTO_REQSENSE)) { + bval &= 0xBF; /* No DisConn */ + DC390_write8(ScsiFifo, bval); + bval1 = SEL_W_ATN; + DEBUG1(printk(KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1); + ) + pSRB->SRBState = SRB_START_; + /* ??? */ + if (pDCB->SyncMode & SYNC_ENABLE) { + if (!(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ + (pSRB->CmdBlock[0] != INQUIRY)) { + bval1 = SEL_W_ATN_STOP; /* Try to establish Sync nego */ + pSRB->SRBState = SRB_MSGOUT; + } + } + } else { /* TagQ ? */ + DC390_write8(ScsiFifo, bval); + if (pDCB->SyncMode & EN_TAG_QUEUEING) { + pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG; + DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, SEL_W_ATN_STOP, pDCB->TagMask); + ) + bval = 0; + wlval = 1; + while (wlval & pDCB->TagMask) { + bval++; + wlval <<= 1; + }; + pDCB->TagMask |= wlval; + pSRB->TagNumber = bval; + DEBUG1(printk(KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval); + ) + pSRB->MsgOutBuf[1] = bval; + pSRB->MsgCnt = 2; + bval1 = SEL_W_ATN_STOP; + pSRB->SRBState = SRB_START_; /* ?? */ + } else { /* No TagQ */ + pSRB->MsgOutBuf[0] = MSG_NOP; + pSRB->MsgCnt = 1; + pSRB->SRBState = SRB_START_; + bval1 = SEL_W_ATN_STOP; + DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, bval1, pDCB->TagMask); + ) + }; } - } } - else /* TagQ ? */ - { - DC390_write8 (ScsiFifo, bval); - if(pDCB->SyncMode & EN_TAG_QUEUEING) - { - pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG; - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);) - bval = 0; wlval = 1; - while (wlval & pDCB->TagMask) - { bval++; wlval <<= 1; }; - pDCB->TagMask |= wlval; - pSRB->TagNumber = bval; - DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);) - pSRB->MsgOutBuf[1] = bval; - pSRB->MsgCnt = 2; - bval1 = SEL_W_ATN_STOP; - pSRB->SRBState = SRB_START_; /* ?? */ - } - else /* No TagQ */ - { - pSRB->MsgOutBuf[0] = MSG_NOP; - pSRB->MsgCnt = 1; - pSRB->SRBState = SRB_START_; - bval1 = SEL_W_ATN_STOP; - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);) - }; - } - } - if (bval1 != SEL_W_ATN_STOP) - { /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ - if( pSRB->SRBFlag & AUTO_REQSENSE ) - { - bval = 0; - DC390_write8 (ScsiFifo, REQUEST_SENSE); - DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5); - DC390_write8 (ScsiFifo, bval); - DC390_write8 (ScsiFifo, bval); - DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); - DC390_write8 (ScsiFifo, bval); - DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n");) - } - else /* write cmnd to bus */ - { - PUCHAR ptr; UCHAR i; - ptr = (PUCHAR) pSRB->CmdBlock; - for (i=0; iScsiCmdLen; i++) - DC390_write8 (ScsiFifo, *(ptr++)); - }; - } - - /* Check if we can't win arbitration */ - if (DC390_read8 (Scsi_Status) & INTERRUPT) - { - pSRB->SRBState = SRB_READY; - pDCB->TagMask &= ~( 1 << pSRB->TagNumber ); - DEBUG0(printk (KERN_WARNING "DC390: Interrupt during StartSCSI!\n");) - return 1; - } - else - { - pSRB->ScsiPhase = SCSI_NOP1; - DEBUG0(if (pACB->pActiveDCB) \ - printk (KERN_WARNING "DC390: ActiveDCB != 0\n");) - DEBUG0(if (pDCB->pActiveSRB) \ - printk (KERN_WARNING "DC390: ActiveSRB != 0\n");) - pACB->pActiveDCB = pDCB; - pDCB->pActiveSRB = pSRB; - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - DC390_write8 (ScsiCmd, bval1); - return 0; - } + if (bval1 != SEL_W_ATN_STOP) { /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ + if (pSRB->SRBFlag & AUTO_REQSENSE) { + bval = 0; + DC390_write8(ScsiFifo, REQUEST_SENSE); + DC390_write8(ScsiFifo, pDCB->IdentifyMsg << 5); + DC390_write8(ScsiFifo, bval); + DC390_write8(ScsiFifo, bval); + DC390_write8(ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); + DC390_write8(ScsiFifo, bval); + DEBUG1(printk(KERN_DEBUG "DC390: AutoReqSense !\n"); + ) + } else { /* write cmnd to bus */ + PUCHAR ptr; + UCHAR i; + ptr = (PUCHAR) pSRB->CmdBlock; + for (i = 0; i < pSRB->ScsiCmdLen; i++) + DC390_write8(ScsiFifo, *(ptr++)); + }; + } + /* Check if we can't win arbitration */ + if (DC390_read8(Scsi_Status) & INTERRUPT) { + pSRB->SRBState = SRB_READY; + pDCB->TagMask &= ~(1 << pSRB->TagNumber); + DEBUG0(printk(KERN_WARNING "DC390: Interrupt during StartSCSI!\n"); + ) + return 1; + } else { + pSRB->ScsiPhase = SCSI_NOP1; + DEBUG0(if (pACB->pActiveDCB) \ + printk(KERN_WARNING "DC390: ActiveDCB != 0\n");) + DEBUG0(if (pDCB->pActiveSRB) \ + printk(KERN_WARNING "DC390: ActiveSRB != 0\n");) + pACB->pActiveDCB = pDCB; + pDCB->pActiveSRB = pSRB; + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + DC390_write8(ScsiCmd, bval1); + return 0; + } } //#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/ @@ -173,417 +164,400 @@ #if DMA_INT /* This is similar to AM53C974.c ... */ -static UCHAR -dc390_dma_intr (PACB pACB) +static UCHAR + dc390_dma_intr(PACB pACB) { - PSRB pSRB; - UCHAR dstate; - DEBUG0(USHORT pstate;PDEVDECL1;) - - DEBUG0(PDEVSET1;) - DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);) - DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\ - { printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \ - PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};) - - dstate = DC390_read8 (DMA_Status); - - if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate; - else pSRB = pACB->pActiveDCB->pActiveSRB; - - if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT)) - { - printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate); - return dstate; - }; - if (dstate & DMA_XFER_DONE) - { - ULONG residual, xferCnt; int ctr = 5000000; - if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION)) - { - do - { - DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");) - dstate = DC390_read8 (DMA_Status); - residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 | - DC390_read8 (CtcReg_High) << 16; - residual += DC390_read8 (Current_Fifo) & 0x1f; - } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr); - if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); - /* residual = ... */ - } + PSRB pSRB; + UCHAR dstate; + DEBUG0(USHORT pstate; + PDEVDECL1; + ) + DEBUG0(PDEVSET1; + ) + DEBUG0(PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstate); + ) + DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY)) \ + { + printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \ + PCI_WRITE_CONFIG_WORD(PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY)); + }; + ) + dstate = DC390_read8(DMA_Status); + + if (!pACB->pActiveDCB || !pACB->pActiveDCB->pActiveSRB) + return dstate; else - residual = 0; - - /* ??? */ - - xferCnt = pSRB->SGToBeXferLen - residual; - pSRB->SGBusAddr += xferCnt; - pSRB->TotalXferredLen += xferCnt; - pSRB->SGToBeXferLen = residual; -# ifdef DC390_DEBUG0 - printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", - (unsigned int)residual, (unsigned int)xferCnt); -# endif - - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - } - dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; - return dstate; + pSRB = pACB->pActiveDCB->pActiveSRB; + + if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT)) { + printk(KERN_ERR "DC390: DMA error (%02x)!\n", dstate); + return dstate; + }; + if (dstate & DMA_XFER_DONE) { + ULONG residual, xferCnt; + int ctr = 5000000; + if (!(DC390_read8(DMA_Cmd) & READ_DIRECTION)) { + do { + DEBUG1(printk(KERN_DEBUG "DC390: read residual bytes ... \n"); + ) + dstate = DC390_read8(DMA_Status); + residual = DC390_read8(CtcReg_Low) | DC390_read8(CtcReg_Mid) << 8 | + DC390_read8(CtcReg_High) << 16; + residual += DC390_read8(Current_Fifo) & 0x1f; + } while (residual && !(dstate & SCSI_INTERRUPT) && --ctr); + if (!ctr) + printk(KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32(DMA_Wk_ByteCntr)); + /* residual = ... */ + } else + residual = 0; + + /* ??? */ + + xferCnt = pSRB->SGToBeXferLen - residual; + pSRB->SGBusAddr += xferCnt; + pSRB->TotalXferredLen += xferCnt; + pSRB->SGToBeXferLen = residual; +#ifdef DC390_DEBUG0 + printk(KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", + (unsigned int) residual, (unsigned int) xferCnt); +#endif + + DC390_write8(DMA_Cmd, DMA_IDLE_CMD); + } + dc390_laststatus &= ~0xff000000; + dc390_laststatus |= dstate << 24; + return dstate; }; #endif void __inline__ -DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) + DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs) { - PACB pACB; - PDCB pDCB; - PSRB pSRB; - UCHAR sstatus=0; - UCHAR phase, i; - void (*stateV)( PACB, PSRB, PUCHAR ); - UCHAR istate, istatus; + PACB pACB; + PDCB pDCB; + PSRB pSRB; + UCHAR sstatus = 0; + UCHAR phase, i; + void (*stateV) (PACB, PSRB, PUCHAR); + UCHAR istate, istatus; #if DMA_INT - UCHAR dstatus; + UCHAR dstatus; #endif - DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS - - pACB = dc390_pACB_start; + DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS - if (pACB == 0) - { - printk(KERN_WARNING "DC390: Interrupt on uninitialized adapter!\n"); - return; - } - DC390_LOCK_DRV; + pACB = dc390_pACB_start; - for( i=0; i < dc390_adapterCnt; i++ ) - { - if( pACB->IRQLevel == (UCHAR) irq ) - { - sstatus = DC390_read8 (Scsi_Status); - if( sstatus & INTERRUPT ) - break; - else - pACB = pACB->pNextACB; - } - else - { - pACB = pACB->pNextACB; + if (pACB == 0) { + printk(KERN_WARNING "DC390: Interrupt on uninitialized adapter!\n"); + return; } - } + DC390_LOCK_DRV; - DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);) + for (i = 0; i < dc390_adapterCnt; i++) { + if (pACB->IRQLevel == (UCHAR) irq) { + sstatus = DC390_read8(Scsi_Status); + if (sstatus & INTERRUPT) + break; + else + pACB = pACB->pNextACB; + } else { + pACB = pACB->pNextACB; + } + } - if( !pACB ) { DC390_UNLOCK_DRV; return; }; + DEBUG1(printk(KERN_DEBUG "sstatus=%02x,", sstatus); + ) + if (!pACB) { + DC390_UNLOCK_DRV; + return; + }; #if DMA_INT - DC390_LOCK_IO; - DC390_LOCK_ACB; - dstatus = dc390_dma_intr (pACB); - DC390_UNLOCK_ACB; - DC390_UNLOCK_IO; - - DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus);) - if (! (dstatus & SCSI_INTERRUPT)) - { - DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n");) - DC390_UNLOCK_DRV; - return; - }; + DC390_LOCK_IO; + DC390_LOCK_ACB; + dstatus = dc390_dma_intr(pACB); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + + DEBUG1(printk(KERN_DEBUG "dstatus=%02x,", dstatus); + ) + if (!(dstatus & SCSI_INTERRUPT)) { + DEBUG0(printk(KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n"); + ) + DC390_UNLOCK_DRV; + return; + }; #else - //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); - //dstatus = DC390_read8 (DMA_Status); - //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); + //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); + //dstatus = DC390_read8 (DMA_Status); + //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); #endif - DC390_LOCK_IO; - DC390_LOCK_ACB; - DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */ - - istate = DC390_read8 (Intern_State); - istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */ - - DEBUG1(printk (KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);) - dc390_laststatus &= ~0x00ffffff; - dc390_laststatus |= /* dstatus<<24 | */ sstatus<<16 | istate<<8 | istatus; - - if (sstatus & ILLEGAL_OP_ERR) - { - printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus); - dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB); - }; - - if(istatus & DISCONNECTED) - { - dc390_Disconnect( pACB ); - goto unlock; - } - - if(istatus & RESELECTED) - { - dc390_Reselect( pACB ); - goto unlock; - } - - if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) ) - { - pDCB = pACB->pActiveDCB; - if (!pDCB) - { - printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n"); - goto unlock; + DC390_LOCK_IO; + DC390_LOCK_ACB; + DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */ + + istate = DC390_read8(Intern_State); + istatus = DC390_read8(INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */ + + DEBUG1(printk(KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,", istatus); + ) + dc390_laststatus &= ~0x00ffffff; + dc390_laststatus |= /* dstatus<<24 | */ sstatus << 16 | istate << 8 | istatus; + + if (sstatus & ILLEGAL_OP_ERR) { + printk("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus); + dc390_dumpinfo(pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB); }; - pSRB = pDCB->pActiveSRB; - if( pDCB->DCBFlag & ABORT_DEV_ ) - dc390_EnableMsgOut_Abort (pACB, pSRB); - - phase = pSRB->ScsiPhase; - DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);) - stateV = (void *) dc390_phase0[phase]; - ( *stateV )( pACB, pSRB, &sstatus ); - - pSRB->ScsiPhase = sstatus & 7; - phase = (UCHAR) sstatus & 7; - DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);) - stateV = (void *) dc390_phase1[phase]; - ( *stateV )( pACB, pSRB, &sstatus ); - goto unlock; - } - - if(istatus & INVALID_CMD) - { - dc390_InvalidCmd( pACB ); - goto unlock; - } - - if(istatus & SCSI_RESET) - { - dc390_ScsiRstDetect( pACB ); - goto unlock; - } - - unlock: - DC390_LOCK_DRV_NI; - DC390_UNLOCK_ACB; - DC390_UNLOCK_IO; - DC390_UNLOCK_DRV; /* Restore initial flags */ -} - -void -do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) -{ - DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq);) - /* Locking is done in DC390_Interrupt */ - DC390_Interrupt(irq, dev_id, regs); - DEBUG1(printk (".. IRQ returned\n");) -} - -void -dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - UCHAR sstatus; - PSGL psgl; - ULONG ResidCnt, xferCnt; - UCHAR dstate = 0; - - sstatus = *psstatus; - - if( !(pSRB->SRBState & SRB_XFERPAD) ) - { - if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) ) - pSRB->SRBStatus |= PARITY_ERROR; - if( sstatus & COUNT_2_ZERO ) - { - int ctr = 5000000; /* only try for about a tenth of a second */ - while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ); - if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); - dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; - pSRB->TotalXferredLen += pSRB->SGToBeXferLen; - pSRB->SGIndex++; - if( pSRB->SGIndex < pSRB->SGcount ) - { - pSRB->pSegmentList++; - psgl = pSRB->pSegmentList; - - pSRB->SGBusAddr = virt_to_bus( psgl->address ); - pSRB->SGToBeXferLen = (ULONG) psgl->length; - } - else - pSRB->SGToBeXferLen = 0; + if (istatus & DISCONNECTED) { + dc390_Disconnect(pACB); + goto unlock; } - else - { - ResidCnt = (ULONG) DC390_read8 (Current_Fifo) & 0x1f; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_High) << 16; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid) << 8; - ResidCnt += (ULONG) DC390_read8 (CtcReg_Low); + if (istatus & RESELECTED) { + dc390_Reselect(pACB); + goto unlock; + } + if (istatus & (SUCCESSFUL_OP | SERVICE_REQUEST)) { + pDCB = pACB->pActiveDCB; + if (!pDCB) { + printk(KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n"); + goto unlock; + }; + pSRB = pDCB->pActiveSRB; + if (pDCB->DCBFlag & ABORT_DEV_) + dc390_EnableMsgOut_Abort(pACB, pSRB); + + phase = pSRB->ScsiPhase; + DEBUG1(printk(KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus); + ) + stateV = (void *) dc390_phase0[phase]; + (*stateV) (pACB, pSRB, &sstatus); + + pSRB->ScsiPhase = sstatus & 7; + phase = (UCHAR) sstatus & 7; + DEBUG1(printk(KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus); + ) + stateV = (void *) dc390_phase1[phase]; + (*stateV) (pACB, pSRB, &sstatus); + goto unlock; + } + if (istatus & INVALID_CMD) { + dc390_InvalidCmd(pACB); + goto unlock; + } + if (istatus & SCSI_RESET) { + dc390_ScsiRstDetect(pACB); + goto unlock; + } + unlock: + DC390_LOCK_DRV_NI; + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + DC390_UNLOCK_DRV; /* Restore initial flags */ +} + +void do_DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + DEBUG1(printk(KERN_INFO "DC390: Irq (%i) caught: ", irq); + ) + /* Locking is done in DC390_Interrupt */ + DC390_Interrupt(irq, dev_id, regs); + DEBUG1(printk(".. IRQ returned\n"); + ) +} + +void dc390_DataOut_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR sstatus; + PSGL psgl; + ULONG ResidCnt, xferCnt; + UCHAR dstate = 0; + + sstatus = *psstatus; + + if (!(pSRB->SRBState & SRB_XFERPAD)) { + if (sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) + pSRB->SRBStatus |= PARITY_ERROR; + + if (sstatus & COUNT_2_ZERO) { + int ctr = 5000000; /* only try for about a tenth of a second */ + while (--ctr && !((dstate = DC390_read8(DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen); + if (!ctr) + printk(KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32(DMA_Wk_ByteCntr)); + dc390_laststatus &= ~0xff000000; + dc390_laststatus |= dstate << 24; + pSRB->TotalXferredLen += pSRB->SGToBeXferLen; + pSRB->SGIndex++; + if (pSRB->SGIndex < pSRB->SGcount) { + pSRB->pSegmentList++; + psgl = pSRB->pSegmentList; + + pSRB->SGBusAddr = virt_to_bus(psgl->address); + pSRB->SGToBeXferLen = (ULONG) psgl->length; + } else + pSRB->SGToBeXferLen = 0; + } else { + ResidCnt = (ULONG) DC390_read8(Current_Fifo) & 0x1f; + ResidCnt |= (ULONG) DC390_read8(CtcReg_High) << 16; + ResidCnt |= (ULONG) DC390_read8(CtcReg_Mid) << 8; + ResidCnt += (ULONG) DC390_read8(CtcReg_Low); + + xferCnt = pSRB->SGToBeXferLen - ResidCnt; + pSRB->SGBusAddr += xferCnt; + pSRB->TotalXferredLen += xferCnt; + pSRB->SGToBeXferLen = ResidCnt; + } + } + DC390_write8(DMA_Cmd, WRITE_DIRECTION + DMA_IDLE_CMD); /* | DMA_INT */ +} - xferCnt = pSRB->SGToBeXferLen - ResidCnt; - pSRB->SGBusAddr += xferCnt; - pSRB->TotalXferredLen += xferCnt; - pSRB->SGToBeXferLen = ResidCnt; +void dc390_DataIn_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR sstatus, residual, bval; + PSGL psgl; + ULONG ResidCnt, xferCnt, i; + PUCHAR ptr; + + sstatus = *psstatus; + + if (!(pSRB->SRBState & SRB_XFERPAD)) { + if (sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) + pSRB->SRBStatus |= PARITY_ERROR; + + if (sstatus & COUNT_2_ZERO) { + int ctr = 5000000; /* only try for about a tenth of a second */ + int dstate = 0; + while (--ctr && !((dstate = DC390_read8(DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen); + if (!ctr) + printk(KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32(DMA_Wk_ByteCntr)); + if (!ctr) + printk(KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate); + dc390_laststatus &= ~0xff000000; + dc390_laststatus |= dstate << 24; + DEBUG1(ResidCnt = ((ULONG) DC390_read8(CtcReg_High) << 16) \ + +((ULONG) DC390_read8(CtcReg_Mid) << 8) \ + +((ULONG) DC390_read8(CtcReg_Low)); + ) + DEBUG1(printk(KERN_DEBUG "Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen); + ) + DC390_write8(DMA_Cmd, READ_DIRECTION + DMA_IDLE_CMD); /* | DMA_INT */ + + pSRB->TotalXferredLen += pSRB->SGToBeXferLen; + pSRB->SGIndex++; + if (pSRB->SGIndex < pSRB->SGcount) { + pSRB->pSegmentList++; + psgl = pSRB->pSegmentList; + + pSRB->SGBusAddr = virt_to_bus(psgl->address); + pSRB->SGToBeXferLen = (ULONG) psgl->length; + } else + pSRB->SGToBeXferLen = 0; + } else { /* phase changed */ + residual = 0; + bval = DC390_read8(Current_Fifo); + while (bval & 0x1f) { + DEBUG1(printk(KERN_DEBUG "Check for residuals,"); + ) + if ((bval & 0x1f) == 1) { + for (i = 0; i < 0x100; i++) { + bval = DC390_read8(Current_Fifo); + if (!(bval & 0x1f)) + goto din_1; + else if (i == 0x0ff) { + residual = 1; /* ;1 residual byte */ + goto din_1; + } + } + } else + bval = DC390_read8(Current_Fifo); + } + din_1: + DC390_write8(DMA_Cmd, READ_DIRECTION + DMA_BLAST_CMD); + for (i = 0xa000; i; i--) { + bval = DC390_read8(DMA_Status); + if (bval & BLAST_COMPLETE) + break; + } + /* It seems a DMA Blast abort isn't that bad ... */ + if (!i) + printk(KERN_ERR "DC390: DMA Blast aborted unfinished!\n"); + //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + dc390_laststatus &= ~0xff000000; + dc390_laststatus |= bval << 24; + + DEBUG1(printk(KERN_DEBUG "Blast: Read %li times DMA_Status %02x", 0xa000 - i, bval); + ) + ResidCnt = (ULONG) DC390_read8(CtcReg_High); + ResidCnt <<= 8; + ResidCnt |= (ULONG) DC390_read8(CtcReg_Mid); + ResidCnt <<= 8; + ResidCnt |= (ULONG) DC390_read8(CtcReg_Low); + + xferCnt = pSRB->SGToBeXferLen - ResidCnt; + pSRB->SGBusAddr += xferCnt; + pSRB->TotalXferredLen += xferCnt; + pSRB->SGToBeXferLen = ResidCnt; + + if (residual) { + bval = DC390_read8(ScsiFifo); /* get one residual byte */ + ptr = (PUCHAR) bus_to_virt(pSRB->SGBusAddr); + *ptr = bval; + pSRB->SGBusAddr++; + xferCnt++; + pSRB->TotalXferredLen++; + pSRB->SGToBeXferLen--; + } + DEBUG1(printk(KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt, \ + pSRB->TotalXferredLen, pSRB->SGToBeXferLen); + ) + } } - } - DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ } -void -dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +static void dc390_Command_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR sstatus, residual, bval; - PSGL psgl; - ULONG ResidCnt, xferCnt, i; - PUCHAR ptr; +} - sstatus = *psstatus; +static void dc390_Status_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ - if( !(pSRB->SRBState & SRB_XFERPAD) ) - { - if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) - pSRB->SRBStatus |= PARITY_ERROR; + pSRB->TargetStatus = DC390_read8(ScsiFifo); + //udelay (1); + pSRB->EndMessage = DC390_read8(ScsiFifo); /* get message */ - if( sstatus & COUNT_2_ZERO ) - { - int ctr = 5000000; /* only try for about a tenth of a second */ - int dstate = 0; - while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ); - if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); - if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate); - dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; - DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16) \ - + ((ULONG) DC390_read8 (CtcReg_Mid) << 8) \ - + ((ULONG) DC390_read8 (CtcReg_Low));) - DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);) - - DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ - - pSRB->TotalXferredLen += pSRB->SGToBeXferLen; - pSRB->SGIndex++; - if( pSRB->SGIndex < pSRB->SGcount ) - { - pSRB->pSegmentList++; - psgl = pSRB->pSegmentList; - - pSRB->SGBusAddr = virt_to_bus( psgl->address ); - pSRB->SGToBeXferLen = (ULONG) psgl->length; - } - else - pSRB->SGToBeXferLen = 0; - } - else /* phase changed */ - { - residual = 0; - bval = DC390_read8 (Current_Fifo); - while( bval & 0x1f ) - { - DEBUG1(printk (KERN_DEBUG "Check for residuals,");) - if( (bval & 0x1f) == 1 ) - { - for(i=0; i < 0x100; i++) - { - bval = DC390_read8 (Current_Fifo); - if( !(bval & 0x1f) ) - goto din_1; - else if( i == 0x0ff ) - { - residual = 1; /* ;1 residual byte */ - goto din_1; - } - } - } - else - bval = DC390_read8 (Current_Fifo); - } -din_1: - DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD); - for (i = 0xa000; i; i--) - { - bval = DC390_read8 (DMA_Status); - if (bval & BLAST_COMPLETE) - break; - } - /* It seems a DMA Blast abort isn't that bad ... */ - if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n"); - //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ - dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24; - - DEBUG1(printk (KERN_DEBUG "Blast: Read %li times DMA_Status %02x", 0xa000-i, bval);) - ResidCnt = (ULONG) DC390_read8 (CtcReg_High); - ResidCnt <<= 8; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid); - ResidCnt <<= 8; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_Low); - - xferCnt = pSRB->SGToBeXferLen - ResidCnt; - pSRB->SGBusAddr += xferCnt; - pSRB->TotalXferredLen += xferCnt; - pSRB->SGToBeXferLen = ResidCnt; - - if( residual ) - { - bval = DC390_read8 (ScsiFifo); /* get one residual byte */ - ptr = (PUCHAR) bus_to_virt( pSRB->SGBusAddr ); - *ptr = bval; - pSRB->SGBusAddr++; xferCnt++; - pSRB->TotalXferredLen++; - pSRB->SGToBeXferLen--; - } - DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\ - pSRB->TotalXferredLen, pSRB->SGToBeXferLen);) - - } - } -} - -static void -dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ -} - -static void -dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - - pSRB->TargetStatus = DC390_read8 (ScsiFifo); - //udelay (1); - pSRB->EndMessage = DC390_read8 (ScsiFifo); /* get message */ - - *psstatus = SCSI_NOP0; - pSRB->SRBState = SRB_COMPLETED; - DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); + *psstatus = SCSI_NOP0; + pSRB->SRBState = SRB_COMPLETED; + DC390_write8(ScsiCmd, MSG_ACCEPTED_CMD); } -static void -dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +static void dc390_MsgOut_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) { - if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) ) - *psstatus = SCSI_NOP0; - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + if (pSRB->SRBState & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) + *psstatus = SCSI_NOP0; + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } static void __inline__ -dc390_reprog (PACB pACB, PDCB pDCB) + dc390_reprog(PACB pACB, PDCB pDCB) { - DC390_write8 (Sync_Period, pDCB->SyncPeriod); - DC390_write8 (Sync_Offset, pDCB->SyncOffset); - DC390_write8 (CtrlReg3, pDCB->CtrlR3); - DC390_write8 (CtrlReg4, pDCB->CtrlR4); - dc390_SetXferRate (pACB, pDCB); + DC390_write8(Sync_Period, pDCB->SyncPeriod); + DC390_write8(Sync_Offset, pDCB->SyncOffset); + DC390_write8(CtrlReg3, pDCB->CtrlR3); + DC390_write8(CtrlReg4, pDCB->CtrlR4); + dc390_SetXferRate(pACB, pDCB); }; #ifdef DC390_DEBUG0 -static void -dc390_printMsg (UCHAR *MsgBuf, UCHAR len) +static void dc390_printMsg(UCHAR * MsgBuf, UCHAR len) { - int i; - printk (" %02x", MsgBuf[0]); - for (i = 1; i < len; i++) - printk (" %02x", MsgBuf[i]); - printk ("\n"); + int i; + printk(" %02x", MsgBuf[0]); + for (i = 1; i < len; i++) + printk(" %02x", MsgBuf[i]); + printk("\n"); }; #endif @@ -591,151 +565,147 @@ /* reject_msg */ static void __inline__ -dc390_MsgIn_reject (PACB pACB, PSRB pSRB) + dc390_MsgIn_reject(PACB pACB, PSRB pSRB) { - pSRB->MsgOutBuf[0] = MSG_REJECT_; - pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; - DEBUG0 (printk (KERN_INFO "DC390: Reject message\n");) + pSRB->MsgOutBuf[0] = MSG_REJECT_; + pSRB->MsgCnt = 1; + DC390_ENABLE_MSGOUT; + DEBUG0(printk(KERN_INFO "DC390: Reject message\n"); + ) } /* abort command */ static void __inline__ -dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB ) + dc390_EnableMsgOut_Abort(PACB pACB, PSRB pSRB) { - pSRB->MsgOutBuf[0] = MSG_ABORT; - pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; - pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; + pSRB->MsgOutBuf[0] = MSG_ABORT; + pSRB->MsgCnt = 1; + DC390_ENABLE_MSGOUT; + pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; } static PSRB -dc390_MsgIn_QTag (PACB pACB, PDCB pDCB, UCHAR tag) + dc390_MsgIn_QTag(PACB pACB, PDCB pDCB, UCHAR tag) { - PSRB lastSRB = pDCB->pGoingLast; - PSRB pSRB = pDCB->pGoingSRB; + PSRB lastSRB = pDCB->pGoingLast; + PSRB pSRB = pDCB->pGoingSRB; - if (pSRB) - { - for( ;pSRB ; ) - { - if (pSRB->TagNumber == tag) break; - if (pSRB == lastSRB) goto mingx0; - pSRB = pSRB->pNextSRB; - } - - if( pDCB->DCBFlag & ABORT_DEV_ ) - { - pSRB->SRBState = SRB_ABORT_SENT; - dc390_EnableMsgOut_Abort( pACB, pSRB ); - } + if (pSRB) { + for (; pSRB;) { + if (pSRB->TagNumber == tag) + break; + if (pSRB == lastSRB) + goto mingx0; + pSRB = pSRB->pNextSRB; + } - if( !(pSRB->SRBState & SRB_DISCONNECT) ) - goto mingx0; + if (pDCB->DCBFlag & ABORT_DEV_) { + pSRB->SRBState = SRB_ABORT_SENT; + dc390_EnableMsgOut_Abort(pACB, pSRB); + } + if (!(pSRB->SRBState & SRB_DISCONNECT)) + goto mingx0; - pDCB->pActiveSRB = pSRB; - pSRB->SRBState = SRB_DATA_XFER; - } - else - { - mingx0: - pSRB = pACB->pTmpSRB; - pSRB->SRBState = SRB_UNEXPECT_RESEL; - pDCB->pActiveSRB = pSRB; - pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; - pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; - } - return pSRB; + pDCB->pActiveSRB = pSRB; + pSRB->SRBState = SRB_DATA_XFER; + } else { + mingx0: + pSRB = pACB->pTmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + pDCB->pActiveSRB = pSRB; + pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; + pSRB->MsgCnt = 1; + DC390_ENABLE_MSGOUT; + } + return pSRB; } /* set async transfer mode */ -static void -dc390_MsgIn_set_async (PACB pACB, PSRB pSRB) +static void dc390_MsgIn_set_async(PACB pACB, PSRB pSRB) { - PDCB pDCB = pSRB->pSRBDCB; - if (!(pSRB->SRBState & DO_SYNC_NEGO)) - printk ("DC390: Target %i initiates Non-Sync?\n", pDCB->UnitSCSIID); - pSRB->SRBState &= ~DO_SYNC_NEGO; - pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE); - pDCB->SyncPeriod = 0; - pDCB->SyncOffset = 0; - //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ - pDCB->CtrlR3 = FAST_CLK; /* fast clock / normal scsi */ - pDCB->CtrlR4 &= 0x3f; - pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ - dc390_reprog (pACB, pDCB); + PDCB pDCB = pSRB->pSRBDCB; + if (!(pSRB->SRBState & DO_SYNC_NEGO)) + printk("DC390: Target %i initiates Non-Sync?\n", pDCB->UnitSCSIID); + pSRB->SRBState &= ~DO_SYNC_NEGO; + pDCB->SyncMode &= ~(SYNC_ENABLE + SYNC_NEGO_DONE); + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ + pDCB->CtrlR3 = FAST_CLK; /* fast clock / normal scsi */ + pDCB->CtrlR4 &= 0x3f; + pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ + dc390_reprog(pACB, pDCB); } /* set sync transfer mode */ -static void -dc390_MsgIn_set_sync (PACB pACB, PSRB pSRB) +static void dc390_MsgIn_set_sync(PACB pACB, PSRB pSRB) { - UCHAR bval; - USHORT wval, wval1; - PDCB pDCB = pSRB->pSRBDCB; - UCHAR oldsyncperiod = pDCB->SyncPeriod; - UCHAR oldsyncoffset = pDCB->SyncOffset; - - if (!(pSRB->SRBState & DO_SYNC_NEGO)) - { - printk ("DC390: Target %i initiates Sync: %ins %i ... answer ...\n", - pDCB->UnitSCSIID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); - - /* reject */ - //dc390_MsgIn_reject (pACB, pSRB); - //return dc390_MsgIn_set_async (pACB, pSRB); - - /* Reply with corrected SDTR Message */ - if (pSRB->MsgInBuf[4] > 15) - { - printk ("DC390: Lower Sync Offset to 15\n"); - pSRB->MsgInBuf[4] = 15; - } - if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod) - { - printk ("DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2); - pSRB->MsgInBuf[3] = pDCB->NegoPeriod; + UCHAR bval; + USHORT wval, wval1; + PDCB pDCB = pSRB->pSRBDCB; + UCHAR oldsyncperiod = pDCB->SyncPeriod; + UCHAR oldsyncoffset = pDCB->SyncOffset; + + if (!(pSRB->SRBState & DO_SYNC_NEGO)) { + printk("DC390: Target %i initiates Sync: %ins %i ... answer ...\n", + pDCB->UnitSCSIID, pSRB->MsgInBuf[3] << 2, pSRB->MsgInBuf[4]); + + /* reject */ + //dc390_MsgIn_reject (pACB, pSRB); + //return dc390_MsgIn_set_async (pACB, pSRB); + + /* Reply with corrected SDTR Message */ + if (pSRB->MsgInBuf[4] > 15) { + printk("DC390: Lower Sync Offset to 15\n"); + pSRB->MsgInBuf[4] = 15; + } + if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod) { + printk("DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2); + pSRB->MsgInBuf[3] = pDCB->NegoPeriod; + }; + memcpy(pSRB->MsgOutBuf, pSRB->MsgInBuf, 5); + pSRB->MsgCnt = 5; + DC390_ENABLE_MSGOUT; }; - memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5); - pSRB->MsgCnt = 5; - DC390_ENABLE_MSGOUT; - }; - - pSRB->SRBState &= ~DO_SYNC_NEGO; - pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE; - pDCB->SyncOffset &= 0x0f0; - pDCB->SyncOffset |= pSRB->MsgInBuf[4]; - pDCB->NegoPeriod = pSRB->MsgInBuf[3]; - - wval = (USHORT) pSRB->MsgInBuf[3]; - wval = wval << 2; wval -= 3; wval1 = wval / 25; /* compute speed */ - if( (wval1 * 25) != wval) wval1++; - bval = FAST_CLK+FAST_SCSI; /* fast clock / fast scsi */ - - pDCB->CtrlR4 &= 0x3f; /* Glitch eater: 12ns less than normal */ - if (pACB->glitch_cfg != NS_TO_GLITCH(0)) - pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1)); - else - pDCB->CtrlR4 |= NS_TO_GLITCH(0); - if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */ - - if (wval1 >= 8) - { - wval1--; /* Timing computation differs by 1 from FAST_SCSI */ - bval = FAST_CLK; /* fast clock / normal scsi */ - pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ - } - - pDCB->CtrlR3 = bval; - pDCB->SyncPeriod = (UCHAR)wval1; - - if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->UnitSCSILUN == 0) - { - if (! (bval & FAST_SCSI)) wval1++; - printk ("DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->UnitSCSIID, - 40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f); - } - - dc390_reprog (pACB, pDCB); + + pSRB->SRBState &= ~DO_SYNC_NEGO; + pDCB->SyncMode |= SYNC_ENABLE + SYNC_NEGO_DONE; + pDCB->SyncOffset &= 0x0f0; + pDCB->SyncOffset |= pSRB->MsgInBuf[4]; + pDCB->NegoPeriod = pSRB->MsgInBuf[3]; + + wval = (USHORT) pSRB->MsgInBuf[3]; + wval = wval << 2; + wval -= 3; + wval1 = wval / 25; /* compute speed */ + if ((wval1 * 25) != wval) + wval1++; + bval = FAST_CLK + FAST_SCSI; /* fast clock / fast scsi */ + + pDCB->CtrlR4 &= 0x3f; /* Glitch eater: 12ns less than normal */ + if (pACB->glitch_cfg != NS_TO_GLITCH(0)) + pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1)); + else + pDCB->CtrlR4 |= NS_TO_GLITCH(0); + if (wval1 < 4) + pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */ + + if (wval1 >= 8) { + wval1--; /* Timing computation differs by 1 from FAST_SCSI */ + bval = FAST_CLK; /* fast clock / normal scsi */ + pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ + } + pDCB->CtrlR3 = bval; + pDCB->SyncPeriod = (UCHAR) wval1; + + if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->UnitSCSILUN == 0) { + if (!(bval & FAST_SCSI)) + wval1++; + printk("DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->UnitSCSIID, + 40 / wval1, ((40 % wval1) * 10 + wval1 / 2) / wval1, pDCB->SyncOffset & 0x0f); + } + dc390_reprog(pACB, pDCB); }; @@ -749,969 +719,890 @@ /* Check if the message is complete */ static UCHAR __inline__ -dc390_MsgIn_complete (UCHAR *msgbuf, ULONG len) -{ - if (*msgbuf == MSG_EXTENDED) - { - if (len < 2) return 0; - if (len < msgbuf[1] + 2) return 0; - } - else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages - if (len < 2) return 0; - return 1; + dc390_MsgIn_complete(UCHAR * msgbuf, ULONG len) +{ + if (*msgbuf == MSG_EXTENDED) { + if (len < 2) + return 0; + if (len < msgbuf[1] + 2) + return 0; + } else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages + + if (len < 2) + return 0; + return 1; } /* read and eval received messages */ -void -dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void dc390_MsgIn_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) { - PDCB pDCB = pACB->pActiveDCB; + PDCB pDCB = pACB->pActiveDCB; - /* Read the msg */ + /* Read the msg */ - pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8 (ScsiFifo); - //pSRB->SRBState = 0; - - /* Msg complete ? */ - if (dc390_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen)) - { - DEBUG0 (printk (KERN_INFO "DC390: MsgIn:"); dc390_printMsg (pSRB->MsgInBuf, pACB->MsgLen);) - /* Now eval the msg */ - switch (pSRB->MsgInBuf[0]) - { - case MSG_DISCONNECT: - pSRB->SRBState = SRB_DISCONNECT; break; - - case MSG_SIMPLE_QTAG: - case MSG_HEAD_QTAG: - case MSG_ORDER_QTAG: - pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]); - break; - - case MSG_REJECT_: - DC390_write8 (ScsiCmd, RESET_ATN_CMD); - pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ - if( pSRB->SRBState & DO_SYNC_NEGO) - dc390_MsgIn_set_async (pACB, pSRB); - break; - - case MSG_EXTENDED: - /* reject every extended msg but SDTR */ - if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR) - dc390_MsgIn_reject (pACB, pSRB); - else - { - if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0) - dc390_MsgIn_set_async (pACB, pSRB); - else - dc390_MsgIn_set_sync (pACB, pSRB); - }; - - // nothing has to be done - case MSG_COMPLETE: break; - - // SAVE POINTER my be ignored as we have the PSRB associated with the - // scsi command. Thanks, Gerard, for pointing it out. - case MSG_SAVE_PTR: break; - // The device might want to restart transfer with a RESTORE - case MSG_RESTORE_PTR: - printk ("DC390: RESTORE POINTER message received ... reject\n"); - // fall through - - // reject unknown messages - default: dc390_MsgIn_reject (pACB, pSRB); - } - - /* Clear counter and MsgIn state */ - pSRB->SRBState &= ~SRB_MSGIN; - pACB->MsgLen = 0; - }; + pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8(ScsiFifo); + //pSRB->SRBState = 0; - *psstatus = SCSI_NOP0; - DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + /* Msg complete ? */ + if (dc390_MsgIn_complete(pSRB->MsgInBuf, pACB->MsgLen)) { + DEBUG0(printk(KERN_INFO "DC390: MsgIn:"); + dc390_printMsg(pSRB->MsgInBuf, pACB->MsgLen); + ) + /* Now eval the msg */ + switch (pSRB->MsgInBuf[0]) { + case MSG_DISCONNECT: + pSRB->SRBState = SRB_DISCONNECT; + break; + + case MSG_SIMPLE_QTAG: + case MSG_HEAD_QTAG: + case MSG_ORDER_QTAG: + pSRB = dc390_MsgIn_QTag(pACB, pDCB, pSRB->MsgInBuf[1]); + break; + + case MSG_REJECT_: + DC390_write8(ScsiCmd, RESET_ATN_CMD); + pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ + if (pSRB->SRBState & DO_SYNC_NEGO) + dc390_MsgIn_set_async(pACB, pSRB); + break; + + case MSG_EXTENDED: + /* reject every extended msg but SDTR */ + if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR) + dc390_MsgIn_reject(pACB, pSRB); + else { + if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0) + dc390_MsgIn_set_async(pACB, pSRB); + else + dc390_MsgIn_set_sync(pACB, pSRB); + }; + + // nothing has to be done + case MSG_COMPLETE: + break; + + // SAVE POINTER my be ignored as we have the PSRB associated with the + // scsi command. Thanks, Gerard, for pointing it out. + case MSG_SAVE_PTR: + break; + // The device might want to restart transfer with a RESTORE + case MSG_RESTORE_PTR: + printk("DC390: RESTORE POINTER message received ... reject\n"); + // fall through + + // reject unknown messages + default: + dc390_MsgIn_reject(pACB, pSRB); + } + + /* Clear counter and MsgIn state */ + pSRB->SRBState &= ~SRB_MSGIN; + pACB->MsgLen = 0; + }; + + *psstatus = SCSI_NOP0; + DC390_write8(ScsiCmd, MSG_ACCEPTED_CMD); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } -void -dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir) +void dc390_DataIO_Comm(PACB pACB, PSRB pSRB, UCHAR ioDir) { - PSGL psgl; - ULONG lval; + PSGL psgl; + ULONG lval; - if( pSRB->SGIndex < pSRB->SGcount ) - { - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */); - if( !pSRB->SGToBeXferLen ) - { - psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = virt_to_bus( psgl->address ); - pSRB->SGToBeXferLen = (ULONG) psgl->length; - DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.");) - } - lval = pSRB->SGToBeXferLen; - DEBUG1(printk (KERN_DEBUG " DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);) - DC390_write8 (CtcReg_Low, (UCHAR) lval); - lval >>= 8; - DC390_write8 (CtcReg_Mid, (UCHAR) lval); - lval >>= 8; - DC390_write8 (CtcReg_High, (UCHAR) lval); - - DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen); - DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr); - - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */ - pSRB->SRBState = SRB_DATA_XFER; - - DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD); - - DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); - //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);) - //DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));) - //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);) - } - else /* xfer pad */ - { - if( pSRB->SGcount ) - { - pSRB->AdaptStatus = H_OVER_UNDER_RUN; - pSRB->SRBStatus |= OVER_RUN; - DEBUG0(printk (KERN_WARNING " DC390: Overrun -");) - } - DEBUG0(printk (KERN_WARNING " Clear transfer pad \n");) - DC390_write8 (CtcReg_Low, 0); - DC390_write8 (CtcReg_Mid, 0); - DC390_write8 (CtcReg_High, 0); + if (pSRB->SGIndex < pSRB->SGcount) { + DC390_write8(DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */ ); + if (!pSRB->SGToBeXferLen) { + psgl = pSRB->pSegmentList; + pSRB->SGBusAddr = virt_to_bus(psgl->address); + pSRB->SGToBeXferLen = (ULONG) psgl->length; + DEBUG1(printk(KERN_DEBUG " DC390: Next SG segment."); + ) + } + lval = pSRB->SGToBeXferLen; + DEBUG1(printk(KERN_DEBUG " DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr); + ) + DC390_write8(CtcReg_Low, (UCHAR) lval); + lval >>= 8; + DC390_write8(CtcReg_Mid, (UCHAR) lval); + lval >>= 8; + DC390_write8(CtcReg_High, (UCHAR) lval); + + DC390_write32(DMA_XferCnt, pSRB->SGToBeXferLen); + DC390_write32(DMA_XferAddr, pSRB->SGBusAddr); + + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */ + pSRB->SRBState = SRB_DATA_XFER; + + DC390_write8(ScsiCmd, DMA_COMMAND + INFO_XFER_CMD); + + DC390_write8(DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); + //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);) + //DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));) + //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);) + } else { /* xfer pad */ + if (pSRB->SGcount) { + pSRB->AdaptStatus = H_OVER_UNDER_RUN; + pSRB->SRBStatus |= OVER_RUN; + DEBUG0(printk(KERN_WARNING " DC390: Overrun -"); + ) + } + DEBUG0(printk(KERN_WARNING " Clear transfer pad \n"); + ) + DC390_write8(CtcReg_Low, 0); + DC390_write8(CtcReg_Mid, 0); + DC390_write8(CtcReg_High, 0); - pSRB->SRBState |= SRB_XFERPAD; - DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE); + pSRB->SRBState |= SRB_XFERPAD; + DC390_write8(ScsiCmd, DMA_COMMAND + XFER_PAD_BYTE); /* - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT; - DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); -*/ - } + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT; + DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); + */ + } } -static void -dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +static void dc390_DataOutPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + dc390_DataIO_Comm(pACB, pSRB, WRITE_DIRECTION); +} + +static void dc390_DataInPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + dc390_DataIO_Comm(pACB, pSRB, READ_DIRECTION); +} + +void dc390_CommandPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) { - dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION); + PDCB pDCB; + UCHAR i, cnt; + PUCHAR ptr; + + DC390_write8(ScsiCmd, RESET_ATN_CMD); + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); + if (!(pSRB->SRBFlag & AUTO_REQSENSE)) { + cnt = (UCHAR) pSRB->ScsiCmdLen; + ptr = (PUCHAR) pSRB->CmdBlock; + for (i = 0; i < cnt; i++) + DC390_write8(ScsiFifo, *(ptr++)); + } else { + UCHAR bval = 0; + DC390_write8(ScsiFifo, REQUEST_SENSE); + pDCB = pACB->pActiveDCB; + DC390_write8(ScsiFifo, pDCB->IdentifyMsg << 5); + DC390_write8(ScsiFifo, bval); + DC390_write8(ScsiFifo, bval); + DC390_write8(ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); + DC390_write8(ScsiFifo, bval); + } + pSRB->SRBState = SRB_COMMAND; + DC390_write8(ScsiCmd, INFO_XFER_CMD); } -static void -dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +static void dc390_StatusPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) { - dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION); + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); + pSRB->SRBState = SRB_STATUS; + DC390_write8(ScsiCmd, INITIATOR_CMD_CMPLTE); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } -void -dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void dc390_MsgOutPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) { - PDCB pDCB; - UCHAR i, cnt; - PUCHAR ptr; + UCHAR bval, i, cnt; + PUCHAR ptr; + PDCB pDCB; - DC390_write8 (ScsiCmd, RESET_ATN_CMD); - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - if( !(pSRB->SRBFlag & AUTO_REQSENSE) ) - { - cnt = (UCHAR) pSRB->ScsiCmdLen; - ptr = (PUCHAR) pSRB->CmdBlock; - for(i=0; i < cnt; i++) - DC390_write8 (ScsiFifo, *(ptr++)); - } - else - { - UCHAR bval = 0; - DC390_write8 (ScsiFifo, REQUEST_SENSE); + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); pDCB = pACB->pActiveDCB; - DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5); - DC390_write8 (ScsiFifo, bval); - DC390_write8 (ScsiFifo, bval); - DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); - DC390_write8 (ScsiFifo, bval); - } - pSRB->SRBState = SRB_COMMAND; - DC390_write8 (ScsiCmd, INFO_XFER_CMD); -} - -static void -dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - pSRB->SRBState = SRB_STATUS; - DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); -} - -void -dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - UCHAR bval, i, cnt; - PUCHAR ptr; - PDCB pDCB; - - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - pDCB = pACB->pActiveDCB; - if( !(pSRB->SRBState & SRB_MSGOUT) ) - { - cnt = pSRB->MsgCnt; - if( cnt ) - { - ptr = (PUCHAR) pSRB->MsgOutBuf; - for(i=0; i < cnt; i++) - DC390_write8 (ScsiFifo, *(ptr++)); - pSRB->MsgCnt = 0; - if( (pDCB->DCBFlag & ABORT_DEV_) && - (pSRB->MsgOutBuf[0] == MSG_ABORT) ) - pSRB->SRBState = SRB_ABORT_SENT; + if (!(pSRB->SRBState & SRB_MSGOUT)) { + cnt = pSRB->MsgCnt; + if (cnt) { + ptr = (PUCHAR) pSRB->MsgOutBuf; + for (i = 0; i < cnt; i++) + DC390_write8(ScsiFifo, *(ptr++)); + pSRB->MsgCnt = 0; + if ((pDCB->DCBFlag & ABORT_DEV_) && + (pSRB->MsgOutBuf[0] == MSG_ABORT)) + pSRB->SRBState = SRB_ABORT_SENT; + } else { + bval = MSG_ABORT; /* ??? MSG_NOP */ + if ((pSRB->CmdBlock[0] == INQUIRY) || + (pSRB->CmdBlock[0] == REQUEST_SENSE) || + (pSRB->SRBFlag & AUTO_REQSENSE)) { + if (pDCB->SyncMode & SYNC_ENABLE) + goto mop1; + } + DC390_write8(ScsiFifo, bval); + } + DC390_write8(ScsiCmd, INFO_XFER_CMD); + } else { + mop1: + //printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + DC390_write8(ScsiFifo, MSG_EXTENDED); + DC390_write8(ScsiFifo, 3); /* ;length of extended msg */ + DC390_write8(ScsiFifo, EXTENDED_SDTR); /* ; sync nego */ + DC390_write8(ScsiFifo, pDCB->NegoPeriod); + if (pDCB->SyncOffset & 0x0f) + DC390_write8(ScsiFifo, pDCB->SyncOffset); + else + DC390_write8(ScsiFifo, SYNC_NEGO_OFFSET); + pSRB->SRBState |= DO_SYNC_NEGO; + DC390_write8(ScsiCmd, INFO_XFER_CMD); } - else - { - bval = MSG_ABORT; /* ??? MSG_NOP */ - if( (pSRB->CmdBlock[0] == INQUIRY ) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE) ) - { - if( pDCB->SyncMode & SYNC_ENABLE ) - goto mop1; - } - DC390_write8 (ScsiFifo, bval); - } - DC390_write8 (ScsiCmd, INFO_XFER_CMD); - } - else - { -mop1: - //printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN); - DC390_write8 (ScsiFifo, MSG_EXTENDED); - DC390_write8 (ScsiFifo, 3); /* ;length of extended msg */ - DC390_write8 (ScsiFifo, EXTENDED_SDTR); /* ; sync nego */ - DC390_write8 (ScsiFifo, pDCB->NegoPeriod); - if (pDCB->SyncOffset & 0x0f) - DC390_write8 (ScsiFifo, pDCB->SyncOffset); - else - DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET); - pSRB->SRBState |= DO_SYNC_NEGO; - DC390_write8 (ScsiCmd, INFO_XFER_CMD); - } } -static void -dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +static void dc390_MsgInPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) { - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - if( !(pSRB->SRBState & SRB_MSGIN) ) - { - pSRB->SRBState &= ~SRB_DISCONNECT; - pSRB->SRBState |= SRB_MSGIN; - } - DC390_write8 (ScsiCmd, INFO_XFER_CMD); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); + if (!(pSRB->SRBState & SRB_MSGIN)) { + pSRB->SRBState &= ~SRB_DISCONNECT; + pSRB->SRBState |= SRB_MSGIN; + } + DC390_write8(ScsiCmd, INFO_XFER_CMD); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } -static void -dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +static void dc390_Nop_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) { } -static void -dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus) +static void dc390_Nop_1(PACB pACB, PSRB pSRB, PUCHAR psstatus) { } -static void -dc390_SetXferRate( PACB pACB, PDCB pDCB ) +static void dc390_SetXferRate(PACB pACB, PDCB pDCB) { - UCHAR bval, i, cnt; - PDCB ptr; + UCHAR bval, i, cnt; + PDCB ptr; - if( !(pDCB->IdentifyMsg & 0x07) ) - { - if( pACB->scan_devices ) - { - dc390_CurrSyncOffset = pDCB->SyncOffset; + if (!(pDCB->IdentifyMsg & 0x07)) { + if (pACB->scan_devices) { + dc390_CurrSyncOffset = pDCB->SyncOffset; + } else { + ptr = pACB->pLinkDCB; + cnt = pACB->DCBCnt; + bval = pDCB->UnitSCSIID; + for (i = 0; i < cnt; i++) { + if (ptr->UnitSCSIID == bval) { + ptr->SyncPeriod = pDCB->SyncPeriod; + ptr->SyncOffset = pDCB->SyncOffset; + ptr->CtrlR3 = pDCB->CtrlR3; + ptr->CtrlR4 = pDCB->CtrlR4; + ptr->SyncMode = pDCB->SyncMode; + } + ptr = ptr->pNextDCB; + } + } } - else - { - ptr = pACB->pLinkDCB; - cnt = pACB->DCBCnt; - bval = pDCB->UnitSCSIID; - for(i=0; iUnitSCSIID == bval ) - { - ptr->SyncPeriod = pDCB->SyncPeriod; - ptr->SyncOffset = pDCB->SyncOffset; - ptr->CtrlR3 = pDCB->CtrlR3; - ptr->CtrlR4 = pDCB->CtrlR4; - ptr->SyncMode = pDCB->SyncMode; - } - ptr = ptr->pNextDCB; - } - } - } - return; + return; } -void -dc390_Disconnect( PACB pACB ) -{ - PDCB pDCB; - PSRB pSRB, psrb; - UCHAR i, cnt; - - DEBUG0(printk(KERN_INFO "DISC,");) - - pDCB = pACB->pActiveDCB; - if (!pDCB) - { - int j = 400; - DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n",\ - (ULONG)pACB,(ULONG)pDCB,pACB->IOPortBase,pACB->IRQLevel);) - while (--j) udelay (1000); - DC390_read8 (INT_Status); /* Reset Pending INT */ - DC390_write8 (ScsiCmd, EN_SEL_RESEL); - return; - } - pSRB = pDCB->pActiveSRB; - pACB->pActiveDCB = 0; - pSRB->ScsiPhase = SCSI_NOP0; - DC390_write8 (ScsiCmd, EN_SEL_RESEL); - if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) - { - pSRB->SRBState = 0; - dc390_DoWaitingSRB( pACB ); - } - else if( pSRB->SRBState & SRB_ABORT_SENT ) - { - pDCB->TagMask = 0; - pDCB->DCBFlag = 0; - cnt = pDCB->GoingSRBCnt; - pDCB->GoingSRBCnt = 0; - pSRB = pDCB->pGoingSRB; - for( i=0; i < cnt; i++) - { - psrb = pSRB->pNextSRB; - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; - pSRB = psrb; - } - pDCB->pGoingSRB = 0; - dc390_DoWaitingSRB( pACB ); - } - else - { - if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) || - !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) ) - { /* Selection time out */ - if( !(pACB->scan_devices) ) - { - pSRB->SRBState = SRB_READY; - dc390_RewaitSRB( pDCB, pSRB); - } - else - { - pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT; - goto disc1; - } +void dc390_Disconnect(PACB pACB) +{ + PDCB pDCB; + PSRB pSRB, psrb; + UCHAR i, cnt; + + DEBUG0(printk(KERN_INFO "DISC,"); + ) + pDCB = pACB->pActiveDCB; + if (!pDCB) { + int j = 400; + DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n", \ + (ULONG) pACB, (ULONG) pDCB, pACB->IOPortBase, pACB->IRQLevel); + ) + while (--j) + udelay(1000); + DC390_read8(INT_Status); /* Reset Pending INT */ + DC390_write8(ScsiCmd, EN_SEL_RESEL); + return; } - else if( pSRB->SRBState & SRB_DISCONNECT ) - { - dc390_DoWaitingSRB( pACB ); + pSRB = pDCB->pActiveSRB; + pACB->pActiveDCB = 0; + pSRB->ScsiPhase = SCSI_NOP0; + DC390_write8(ScsiCmd, EN_SEL_RESEL); + if (pSRB->SRBState & SRB_UNEXPECT_RESEL) { + pSRB->SRBState = 0; + dc390_DoWaitingSRB(pACB); + } else if (pSRB->SRBState & SRB_ABORT_SENT) { + pDCB->TagMask = 0; + pDCB->DCBFlag = 0; + cnt = pDCB->GoingSRBCnt; + pDCB->GoingSRBCnt = 0; + pSRB = pDCB->pGoingSRB; + for (i = 0; i < cnt; i++) { + psrb = pSRB->pNextSRB; + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + pSRB = psrb; + } + pDCB->pGoingSRB = 0; + dc390_DoWaitingSRB(pACB); + } else { + if ((pSRB->SRBState & (SRB_START_ + SRB_MSGOUT)) || + !(pSRB->SRBState & (SRB_DISCONNECT + SRB_COMPLETED))) { /* Selection time out */ + if (!(pACB->scan_devices)) { + pSRB->SRBState = SRB_READY; + dc390_RewaitSRB(pDCB, pSRB); + } else { + pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT; + goto disc1; + } + } else if (pSRB->SRBState & SRB_DISCONNECT) { + dc390_DoWaitingSRB(pACB); + } else if (pSRB->SRBState & SRB_COMPLETED) { + disc1: + if (pDCB->MaxCommand > 1) { + pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* free tag mask */ + } + pDCB->pActiveSRB = 0; + pSRB->SRBState = SRB_FREE; + dc390_SRBdone(pACB, pDCB, pSRB); + } } - else if( pSRB->SRBState & SRB_COMPLETED ) - { -disc1: - if(pDCB->MaxCommand > 1) - { - pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* free tag mask */ - } - pDCB->pActiveSRB = 0; - pSRB->SRBState = SRB_FREE; - dc390_SRBdone( pACB, pDCB, pSRB); - } - } - pACB->MsgLen = 0; + pACB->MsgLen = 0; } -void -dc390_Reselect( PACB pACB ) -{ - PDCB pDCB; - PSRB pSRB; - USHORT wval; - UCHAR bval; - - DEBUG0(printk(KERN_INFO "RSEL,");) - pDCB = pACB->pActiveDCB; - if( pDCB ) - { /* Arbitration lost but Reselection won */ - DEBUG0(printk ("(ActiveDCB != 0)");) - pSRB = pDCB->pActiveSRB; - if( !( pACB->scan_devices ) ) - { - pSRB->SRBState = SRB_READY; - dc390_RewaitSRB( pDCB, pSRB); +void dc390_Reselect(PACB pACB) +{ + PDCB pDCB; + PSRB pSRB; + USHORT wval; + UCHAR bval; + + DEBUG0(printk(KERN_INFO "RSEL,"); + ) + pDCB = pACB->pActiveDCB; + if (pDCB) { /* Arbitration lost but Reselection won */ + DEBUG0(printk("(ActiveDCB != 0)"); + ) + pSRB = pDCB->pActiveSRB; + if (!(pACB->scan_devices)) { + pSRB->SRBState = SRB_READY; + dc390_RewaitSRB(pDCB, pSRB); + } } - } - bval = DC390_read8 (ScsiFifo); /* get ID */ - DEBUG0(printk ("Dev %02x,", bval);) - bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ - wval = 0; - while (bval >>= 1) wval++; - wval |= ( (USHORT) DC390_read8 (ScsiFifo) & 7) << 8; /* get LUN */ - DEBUG0(printk ("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8);) - pDCB = pACB->pLinkDCB; - while( wval != *((PUSHORT) &pDCB->UnitSCSIID) ) - { - pDCB = pDCB->pNextDCB; - if( pDCB == pACB->pLinkDCB ) - { - printk (KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); - return; - } - } - pACB->pActiveDCB = pDCB; - if( pDCB->SyncMode & EN_TAG_QUEUEING ) - { - pSRB = pACB->pTmpSRB; /* ?? */ - pDCB->pActiveSRB = pSRB; - } - else - { - pSRB = pDCB->pActiveSRB; - if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) ) - { - pSRB= pACB->pTmpSRB; - pSRB->SRBState = SRB_UNEXPECT_RESEL; - printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); - pDCB->pActiveSRB = pSRB; - dc390_EnableMsgOut_Abort ( pACB, pSRB ); + bval = DC390_read8(ScsiFifo); /* get ID */ + DEBUG0(printk("Dev %02x,", bval); + ) + bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ + wval = 0; + while (bval >>= 1) + wval++; + wval |= ((USHORT) DC390_read8(ScsiFifo) & 7) << 8; /* get LUN */ + DEBUG0(printk("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8); + ) + pDCB = pACB->pLinkDCB; + while (wval != *((PUSHORT) & pDCB->UnitSCSIID)) { + pDCB = pDCB->pNextDCB; + if (pDCB == pACB->pLinkDCB) { + printk(KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n", + wval & 0xff, (wval & 0xff00) >> 8); + return; + } } - else - { - if( pDCB->DCBFlag & ABORT_DEV_ ) - { - pSRB->SRBState = SRB_ABORT_SENT; - printk (KERN_INFO "DC390: Reselect: Abort (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); - dc390_EnableMsgOut_Abort( pACB, pSRB ); - } - else - pSRB->SRBState = SRB_DATA_XFER; + pACB->pActiveDCB = pDCB; + if (pDCB->SyncMode & EN_TAG_QUEUEING) { + pSRB = pACB->pTmpSRB; /* ?? */ + pDCB->pActiveSRB = pSRB; + } else { + pSRB = pDCB->pActiveSRB; + if (!pSRB || !(pSRB->SRBState & SRB_DISCONNECT)) { + pSRB = pACB->pTmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + printk(KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n", + wval & 0xff, (wval & 0xff00) >> 8); + pDCB->pActiveSRB = pSRB; + dc390_EnableMsgOut_Abort(pACB, pSRB); + } else { + if (pDCB->DCBFlag & ABORT_DEV_) { + pSRB->SRBState = SRB_ABORT_SENT; + printk(KERN_INFO "DC390: Reselect: Abort (ID %02x, LUN %02x)\n", + wval & 0xff, (wval & 0xff00) >> 8); + dc390_EnableMsgOut_Abort(pACB, pSRB); + } else + pSRB->SRBState = SRB_DATA_XFER; + } } - } - DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);) - pSRB->ScsiPhase = SCSI_NOP0; - DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID); - DC390_write8 (Sync_Period, pDCB->SyncPeriod); - DC390_write8 (Sync_Offset, pDCB->SyncOffset); - DC390_write8 (CtrlReg1, pDCB->CtrlR1); - DC390_write8 (CtrlReg3, pDCB->CtrlR3); - DC390_write8 (CtrlReg4, pDCB->CtrlR4); /* ; Glitch eater */ - DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); /* ;to release the /ACK signal */ + DEBUG1(printk(KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber); + ) + pSRB->ScsiPhase = SCSI_NOP0; + DC390_write8(Scsi_Dest_ID, pDCB->UnitSCSIID); + DC390_write8(Sync_Period, pDCB->SyncPeriod); + DC390_write8(Sync_Offset, pDCB->SyncOffset); + DC390_write8(CtrlReg1, pDCB->CtrlR1); + DC390_write8(CtrlReg3, pDCB->CtrlR3); + DC390_write8(CtrlReg4, pDCB->CtrlR4); /* ; Glitch eater */ + DC390_write8(ScsiCmd, MSG_ACCEPTED_CMD); /* ;to release the /ACK signal */ } -static void -dc390_remove_dev (PACB pACB, PDCB pDCB) -{ - PDCB pPrevDCB = pACB->pLinkDCB; - - pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN); - if (pDCB->GoingSRBCnt > 1) - { - DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB, pDCB->GoingSRBCnt);) - return; - }; - - if (pDCB == pACB->pLinkDCB) - { - if (pDCB->pNextDCB == pDCB) pDCB->pNextDCB = 0; - pACB->pLinkDCB = pDCB->pNextDCB; - pACB->pLastDCB->pNextDCB = pDCB->pNextDCB; - } - else - { - while (pPrevDCB->pNextDCB != pDCB) pPrevDCB = pPrevDCB->pNextDCB; - pPrevDCB->pNextDCB = pDCB->pNextDCB; - if (pDCB == pACB->pLastDCB) pACB->pLastDCB = pPrevDCB; - } - - DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n",\ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);) - kfree (pDCB); if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0; - pACB->DCBCnt--; - /* pACB->DeviceCnt--; */ +static void dc390_remove_dev(PACB pACB, PDCB pDCB) +{ + PDCB pPrevDCB = pACB->pLinkDCB; + + pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN); + if (pDCB->GoingSRBCnt > 1) { + DCBDEBUG(printk(KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n", \ + pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int) pDCB, pDCB->GoingSRBCnt); + ) + return; + }; + + if (pDCB == pACB->pLinkDCB) { + if (pDCB->pNextDCB == pDCB) + pDCB->pNextDCB = 0; + pACB->pLinkDCB = pDCB->pNextDCB; + pACB->pLastDCB->pNextDCB = pDCB->pNextDCB; + } else { + while (pPrevDCB->pNextDCB != pDCB) + pPrevDCB = pPrevDCB->pNextDCB; + pPrevDCB->pNextDCB = pDCB->pNextDCB; + if (pDCB == pACB->pLastDCB) + pACB->pLastDCB = pPrevDCB; + } + + DCBDEBUG(printk(KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n", \ + pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int) pDCB); + ) + kfree(pDCB); + if (pDCB == pACB->pActiveDCB) + pACB->pActiveDCB = 0; + pACB->DCBCnt--; + /* pACB->DeviceCnt--; */ }; static UCHAR __inline__ -dc390_tagq_blacklist (char* name) + dc390_tagq_blacklist(char *name) { - UCHAR i; - for(i=0; iVers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2 ) - { - if ( (ptr->Flags & SCSI_INQ_CMDQUEUE) && - (pDCB->DevMode & TAG_QUEUEING_) && - /* ((pDCB->DevType == TYPE_DISK) - || (pDCB->DevType == TYPE_MOD)) &&*/ - !dc390_tagq_blacklist (((char*)ptr)+8) ) - { - pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum; - pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */; - pDCB->TagMask = 0; - } - else - { - /* Do we really need to check for DevType here ? */ - if ( 0 /*(pDCB->DevMode & EN_DISCONNECT_)*/ - /* && ((pDCB->DevType == TYPE_DISK) - || (pDCB->DevType == TYPE_MOD))*/ ) - pDCB->SyncMode |= EN_ATN_STOP; - else - //pDCB->SyncMode &= ~EN_ATN_STOP; - pDCB->SyncMode &= ~0; - } - } + /* Check for SCSI format (ANSI and Response data format) */ + if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) { + if ((ptr->Flags & SCSI_INQ_CMDQUEUE) && + (pDCB->DevMode & TAG_QUEUEING_) && + /* ((pDCB->DevType == TYPE_DISK) + || (pDCB->DevType == TYPE_MOD)) && */ + !dc390_tagq_blacklist(((char *) ptr) + 8)) { + pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum; + pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */ ; + pDCB->TagMask = 0; + } else { + /* Do we really need to check for DevType here ? */ + if (0 /*(pDCB->DevMode & EN_DISCONNECT_) */ + /* && ((pDCB->DevType == TYPE_DISK) + || (pDCB->DevType == TYPE_MOD)) */ ) + pDCB->SyncMode |= EN_ATN_STOP; + else + //pDCB->SyncMode &= ~EN_ATN_STOP; + pDCB->SyncMode &= ~0; + } + } }; -static void -dc390_add_dev (PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr) +static void dc390_add_dev(PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr) { - UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE; - pDCB->DevType = bval1; - /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */ - dc390_disc_tagq_set (pDCB, ptr); + UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE; + pDCB->DevType = bval1; + /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */ + dc390_disc_tagq_set(pDCB, ptr); }; -void -dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) +void dc390_SRBdone(PACB pACB, PDCB pDCB, PSRB pSRB) { - PSRB psrb; - UCHAR bval, status, i; - PSCSICMD pcmd; - PSCSI_INQDATA ptr; - PSGL ptr2; - ULONG swlval; - - pcmd = pSRB->pcmd; - status = pSRB->TargetStatus; - DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\ - pSRB, pcmd->pid);) - if(pSRB->SRBFlag & AUTO_REQSENSE) - { /* Last command was a Request Sense */ - pSRB->SRBFlag &= ~AUTO_REQSENSE; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = SCSI_STAT_CHECKCOND; + PSRB psrb; + UCHAR bval, status, i; + PSCSICMD pcmd; + PSCSI_INQDATA ptr; + PSGL ptr2; + ULONG swlval; + + pcmd = pSRB->pcmd; + status = pSRB->TargetStatus; + DEBUG0(printk(" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result, \ + pSRB, pcmd->pid); + ) + if (pSRB->SRBFlag & AUTO_REQSENSE) { /* Last command was a Request Sense */ + pSRB->SRBFlag &= ~AUTO_REQSENSE; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = SCSI_STAT_CHECKCOND; #ifdef DC390_REMOVABLEDEBUG - switch (pcmd->sense_buffer[2] & 0x0f) - { - case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, - status, pACB->scan_devices); break; - case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, - status, pACB->scan_devices); break; - case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, - status, pACB->scan_devices); break; - case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, - status, pACB->scan_devices); break; - case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, - status, pACB->scan_devices); break; - } + switch (pcmd->sense_buffer[2] & 0x0f) { + case NOT_READY: + printk(KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + status, pACB->scan_devices); + break; + case UNIT_ATTENTION: + printk(KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + status, pACB->scan_devices); + break; + case ILLEGAL_REQUEST: + printk(KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + status, pACB->scan_devices); + break; + case MEDIUM_ERROR: + printk(KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + status, pACB->scan_devices); + break; + case HARDWARE_ERROR: + printk(KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + status, pACB->scan_devices); + break; + } #endif - //pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status; - if(status == SCSI_STAT_CHECKCOND) - { - pcmd->result = DID_BAD_TARGET << 16; - goto ckc_e; - } - if(pSRB->RetryCnt == 0) - { - (ULONG)(pSRB->CmdBlock[0]) = pSRB->Segment0[0]; - pSRB->TotalXferredLen = pSRB->Segment1[1]; - if( (pSRB->TotalXferredLen) && - (pSRB->TotalXferredLen >= pcmd->underflow) ) - pcmd->result |= (DID_OK << 16); - else - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | - SCSI_STAT_CHECKCOND; - REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\ - (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) - goto ckc_e; - } - else /* Retry */ - { - pSRB->RetryCnt--; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; - *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; - /* Don't retry on TEST_UNIT_READY */ - if( pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */) - { - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) - | SCSI_STAT_CHECKCOND; - REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\ - (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) - goto ckc_e; - } - pcmd->result |= (DRIVER_SENSE << 24); - pSRB->SGcount = (UCHAR) pSRB->Segment1[0]; - pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); - pSRB->SGIndex = 0; - pSRB->TotalXferredLen = 0; - pSRB->SGToBeXferLen = 0; - if( pcmd->use_sg ) - pSRB->pSegmentList = (PSGL) pcmd->request_buffer; - else if( pcmd->request_buffer ) - { - pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; - pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; - pSRB->Segmentx.length = pcmd->request_bufflen; - } - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) - dc390_RewaitSRB( pDCB, pSRB ); - return; - } - } - if( status ) - { - if( status == SCSI_STAT_CHECKCOND) - { - REMOVABLEDEBUG(printk (KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n",\ - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) - if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) ) - { - bval = pSRB->SGcount; - swlval = 0; - ptr2 = pSRB->pSegmentList; - for( i=pSRB->SGIndex; i < bval; i++) - { - swlval += ptr2->length; - ptr2++; - } - REMOVABLEDEBUG(printk(KERN_INFO "XferredLen=%08x,NotXferLen=%08x\n",\ - (UINT) pSRB->TotalXferredLen, (UINT) swlval);) - } - dc390_RequestSense( pACB, pDCB, pSRB ); - return; - } - else if( status == SCSI_STAT_QUEUEFULL ) - { - bval = (UCHAR) pDCB->GoingSRBCnt; - bval--; - pDCB->MaxCommand = bval; - dc390_RewaitSRB( pDCB, pSRB ); - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - return; - } - else if(status == SCSI_STAT_SEL_TIMEOUT) - { - pSRB->AdaptStatus = H_SEL_TIMEOUT; - pSRB->TargetStatus = 0; - pcmd->result = DID_BAD_TARGET << 16; - /* Devices are removed below ... */ - } - else if (status == SCSI_STAT_BUSY && - (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) && - pACB->scan_devices) - { - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = status; - pcmd->result = (ULONG) (pSRB->EndMessage << 8) - /* | (ULONG) status */; - } - else - { /* Another error */ - pSRB->AdaptStatus = 0; - if( pSRB->RetryCnt ) - { /* Retry */ - pSRB->RetryCnt--; - pSRB->TargetStatus = 0; - pSRB->SGIndex = 0; - pSRB->TotalXferredLen = 0; - pSRB->SGToBeXferLen = 0; - if( pcmd->use_sg ) - pSRB->pSegmentList = (PSGL) pcmd->request_buffer; - else if( pcmd->request_buffer ) - { - pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; - pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; - pSRB->Segmentx.length = pcmd->request_bufflen; + //pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status; + if (status == SCSI_STAT_CHECKCOND) { + pcmd->result = DID_BAD_TARGET << 16; + goto ckc_e; + } + if (pSRB->RetryCnt == 0) { + (ULONG) (pSRB->CmdBlock[0]) = pSRB->Segment0[0]; + pSRB->TotalXferredLen = pSRB->Segment1[1]; + if ((pSRB->TotalXferredLen) && + (pSRB->TotalXferredLen >= pcmd->underflow)) + pcmd->result |= (DID_OK << 16); + else + pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | + SCSI_STAT_CHECKCOND; + REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n", pSRB->CmdBlock[0], \ + (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen); + ) + goto ckc_e; + } else { /* Retry */ + pSRB->RetryCnt--; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + *((PULONG) & (pSRB->CmdBlock[0])) = pSRB->Segment0[0]; + *((PULONG) & (pSRB->CmdBlock[4])) = pSRB->Segment0[1]; + /* Don't retry on TEST_UNIT_READY */ + if (pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */ ) { + pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) + | SCSI_STAT_CHECKCOND; + REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n", pSRB->CmdBlock[0], \ + (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen); + ) + goto ckc_e; + } + pcmd->result |= (DRIVER_SENSE << 24); + pSRB->SGcount = (UCHAR) pSRB->Segment1[0]; + pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); + pSRB->SGIndex = 0; + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if (pcmd->use_sg) + pSRB->pSegmentList = (PSGL) pcmd->request_buffer; + else if (pcmd->request_buffer) { + pSRB->pSegmentList = (PSGL) & pSRB->Segmentx; + pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; + pSRB->Segmentx.length = pcmd->request_bufflen; + } + if (dc390_StartSCSI(pACB, pDCB, pSRB)) + dc390_RewaitSRB(pDCB, pSRB); + return; } - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) - dc390_RewaitSRB( pDCB, pSRB ); - return; - } - else - { /* Report error */ - pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) | - (ULONG) status; - } - } - } - else - { /* Target status == 0 */ - status = pSRB->AdaptStatus; - if(status & H_OVER_UNDER_RUN) - { - pSRB->TargetStatus = 0; - pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8); } - else if( pSRB->SRBStatus & PARITY_ERROR) - { - pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8); + if (status) { + if (status == SCSI_STAT_CHECKCOND) { + REMOVABLEDEBUG(printk(KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n", \ + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + ) + if ((pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen)) { + bval = pSRB->SGcount; + swlval = 0; + ptr2 = pSRB->pSegmentList; + for (i = pSRB->SGIndex; i < bval; i++) { + swlval += ptr2->length; + ptr2++; + } + REMOVABLEDEBUG(printk(KERN_INFO "XferredLen=%08x,NotXferLen=%08x\n", \ + (UINT) pSRB->TotalXferredLen, (UINT) swlval); + ) + } + dc390_RequestSense(pACB, pDCB, pSRB); + return; + } else if (status == SCSI_STAT_QUEUEFULL) { + bval = (UCHAR) pDCB->GoingSRBCnt; + bval--; + pDCB->MaxCommand = bval; + dc390_RewaitSRB(pDCB, pSRB); + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + return; + } else if (status == SCSI_STAT_SEL_TIMEOUT) { + pSRB->AdaptStatus = H_SEL_TIMEOUT; + pSRB->TargetStatus = 0; + pcmd->result = DID_BAD_TARGET << 16; + /* Devices are removed below ... */ + } else if (status == SCSI_STAT_BUSY && + (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) && + pACB->scan_devices) { + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = status; + pcmd->result = (ULONG) (pSRB->EndMessage << 8) + /* | (ULONG) status */ ; + } else { /* Another error */ + pSRB->AdaptStatus = 0; + if (pSRB->RetryCnt) { /* Retry */ + pSRB->RetryCnt--; + pSRB->TargetStatus = 0; + pSRB->SGIndex = 0; + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if (pcmd->use_sg) + pSRB->pSegmentList = (PSGL) pcmd->request_buffer; + else if (pcmd->request_buffer) { + pSRB->pSegmentList = (PSGL) & pSRB->Segmentx; + pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; + pSRB->Segmentx.length = pcmd->request_bufflen; + } + if (dc390_StartSCSI(pACB, pDCB, pSRB)) + dc390_RewaitSRB(pDCB, pSRB); + return; + } else { /* Report error */ + pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) | + (ULONG) status; + } + } + } else { /* Target status == 0 */ + status = pSRB->AdaptStatus; + if (status & H_OVER_UNDER_RUN) { + pSRB->TargetStatus = 0; + pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8); + } else if (pSRB->SRBStatus & PARITY_ERROR) { + pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8); + } else { /* No error */ + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pcmd->result |= (DID_OK << 16); + } } - else /* No error */ - { - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - pcmd->result |= (DID_OK << 16); - } - } - -ckc_e: - if( pACB->scan_devices ) - { - if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) - { + + ckc_e: + if (pACB->scan_devices) { + if (pSRB->CmdBlock[0] == TEST_UNIT_READY) { #ifdef DC390_DEBUG0 - printk (KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result); - if (pcmd->result & DRIVER_SENSE << 24) printk (" (sense: %02x %02x %02x %02x)\n", - pcmd->sense_buffer[0], pcmd->sense_buffer[1], - pcmd->sense_buffer[2], pcmd->sense_buffer[3]); - else printk ("\n"); + printk(KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result); + if (pcmd->result & DRIVER_SENSE << 24) + printk(" (sense: %02x %02x %02x %02x)\n", + pcmd->sense_buffer[0], pcmd->sense_buffer[1], + pcmd->sense_buffer[2], pcmd->sense_buffer[3]); + else + printk("\n"); #endif - if((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) || - ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 && - (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16) - { - /* device not present: remove */ - dc390_remove_dev (pACB, pDCB); - - if( (pcmd->target == pACB->pScsiHost->max_id - 1) && - ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) ) - pACB->scan_devices = 0; - } - else - { - /* device present: add */ - if( (pcmd->target == pACB->pScsiHost->max_id - 1) && - (pcmd->lun == pACB->pScsiHost->max_lun - 1) ) - pACB->scan_devices = END_SCAN ; - /* pACB->DeviceCnt++; */ /* Dev is added on INQUIRY */ - } - } - } - - if( pSRB->CmdBlock[0] == INQUIRY && - (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND) ) - { - ptr = (PSCSI_INQDATA) (pcmd->request_buffer); - if( pcmd->use_sg ) - ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); - if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV) - { - /* device not present: remove */ - dc390_remove_dev (pACB, pDCB); - } - else - { - /* device found: add */ - dc390_add_dev (pACB, pDCB, ptr); - if (pACB->scan_devices) pACB->DeviceCnt++; - } - if( (pcmd->target == pACB->pScsiHost->max_id - 1) && - (pcmd->lun == pACB->pScsiHost->max_lun - 1) ) - pACB->scan_devices = 0; - }; + if ((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) || + ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 && + (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16) { + /* device not present: remove */ + dc390_remove_dev(pACB, pDCB); + + if ((pcmd->target == pACB->pScsiHost->max_id - 1) && + ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1))) + pACB->scan_devices = 0; + } else { + /* device present: add */ + if ((pcmd->target == pACB->pScsiHost->max_id - 1) && + (pcmd->lun == pACB->pScsiHost->max_lun - 1)) + pACB->scan_devices = END_SCAN; + /* pACB->DeviceCnt++; *//* Dev is added on INQUIRY */ + } + } + } + if (pSRB->CmdBlock[0] == INQUIRY && + (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND)) { + ptr = (PSCSI_INQDATA) (pcmd->request_buffer); + if (pcmd->use_sg) + ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); + if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV) { + /* device not present: remove */ + dc390_remove_dev(pACB, pDCB); + } else { + /* device found: add */ + dc390_add_dev(pACB, pDCB, ptr); + if (pACB->scan_devices) + pACB->DeviceCnt++; + } + if ((pcmd->target == pACB->pScsiHost->max_id - 1) && + (pcmd->lun == pACB->pScsiHost->max_lun - 1)) + pACB->scan_devices = 0; + }; /* dc390_ReleaseSRB( pDCB, pSRB ); */ - if(pSRB == pDCB->pGoingSRB ) - { - pDCB->pGoingSRB = pSRB->pNextSRB; - } - else - { - psrb = pDCB->pGoingSRB; - while( psrb->pNextSRB != pSRB ) - psrb = psrb->pNextSRB; - psrb->pNextSRB = pSRB->pNextSRB; - if( pSRB == pDCB->pGoingLast ) - pDCB->pGoingLast = psrb; - } - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; - pDCB->GoingSRBCnt--; - - dc390_DoWaitingSRB( pACB ); - - DC390_UNLOCK_ACB_NI; - pcmd->scsi_done( pcmd ); - DC390_LOCK_ACB_NI; - - if( pDCB->QIORBCnt ) - dc390_DoNextCmd( pACB, pDCB ); - return; + if (pSRB == pDCB->pGoingSRB) { + pDCB->pGoingSRB = pSRB->pNextSRB; + } else { + psrb = pDCB->pGoingSRB; + while (psrb->pNextSRB != pSRB) + psrb = psrb->pNextSRB; + psrb->pNextSRB = pSRB->pNextSRB; + if (pSRB == pDCB->pGoingLast) + pDCB->pGoingLast = psrb; + } + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + pDCB->GoingSRBCnt--; + + dc390_DoWaitingSRB(pACB); + + DC390_UNLOCK_ACB_NI; + pcmd->scsi_done(pcmd); + DC390_LOCK_ACB_NI; + + if (pDCB->QIORBCnt) + dc390_DoNextCmd(pACB, pDCB); + return; } /* Remove all SRBs and tell midlevel code DID_RESET */ -void -dc390_DoingSRB_Done( PACB pACB ) +void dc390_DoingSRB_Done(PACB pACB) { - PDCB pDCB, pdcb; - PSRB psrb, psrb2; - UCHAR i; - PSCSICMD pcmd; - - pDCB = pACB->pLinkDCB; - pdcb = pDCB; - if (! pdcb) return; - do - { - psrb = pdcb->pGoingSRB; - for( i=0; iGoingSRBCnt; i++) - { - psrb2 = psrb->pNextSRB; - pcmd = psrb->pcmd; - pcmd->result = DID_RESET << 16; - -/* ReleaseSRB( pDCB, pSRB ); */ - - psrb->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = psrb; - - DC390_UNLOCK_ACB_NI; - pcmd->scsi_done( pcmd ); - DC390_LOCK_ACB_NI; - psrb = psrb2; - } - pdcb->GoingSRBCnt = 0;; - pdcb->pGoingSRB = NULL; - pdcb->TagMask = 0; - pdcb = pdcb->pNextDCB; - } while( pdcb != pDCB ); + PDCB pDCB, pdcb; + PSRB psrb, psrb2; + UCHAR i; + PSCSICMD pcmd; + + pDCB = pACB->pLinkDCB; + pdcb = pDCB; + if (!pdcb) + return; + do { + psrb = pdcb->pGoingSRB; + for (i = 0; i < pdcb->GoingSRBCnt; i++) { + psrb2 = psrb->pNextSRB; + pcmd = psrb->pcmd; + pcmd->result = DID_RESET << 16; + +/* ReleaseSRB( pDCB, pSRB ); */ + + psrb->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = psrb; + + DC390_UNLOCK_ACB_NI; + pcmd->scsi_done(pcmd); + DC390_LOCK_ACB_NI; + psrb = psrb2; + } + pdcb->GoingSRBCnt = 0;; + pdcb->pGoingSRB = NULL; + pdcb->TagMask = 0; + pdcb = pdcb->pNextDCB; + } while (pdcb != pDCB); } -static void -dc390_ResetSCSIBus( PACB pACB ) +static void dc390_ResetSCSIBus(PACB pACB) { - pACB->ACBFlag |= RESET_DEV; + pACB->ACBFlag |= RESET_DEV; - DC390_write8 (ScsiCmd, RST_DEVICE_CMD); - udelay (250); - DC390_write8 (ScsiCmd, NOP_CMD); + DC390_write8(ScsiCmd, RST_DEVICE_CMD); + udelay(250); + DC390_write8(ScsiCmd, NOP_CMD); - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD); + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); + DC390_write8(DMA_Cmd, DMA_IDLE_CMD); + DC390_write8(ScsiCmd, RST_SCSI_BUS_CMD); - return; + return; } -static void -dc390_ScsiRstDetect( PACB pACB ) +static void dc390_ScsiRstDetect(PACB pACB) { - printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus); - //DEBUG0(printk(KERN_INFO "RST_DETECT,");) + printk("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus); + //DEBUG0(printk(KERN_INFO "RST_DETECT,");) - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - /* Unlock before ? */ - /* delay a second */ - { unsigned int msec = 1*1000; while (--msec) udelay(1000); } - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - - if( pACB->ACBFlag & RESET_DEV ) - pACB->ACBFlag |= RESET_DONE; - else - { - pACB->ACBFlag |= RESET_DETECT; - - dc390_ResetDevParam( pACB ); -/* dc390_DoingSRB_Done( pACB ); ???? */ - dc390_RecoverSRB( pACB ); - pACB->pActiveDCB = NULL; - pACB->ACBFlag = 0; - dc390_DoWaitingSRB( pACB ); - } - return; + DC390_write8(DMA_Cmd, DMA_IDLE_CMD); + /* Unlock before ? */ + /* delay a second */ + { + unsigned int msec = 1 * 1000; + while (--msec) + udelay(1000); + } + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); + + if (pACB->ACBFlag & RESET_DEV) + pACB->ACBFlag |= RESET_DONE; + else { + pACB->ACBFlag |= RESET_DETECT; + + dc390_ResetDevParam(pACB); +/* dc390_DoingSRB_Done( pACB ); ???? */ + dc390_RecoverSRB(pACB); + pACB->pActiveDCB = NULL; + pACB->ACBFlag = 0; + dc390_DoWaitingSRB(pACB); + } + return; } static void __inline__ -dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) + dc390_RequestSense(PACB pACB, PDCB pDCB, PSRB pSRB) { - PSCSICMD pcmd; + PSCSICMD pcmd; - REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\ - pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + REMOVABLEDEBUG(printk(KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n", \ + pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + ) + pSRB->SRBFlag |= AUTO_REQSENSE; + pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0]; + pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4]; + pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount); + pSRB->Segment1[1] = pSRB->TotalXferredLen; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */ + + pcmd = pSRB->pcmd; - pSRB->SRBFlag |= AUTO_REQSENSE; - pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0]; - pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4]; - pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount); - pSRB->Segment1[1] = pSRB->TotalXferredLen; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */ - - pcmd = pSRB->pcmd; - - pSRB->Segmentx.address = (PUCHAR) &(pcmd->sense_buffer); - pSRB->Segmentx.length = sizeof(pcmd->sense_buffer); - pSRB->pSegmentList = &pSRB->Segmentx; - pSRB->SGcount = 1; - pSRB->SGIndex = 0; - - pSRB->CmdBlock[0] = REQUEST_SENSE; - pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; - (USHORT) pSRB->CmdBlock[2] = 0; - (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); - pSRB->ScsiCmdLen = 6; - - pSRB->TotalXferredLen = 0; - pSRB->SGToBeXferLen = 0; - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) - dc390_RewaitSRB( pDCB, pSRB ); + pSRB->Segmentx.address = (PUCHAR) & (pcmd->sense_buffer); + pSRB->Segmentx.length = sizeof(pcmd->sense_buffer); + pSRB->pSegmentList = &pSRB->Segmentx; + pSRB->SGcount = 1; + pSRB->SGIndex = 0; + + pSRB->CmdBlock[0] = REQUEST_SENSE; + pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; + (USHORT) pSRB->CmdBlock[2] = 0; + (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); + pSRB->ScsiCmdLen = 6; + + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if (dc390_StartSCSI(pACB, pDCB, pSRB)) + dc390_RewaitSRB(pDCB, pSRB); } static void __inline__ -dc390_InvalidCmd( PACB pACB ) + dc390_InvalidCmd(PACB pACB) { - if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + if (pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_ + SRB_MSGOUT)) + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); } - diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.3.16/linux/drivers/scsi/sd.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/scsi/sd.c Sat Sep 4 10:48:46 1999 @@ -18,7 +18,7 @@ * Modified by Jirka Hanika geo@ff.cuni.cz to support more * scsi disks using eight major numbers. */ - + #include #ifdef MODULE /* @@ -29,7 +29,7 @@ #define MODULE_FLAG 1 #else #define MODULE_FLAG scsi_loadable_module_flag -#endif /* MODULE */ +#endif /* MODULE */ #include #include @@ -57,9 +57,9 @@ /* * static const char RCSid[] = "$Header:"; */ - + #define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) - + #define SCSI_DISKS_PER_MAJOR 16 #define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8) #define SD_MINOR_NUMBER(i) ((i) & 255) @@ -80,12 +80,12 @@ #define CLUSTERABLE_DEVICE(SC) (SC->host->use_clustering && \ SC->device->type != TYPE_MOD) -struct hd_struct * sd; +struct hd_struct *sd; -Scsi_Disk * rscsi_disks = NULL; -static int * sd_sizes; -static int * sd_blocksizes; -static int * sd_hardsizes; /* Hardware sector size */ +Scsi_Disk *rscsi_disks = NULL; +static int *sd_sizes; +static int *sd_blocksizes; +static int *sd_hardsizes; /* Hardware sector size */ extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long); @@ -94,7 +94,7 @@ static int sd_init_onedisk(int); -static void requeue_sd_request (Scsi_Cmnd * SCpnt); +static void requeue_sd_request(Scsi_Cmnd * SCpnt); static int sd_init(void); static void sd_finish(void); @@ -102,175 +102,171 @@ static int sd_detect(Scsi_Device *); static void sd_detach(Scsi_Device *); -static void sd_devname(unsigned int disknum, char * buffer) +static void sd_devname(unsigned int disknum, char *buffer) { - if( disknum < 26 ) - sprintf(buffer, "sd%c", 'a' + disknum); - else { - unsigned int min1; - unsigned int min2; - /* - * For larger numbers of disks, we need to go to a new - * naming scheme. - */ - min1 = disknum / 26; - min2 = disknum % 26; - sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); - } + if (disknum < 26) + sprintf(buffer, "sd%c", 'a' + disknum); + else { + unsigned int min1; + unsigned int min2; + /* + * For larger numbers of disks, we need to go to a new + * naming scheme. + */ + min1 = disknum / 26; + min2 = disknum % 26; + sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); + } } struct Scsi_Device_Template sd_template = -{ NULL, "disk", "sd", NULL, TYPE_DISK, - SCSI_DISK0_MAJOR, 0, 0, 0, 1, - sd_detect, sd_init, - sd_finish, sd_attach, sd_detach +{NULL, "disk", "sd", NULL, TYPE_DISK, + SCSI_DISK0_MAJOR, 0, 0, 0, 1, + sd_detect, sd_init, + sd_finish, sd_attach, sd_detach }; -static int sd_open(struct inode * inode, struct file * filp) +static int sd_open(struct inode *inode, struct file *filp) { - int target; - target = DEVICE_NR(inode->i_rdev); + int target; + target = DEVICE_NR(inode->i_rdev); - SCSI_LOG_HLQUEUE(1,printk("target=%d, max=%d\n", target, sd_template.dev_max)); + SCSI_LOG_HLQUEUE(1, printk("target=%d, max=%d\n", target, sd_template.dev_max)); - if(target >= sd_template.dev_max || !rscsi_disks[target].device) - return -ENXIO; /* No such device */ - - /* - * If the device is in error recovery, wait until it is done. - * If the device is offline, then disallow any access to it. - */ - if( !scsi_block_when_processing_errors(rscsi_disks[target].device) ) - { - return -ENXIO; - } - - /* - * Make sure that only one process can do a check_change_disk at one time. - * This is also used to lock out further access when the partition table - * is being re-read. - */ - - while (rscsi_disks[target].device->busy) - barrier(); - if(rscsi_disks[target].device->removable) { - check_disk_change(inode->i_rdev); + if (target >= sd_template.dev_max || !rscsi_disks[target].device) + return -ENXIO; /* No such device */ /* - * If the drive is empty, just let the open fail. + * If the device is in error recovery, wait until it is done. + * If the device is offline, then disallow any access to it. */ - if ( !rscsi_disks[target].ready ) - return -ENXIO; + if (!scsi_block_when_processing_errors(rscsi_disks[target].device)) { + return -ENXIO; + } + /* + * Make sure that only one process can do a check_change_disk at one time. + * This is also used to lock out further access when the partition table + * is being re-read. + */ + + while (rscsi_disks[target].device->busy) + barrier(); + if (rscsi_disks[target].device->removable) { + check_disk_change(inode->i_rdev); + /* + * If the drive is empty, just let the open fail. + */ + if (!rscsi_disks[target].ready) + return -ENXIO; + + /* + * Similarly, if the device has the write protect tab set, + * have the open fail if the user expects to be able to write + * to the thing. + */ + if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) + return -EROFS; + } + /* + * It is possible that the disk changing stuff resulted in the device being taken + * offline. If this is the case, report this to the user, and don't pretend that + * the open actually succeeded. + */ + if (!rscsi_disks[target].device->online) { + return -ENXIO; + } /* - * Similarly, if the device has the write protect tab set, - * have the open fail if the user expects to be able to write - * to the thing. + * See if we are requesting a non-existent partition. Do this + * after checking for disk change. */ - if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) ) - return -EROFS; - } - - /* - * It is possible that the disk changing stuff resulted in the device being taken - * offline. If this is the case, report this to the user, and don't pretend that - * the open actually succeeded. - */ - if( !rscsi_disks[target].device->online ) - { - return -ENXIO; - } - - /* - * See if we are requesting a non-existent partition. Do this - * after checking for disk change. - */ - if(sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) - return -ENXIO; - - if(rscsi_disks[target].device->removable) - if(!rscsi_disks[target].device->access_count) - sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); - - rscsi_disks[target].device->access_count++; - if (rscsi_disks[target].device->host->hostt->module) - __MOD_INC_USE_COUNT(rscsi_disks[target].device->host->hostt->module); - if(sd_template.module) - __MOD_INC_USE_COUNT(sd_template.module); - return 0; + if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) + return -ENXIO; + + if (rscsi_disks[target].device->removable) + if (!rscsi_disks[target].device->access_count) + sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); + + rscsi_disks[target].device->access_count++; + if (rscsi_disks[target].device->host->hostt->module) + __MOD_INC_USE_COUNT(rscsi_disks[target].device->host->hostt->module); + if (sd_template.module) + __MOD_INC_USE_COUNT(sd_template.module); + return 0; } -static int sd_release(struct inode * inode, struct file * file) +static int sd_release(struct inode *inode, struct file *file) { - int target; - fsync_dev(inode->i_rdev); - - target = DEVICE_NR(inode->i_rdev); + int target; + fsync_dev(inode->i_rdev); - rscsi_disks[target].device->access_count--; + target = DEVICE_NR(inode->i_rdev); - if(rscsi_disks[target].device->removable) { - if(!rscsi_disks[target].device->access_count) - sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); - } + rscsi_disks[target].device->access_count--; - if(rscsi_disks[target].device->host->hostt->module) - __MOD_DEC_USE_COUNT(rscsi_disks[target].device->host->hostt->module); - if(sd_template.module) - __MOD_DEC_USE_COUNT(sd_template.module); - return 0; + if (rscsi_disks[target].device->removable) { + if (!rscsi_disks[target].device->access_count) + sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); + } + if (rscsi_disks[target].device->host->hostt->module) + __MOD_DEC_USE_COUNT(rscsi_disks[target].device->host->hostt->module); + if (sd_template.module) + __MOD_DEC_USE_COUNT(sd_template.module); + return 0; } static void sd_geninit(struct gendisk *); -static struct file_operations sd_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - sd_ioctl, /* ioctl */ - NULL, /* mmap */ - sd_open, /* open code */ - NULL, /* flush */ - sd_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - check_scsidisk_media_change, /* Disk change */ - fop_revalidate_scsidisk /* revalidate */ +static struct file_operations sd_fops = +{ + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + sd_ioctl, /* ioctl */ + NULL, /* mmap */ + sd_open, /* open code */ + NULL, /* flush */ + sd_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + check_scsidisk_media_change, /* Disk change */ + fop_revalidate_scsidisk /* revalidate */ }; /* - * If we need more than one SCSI disk major (i.e. more than - * 16 SCSI disks), we'll have to kmalloc() more gendisks later. + * If we need more than one SCSI disk major (i.e. more than + * 16 SCSI disks), we'll have to kmalloc() more gendisks later. */ -static struct gendisk sd_gendisk = { - SCSI_DISK0_MAJOR, /* Major number */ - "sd", /* Major name */ - 4, /* Bits to shift to get real from partition */ - 1 << 4, /* Number of partitions per real */ - 0, /* maximum number of real */ - sd_geninit, /* init function */ - NULL, /* hd struct */ - NULL, /* block sizes */ - 0, /* number */ - NULL, /* internal */ - NULL /* next */ -}; +static struct gendisk sd_gendisk = +{ + SCSI_DISK0_MAJOR, /* Major number */ + "sd", /* Major name */ + 4, /* Bits to shift to get real from partition */ + 1 << 4, /* Number of partitions per real */ + 0, /* maximum number of real */ + sd_geninit, /* init function */ + NULL, /* hd struct */ + NULL, /* block sizes */ + 0, /* number */ + NULL, /* internal */ + NULL /* next */ +}; static struct gendisk *sd_gendisks = &sd_gendisk; #define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR] #define LAST_SD_GENDISK sd_gendisks[N_USED_SD_MAJORS - 1] -static void sd_geninit (struct gendisk *ignored) +static void sd_geninit(struct gendisk *ignored) { - int i; + int i; - for (i = 0; i < sd_template.dev_max; ++i) - if(rscsi_disks[i].device) - sd[i << 4].nr_sects = rscsi_disks[i].capacity; + for (i = 0; i < sd_template.dev_max; ++i) + if (rscsi_disks[i].device) + sd[i << 4].nr_sects = rscsi_disks[i].capacity; } /* @@ -279,1208 +275,1169 @@ * will take one of several actions based on success or failure. */ -static void rw_intr (Scsi_Cmnd *SCpnt) +static void rw_intr(Scsi_Cmnd * SCpnt) { - int result = SCpnt->result; - char nbuff[6]; - int this_count = SCpnt->bufflen >> 9; - int good_sectors = (result == 0 ? this_count : 0); - int block_sectors = 1; - - sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff); - - SCSI_LOG_HLCOMPLETE(1,printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff, - SCpnt->host->host_no, - result, - SCpnt->sense_buffer[0], - SCpnt->sense_buffer[2])); - - /* - Handle MEDIUM ERRORs that indicate partial success. Since this is a - relatively rare error condition, no care is taken to avoid unnecessary - additional work such as memcpy's that could be avoided. - */ - - if (driver_byte(result) != 0 && /* An error occurred */ - SCpnt->sense_buffer[0] == 0xF0 && /* Sense data is valid */ - SCpnt->sense_buffer[2] == MEDIUM_ERROR) - { - long error_sector = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | - SCpnt->sense_buffer[6]; - int sector_size = - rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].sector_size; - if (SCpnt->request.bh != NULL) - block_sectors = SCpnt->request.bh->b_size >> 9; - if (sector_size == 1024) - { - error_sector <<= 1; - if (block_sectors < 2) block_sectors = 2; - } - else if (sector_size == 2048) - { - error_sector <<= 2; - if (block_sectors < 4) block_sectors = 4; - } - else if (sector_size == 256) - error_sector >>= 1; - error_sector -= sd[SD_PARTITION(SCpnt->request.rq_dev)].start_sect; - error_sector &= ~ (block_sectors - 1); - good_sectors = error_sector - SCpnt->request.sector; - if (good_sectors < 0 || good_sectors >= this_count) - good_sectors = 0; - } - - /* - * First case : we assume that the command succeeded. One of two things - * will happen here. Either we will be finished, or there will be more - * sectors that we were unable to read last time. - */ - - if (good_sectors > 0) { - - SCSI_LOG_HLCOMPLETE(1,printk("%s : %ld sectors remain.\n", nbuff, - SCpnt->request.nr_sectors)); - SCSI_LOG_HLCOMPLETE(1,printk("use_sg is %d\n ",SCpnt->use_sg)); - - if (SCpnt->use_sg) { - struct scatterlist * sgpnt; - int i; - sgpnt = (struct scatterlist *) SCpnt->buffer; - for(i=0; iuse_sg; i++) { + int result = SCpnt->result; + char nbuff[6]; + int this_count = SCpnt->bufflen >> 9; + int good_sectors = (result == 0 ? this_count : 0); + int block_sectors = 1; + + sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff); + + SCSI_LOG_HLCOMPLETE(1, printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff, + SCpnt->host->host_no, + result, + SCpnt->sense_buffer[0], + SCpnt->sense_buffer[2])); -#if 0 - SCSI_LOG_HLCOMPLETE(3,printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address, - sgpnt[i].length)); -#endif - - if (sgpnt[i].alt_address) { - if (SCpnt->request.cmd == READ) - memcpy(sgpnt[i].alt_address, sgpnt[i].address, - sgpnt[i].length); - scsi_free(sgpnt[i].address, sgpnt[i].length); - } - } + /* + Handle MEDIUM ERRORs that indicate partial success. Since this is a + relatively rare error condition, no care is taken to avoid unnecessary + additional work such as memcpy's that could be avoided. + */ - /* Free list of scatter-gather pointers */ - scsi_free(SCpnt->buffer, SCpnt->sglist_len); - } else { - if (SCpnt->buffer != SCpnt->request.buffer) { - SCSI_LOG_HLCOMPLETE(3,printk("nosg: %p %p %d\n", - SCpnt->request.buffer, SCpnt->buffer, - SCpnt->bufflen)); - - if (SCpnt->request.cmd == READ) - memcpy(SCpnt->request.buffer, SCpnt->buffer, - SCpnt->bufflen); - scsi_free(SCpnt->buffer, SCpnt->bufflen); - } + if (driver_byte(result) != 0 && /* An error occurred */ + SCpnt->sense_buffer[0] == 0xF0 && /* Sense data is valid */ + SCpnt->sense_buffer[2] == MEDIUM_ERROR) { + long error_sector = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | + SCpnt->sense_buffer[6]; + int sector_size = + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].sector_size; + if (SCpnt->request.bh != NULL) + block_sectors = SCpnt->request.bh->b_size >> 9; + if (sector_size == 1024) { + error_sector <<= 1; + if (block_sectors < 2) + block_sectors = 2; + } else if (sector_size == 2048) { + error_sector <<= 2; + if (block_sectors < 4) + block_sectors = 4; + } else if (sector_size == 256) + error_sector >>= 1; + error_sector -= sd[SD_PARTITION(SCpnt->request.rq_dev)].start_sect; + error_sector &= ~(block_sectors - 1); + good_sectors = error_sector - SCpnt->request.sector; + if (good_sectors < 0 || good_sectors >= this_count) + good_sectors = 0; } /* - * If multiple sectors are requested in one buffer, then - * they will have been finished off by the first command. - * If not, then we have a multi-buffer command. + * First case : we assume that the command succeeded. One of two things + * will happen here. Either we will be finished, or there will be more + * sectors that we were unable to read last time. */ - if (SCpnt->request.nr_sectors > this_count) - { - SCpnt->request.errors = 0; - - if (!SCpnt->request.bh) - { - SCSI_LOG_HLCOMPLETE(2,printk("%s : handling page request, no buffer\n", - nbuff)); + if (good_sectors > 0) { + + SCSI_LOG_HLCOMPLETE(1, printk("%s : %ld sectors remain.\n", nbuff, + SCpnt->request.nr_sectors)); + SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg)); + + if (SCpnt->use_sg) { + struct scatterlist *sgpnt; + int i; + sgpnt = (struct scatterlist *) SCpnt->buffer; + for (i = 0; i < SCpnt->use_sg; i++) { + +#if 0 + SCSI_LOG_HLCOMPLETE(3, printk(":%p %p %d\n", sgpnt[i].alt_address, sgpnt[i].address, + sgpnt[i].length)); +#endif + + if (sgpnt[i].alt_address) { + if (SCpnt->request.cmd == READ) + memcpy(sgpnt[i].alt_address, sgpnt[i].address, + sgpnt[i].length); + scsi_free(sgpnt[i].address, sgpnt[i].length); + } + } + + /* Free list of scatter-gather pointers */ + scsi_free(SCpnt->buffer, SCpnt->sglist_len); + } else { + if (SCpnt->buffer != SCpnt->request.buffer) { + SCSI_LOG_HLCOMPLETE(3, printk("nosg: %p %p %d\n", + SCpnt->request.buffer, SCpnt->buffer, + SCpnt->bufflen)); + + if (SCpnt->request.cmd == READ) + memcpy(SCpnt->request.buffer, SCpnt->buffer, + SCpnt->bufflen); + scsi_free(SCpnt->buffer, SCpnt->bufflen); + } + } /* - * The SCpnt->request.nr_sectors field is always done in - * 512 byte sectors, even if this really isn't the case. + * If multiple sectors are requested in one buffer, then + * they will have been finished off by the first command. + * If not, then we have a multi-buffer command. */ - panic("sd.c: linked page request (%lx %x)", - SCpnt->request.sector, this_count); - } - } - SCpnt = end_scsi_request(SCpnt, 1, good_sectors); - if (result == 0) - { - requeue_sd_request(SCpnt); - return; - } - } - - if (good_sectors == 0) { - - /* Free up any indirection buffers we allocated for DMA purposes. */ - if (SCpnt->use_sg) { - struct scatterlist * sgpnt; - int i; - sgpnt = (struct scatterlist *) SCpnt->buffer; - for(i=0; iuse_sg; i++) { - SCSI_LOG_HLCOMPLETE(3,printk("err: %p %p %d\n", - SCpnt->request.buffer, SCpnt->buffer, - SCpnt->bufflen)); - if (sgpnt[i].alt_address) { - scsi_free(sgpnt[i].address, sgpnt[i].length); - } - } - scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ - } else { - SCSI_LOG_HLCOMPLETE(2,printk("nosgerr: %p %p %d\n", - SCpnt->request.buffer, SCpnt->buffer, - SCpnt->bufflen)); - if (SCpnt->buffer != SCpnt->request.buffer) - scsi_free(SCpnt->buffer, SCpnt->bufflen); - } - } - - /* - * Now, if we were good little boys and girls, Santa left us a request - * sense buffer. We can extract information from this, so we - * can choose a block to remap, etc. - */ + if (SCpnt->request.nr_sectors > this_count) { + SCpnt->request.errors = 0; - if (driver_byte(result) != 0) { - if (suggestion(result) == SUGGEST_REMAP) { -#ifdef REMAP - /* - * Not yet implemented. A read will fail after being remapped, - * a write will call the strategy routine again. - */ - if rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].remap - { - result = 0; - } - else -#endif + if (!SCpnt->request.bh) { + SCSI_LOG_HLCOMPLETE(2, printk("%s : handling page request, no buffer\n", + nbuff)); + + /* + * The SCpnt->request.nr_sectors field is always done in + * 512 byte sectors, even if this really isn't the case. + */ + panic("sd.c: linked page request (%lx %x)", + SCpnt->request.sector, this_count); + } + } + SCpnt = end_scsi_request(SCpnt, 1, good_sectors); + if (result == 0) { + requeue_sd_request(SCpnt); + return; + } } + if (good_sectors == 0) { - if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) { - if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) { - if(rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->removable) { - /* detected disc change. set a bit and quietly refuse - * further access. - */ - rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1; - SCpnt = end_scsi_request(SCpnt, 0, this_count); - requeue_sd_request(SCpnt); - return; - } - else - { - /* - * Must have been a power glitch, or a bus reset. - * Could not have been a media change, so we just retry - * the request and see what happens. - */ - requeue_sd_request(SCpnt); - return; - } - } + /* Free up any indirection buffers we allocated for DMA purposes. */ + if (SCpnt->use_sg) { + struct scatterlist *sgpnt; + int i; + sgpnt = (struct scatterlist *) SCpnt->buffer; + for (i = 0; i < SCpnt->use_sg; i++) { + SCSI_LOG_HLCOMPLETE(3, printk("err: %p %p %d\n", + SCpnt->request.buffer, SCpnt->buffer, + SCpnt->bufflen)); + if (sgpnt[i].alt_address) { + scsi_free(sgpnt[i].address, sgpnt[i].length); + } + } + scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ + } else { + SCSI_LOG_HLCOMPLETE(2, printk("nosgerr: %p %p %d\n", + SCpnt->request.buffer, SCpnt->buffer, + SCpnt->bufflen)); + if (SCpnt->buffer != SCpnt->request.buffer) + scsi_free(SCpnt->buffer, SCpnt->bufflen); + } } - - - /* If we had an ILLEGAL REQUEST returned, then we may have - * performed an unsupported command. The only thing this should be - * would be a ten byte read where only a six byte read was supported. - * Also, on a system where READ CAPACITY failed, we have have read - * past the end of the disk. + /* + * Now, if we were good little boys and girls, Santa left us a request + * sense buffer. We can extract information from this, so we + * can choose a block to remap, etc. */ - if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) { - if (rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten) { - rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten = 0; + if (driver_byte(result) != 0) { + if (suggestion(result) == SUGGEST_REMAP) { +#ifdef REMAP + /* + * Not yet implemented. A read will fail after being remapped, + * a write will call the strategy routine again. + */ + if rscsi_disks + [DEVICE_NR(SCpnt->request.rq_dev)].remap + { + result = 0; + } +#endif + } + if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) { + if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) { + if (rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->removable) { + /* detected disc change. set a bit and quietly refuse + * further access. + */ + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1; + SCpnt = end_scsi_request(SCpnt, 0, this_count); + requeue_sd_request(SCpnt); + return; + } else { + /* + * Must have been a power glitch, or a bus reset. + * Could not have been a media change, so we just retry + * the request and see what happens. + */ + requeue_sd_request(SCpnt); + return; + } + } + } + /* If we had an ILLEGAL REQUEST returned, then we may have + * performed an unsupported command. The only thing this should be + * would be a ten byte read where only a six byte read was supported. + * Also, on a system where READ CAPACITY failed, we have have read + * past the end of the disk. + */ + + if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) { + if (rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten) { + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten = 0; + requeue_sd_request(SCpnt); + result = 0; + } else { + /* ???? */ + } + } + if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) { + printk("scsi%d: MEDIUM ERROR on channel %d, id %d, lun %d, CDB: ", + SCpnt->host->host_no, (int) SCpnt->channel, + (int) SCpnt->target, (int) SCpnt->lun); + print_command(SCpnt->cmnd); + print_sense("sd", SCpnt); + SCpnt = end_scsi_request(SCpnt, 0, block_sectors); + requeue_sd_request(SCpnt); + return; + } + } /* driver byte != 0 */ + if (result) { + printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n", + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no, + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->channel, + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->id, + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, result); + + if (driver_byte(result) & DRIVER_SENSE) + print_sense("sd", SCpnt); + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); requeue_sd_request(SCpnt); - result = 0; - } else { - /* ???? */ - } - } - - if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) { - printk("scsi%d: MEDIUM ERROR on channel %d, id %d, lun %d, CDB: ", - SCpnt->host->host_no, (int) SCpnt->channel, - (int) SCpnt->target, (int) SCpnt->lun); - print_command(SCpnt->cmnd); - print_sense("sd", SCpnt); - SCpnt = end_scsi_request(SCpnt, 0, block_sectors); - requeue_sd_request(SCpnt); - return; - } - } /* driver byte != 0 */ - if (result) { - printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n", - rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no, - rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->channel, - rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->id, - rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, result); - - if (driver_byte(result) & DRIVER_SENSE) - print_sense("sd", SCpnt); - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); - requeue_sd_request(SCpnt); - return; - } + return; + } } - /* * requeue_sd_request() is the request handler function for the sd driver. * Its function in life is to take block device requests, and translate * them to SCSI commands. */ -static void do_sd_request (void) +static void do_sd_request(void) { - Scsi_Cmnd * SCpnt = NULL; - Scsi_Device * SDev; - struct request * req = NULL; - int flag = 0; - - while (1==1){ - if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { - return; - } - - INIT_SCSI_REQUEST; - SDev = rscsi_disks[CURRENT_DEV].device; - - /* - * If the host for this device is in error recovery mode, don't - * do anything at all here. When the host leaves error recovery - * mode, it will automatically restart things and start queueing - * commands again. - */ - if( SDev->host->in_recovery ) - { - return; - } - - /* - * I am not sure where the best place to do this is. We need - * to hook in a place where we are likely to come if in user - * space. - */ - if( SDev->was_reset ) - { - /* - * We need to relock the door, but we might - * be in an interrupt handler. Only do this - * from user space, since we do not want to - * sleep from an interrupt. FIXME(eric) - do this - * from the kernel error handling thred. - */ - if( SDev->removable && !in_interrupt() ) - { - spin_unlock_irq(&io_request_lock); /* FIXME!!!! */ - scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); - /* scsi_ioctl may allow CURRENT to change, so start over. */ - SDev->was_reset = 0; - spin_lock_irq(&io_request_lock); /* FIXME!!!! */ - continue; - } - SDev->was_reset = 0; - } - - /* We have to be careful here. scsi_allocate_device will get a free pointer, - * but there is no guarantee that it is queueable. In normal usage, - * we want to call this, because other types of devices may have the - * host all tied up, and we want to make sure that we have at least - * one request pending for this type of device. We can also come - * through here while servicing an interrupt, because of the need to - * start another command. If we call scsi_allocate_device more than once, - * then the system can wedge if the command is not queueable. The - * scsi_request_queueable function is safe because it checks to make sure - * that the host is able to take another command before it returns - * a pointer. - */ - - if (flag++ == 0) - SCpnt = scsi_allocate_device(&CURRENT, - rscsi_disks[CURRENT_DEV].device, 0); - else SCpnt = NULL; + Scsi_Cmnd *SCpnt = NULL; + Scsi_Device *SDev; + struct request *req = NULL; + int flag = 0; + + while (1 == 1) { + if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { + return; + } + INIT_SCSI_REQUEST; + SDev = rscsi_disks[CURRENT_DEV].device; - /* - * The following restore_flags leads to latency problems. FIXME. - * Using a "sti()" gets rid of the latency problems but causes - * race conditions and crashes. - */ + /* + * If the host for this device is in error recovery mode, don't + * do anything at all here. When the host leaves error recovery + * mode, it will automatically restart things and start queueing + * commands again. + */ + if (SDev->host->in_recovery) { + return; + } + /* + * I am not sure where the best place to do this is. We need + * to hook in a place where we are likely to come if in user + * space. + */ + if (SDev->was_reset) { + /* + * We need to relock the door, but we might + * be in an interrupt handler. Only do this + * from user space, since we do not want to + * sleep from an interrupt. FIXME(eric) - do this + * from the kernel error handling thred. + */ + if (SDev->removable && !in_interrupt()) { + spin_unlock_irq(&io_request_lock); /* FIXME!!!! */ + scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); + /* scsi_ioctl may allow CURRENT to change, so start over. */ + SDev->was_reset = 0; + spin_lock_irq(&io_request_lock); /* FIXME!!!! */ + continue; + } + SDev->was_reset = 0; + } + /* We have to be careful here. scsi_allocate_device will get a free pointer, + * but there is no guarantee that it is queueable. In normal usage, + * we want to call this, because other types of devices may have the + * host all tied up, and we want to make sure that we have at least + * one request pending for this type of device. We can also come + * through here while servicing an interrupt, because of the need to + * start another command. If we call scsi_allocate_device more than once, + * then the system can wedge if the command is not queueable. The + * scsi_request_queueable function is safe because it checks to make sure + * that the host is able to take another command before it returns + * a pointer. + */ - /* This is a performance enhancement. We dig down into the request - * list and try to find a queueable request (i.e. device not busy, - * and host able to accept another command. If we find one, then we - * queue it. This can make a big difference on systems with more than - * one disk drive. We want to have the interrupts off when monkeying - * with the request list, because otherwise the kernel might try to - * slip in a request in between somewhere. - * - * FIXME(eric) - this doesn't belong at this level. The device code in - * ll_rw_blk.c should know how to dig down into the device queue to - * figure out what it can deal with, and what it can't. Consider - * possibility of pulling entire queue down into scsi layer. - */ - if (!SCpnt && sd_template.nr_dev > 1){ - struct request *req1; - req1 = NULL; - req = CURRENT; - while(req){ - SCpnt = scsi_request_queueable(req, - rscsi_disks[DEVICE_NR(req->rq_dev)].device); - if(SCpnt) break; - req1 = req; - req = req->next; - } - if (SCpnt && req->rq_status == RQ_INACTIVE) { - if (req == CURRENT) - CURRENT = CURRENT->next; + if (flag++ == 0) + SCpnt = scsi_allocate_device(&CURRENT, + rscsi_disks[CURRENT_DEV].device, 0); else - req1->next = req->next; - } - } + SCpnt = NULL; - if (!SCpnt) return; /* Could not find anything to do */ + /* + * The following restore_flags leads to latency problems. FIXME. + * Using a "sti()" gets rid of the latency problems but causes + * race conditions and crashes. + */ - /* Queue command */ - requeue_sd_request(SCpnt); - } /* While */ + /* This is a performance enhancement. We dig down into the request + * list and try to find a queueable request (i.e. device not busy, + * and host able to accept another command. If we find one, then we + * queue it. This can make a big difference on systems with more than + * one disk drive. We want to have the interrupts off when monkeying + * with the request list, because otherwise the kernel might try to + * slip in a request in between somewhere. + * + * FIXME(eric) - this doesn't belong at this level. The device code in + * ll_rw_blk.c should know how to dig down into the device queue to + * figure out what it can deal with, and what it can't. Consider + * possibility of pulling entire queue down into scsi layer. + */ + if (!SCpnt && sd_template.nr_dev > 1) { + struct request *req1; + req1 = NULL; + req = CURRENT; + while (req) { + SCpnt = scsi_request_queueable(req, + rscsi_disks[DEVICE_NR(req->rq_dev)].device); + if (SCpnt) + break; + req1 = req; + req = req->next; + } + if (SCpnt && req->rq_status == RQ_INACTIVE) { + if (req == CURRENT) + CURRENT = CURRENT->next; + else + req1->next = req->next; + } + } + if (!SCpnt) + return; /* Could not find anything to do */ + + /* Queue command */ + requeue_sd_request(SCpnt); + } /* While */ } -static void requeue_sd_request (Scsi_Cmnd * SCpnt) +static void requeue_sd_request(Scsi_Cmnd * SCpnt) { - int dev, devm, block, this_count; - unsigned char cmd[10]; - char nbuff[6]; - int bounce_size, contiguous; - int max_sg; - struct buffer_head * bh, *bhp; - char * buff, *bounce_buffer; - - repeat: - - if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) { - do_sd_request(); - return; - } + int dev, devm, block, this_count; + unsigned char cmd[10]; + char nbuff[6]; + int bounce_size, contiguous; + int max_sg; + struct buffer_head *bh, *bhp; + char *buff, *bounce_buffer; + +repeat: + + if (!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) { + do_sd_request(); + return; + } + devm = SD_PARTITION(SCpnt->request.rq_dev); + dev = DEVICE_NR(SCpnt->request.rq_dev); - devm = SD_PARTITION(SCpnt->request.rq_dev); - dev = DEVICE_NR(SCpnt->request.rq_dev); + block = SCpnt->request.sector; + this_count = 0; - block = SCpnt->request.sector; - this_count = 0; + SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = %d, block = %d\n", devm, block)); - SCSI_LOG_HLQUEUE(1,printk("Doing sd request, dev = %d, block = %d\n", devm, block)); - - if (devm >= (sd_template.dev_max << 4) || - !rscsi_disks[dev].device || - !rscsi_disks[dev].device->online || - block + SCpnt->request.nr_sectors > sd[devm].nr_sects) - { - SCSI_LOG_HLQUEUE(2,printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors)); - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); - SCSI_LOG_HLQUEUE(2,printk("Retry with 0x%p\n", SCpnt)); - goto repeat; - } + if (devm >= (sd_template.dev_max << 4) || + !rscsi_disks[dev].device || + !rscsi_disks[dev].device->online || + block + SCpnt->request.nr_sectors > sd[devm].nr_sects) { + SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors)); + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); + goto repeat; + } + block += sd[devm].start_sect; - block += sd[devm].start_sect; + if (rscsi_disks[dev].device->changed) { + /* + * quietly refuse to do anything to a changed disc until the changed + * bit has been reset + */ + /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */ + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + } + sd_devname(devm >> 4, nbuff); + SCSI_LOG_HLQUEUE(2, printk("%s : real dev = /dev/%d, block = %d\n", + nbuff, dev, block)); - if (rscsi_disks[dev].device->changed) - { /* - * quietly refuse to do anything to a changed disc until the changed - * bit has been reset + * If we have a 1K hardware sectorsize, prevent access to single + * 512 byte sectors. In theory we could handle this - in fact + * the scsi cdrom driver must be able to handle this because + * we typically use 1K blocksizes, and cdroms typically have + * 2K hardware sectorsizes. Of course, things are simpler + * with the cdrom, since it is read-only. For performance + * reasons, the filesystems should be able to handle this + * and not force the scsi disk driver to use bounce buffers + * for this. */ - /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */ - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); - goto repeat; - } - - sd_devname(devm >> 4, nbuff); - SCSI_LOG_HLQUEUE(2,printk("%s : real dev = /dev/%d, block = %d\n", - nbuff, dev, block)); - - /* - * If we have a 1K hardware sectorsize, prevent access to single - * 512 byte sectors. In theory we could handle this - in fact - * the scsi cdrom driver must be able to handle this because - * we typically use 1K blocksizes, and cdroms typically have - * 2K hardware sectorsizes. Of course, things are simpler - * with the cdrom, since it is read-only. For performance - * reasons, the filesystems should be able to handle this - * and not force the scsi disk driver to use bounce buffers - * for this. - */ - if (rscsi_disks[dev].sector_size == 1024) - if((block & 1) || (SCpnt->request.nr_sectors & 1)) { - printk("sd.c:Bad block number/count requested"); - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); - goto repeat; - } - - if (rscsi_disks[dev].sector_size == 2048) - if((block & 3) || (SCpnt->request.nr_sectors & 3)) { - printk("sd.c:Bad block number/count requested"); - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); - goto repeat; - } - if (rscsi_disks[dev].sector_size == 4096) - if((block & 7) || (SCpnt->request.nr_sectors & 7)) { - printk("sd.cBad block number/count requested"); - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); - goto repeat; - } - - switch (SCpnt->request.cmd) - { - case WRITE : - if (!rscsi_disks[dev].device->writeable) - { - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); - goto repeat; - } - cmd[0] = WRITE_6; - break; - case READ : - cmd[0] = READ_6; - break; - default : - panic ("Unknown sd command %d\n", SCpnt->request.cmd); - } - - SCpnt->this_count = 0; - - /* If the host adapter can deal with very large scatter-gather - * requests, it is a waste of time to cluster - */ - contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 :1); - bounce_buffer = NULL; - bounce_size = (SCpnt->request.nr_sectors << 9); - - /* First see if we need a bounce buffer for this request. If we do, make - * sure that we can allocate a buffer. Do not waste space by allocating - * a bounce buffer if we are straddling the 16Mb line - */ - if (contiguous && SCpnt->request.bh && - virt_to_phys(SCpnt->request.bh->b_data) - + (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD - && SCpnt->host->unchecked_isa_dma) { - if(virt_to_phys(SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD) - bounce_buffer = (char *) scsi_malloc(bounce_size); - if(!bounce_buffer) contiguous = 0; - } - - if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext) - for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp, - bhp = bhp->b_reqnext) { - if(!CONTIGUOUS_BUFFERS(bh,bhp)) { - if(bounce_buffer) scsi_free(bounce_buffer, bounce_size); - contiguous = 0; + if (rscsi_disks[dev].sector_size == 1024) + if ((block & 1) || (SCpnt->request.nr_sectors & 1)) { + printk("sd.c:Bad block number/count requested"); + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + } + if (rscsi_disks[dev].sector_size == 2048) + if ((block & 3) || (SCpnt->request.nr_sectors & 3)) { + printk("sd.c:Bad block number/count requested"); + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + } + if (rscsi_disks[dev].sector_size == 4096) + if ((block & 7) || (SCpnt->request.nr_sectors & 7)) { + printk("sd.cBad block number/count requested"); + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + } + switch (SCpnt->request.cmd) { + case WRITE: + if (!rscsi_disks[dev].device->writeable) { + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + } + cmd[0] = WRITE_6; + break; + case READ: + cmd[0] = READ_6; break; - } + default: + panic("Unknown sd command %d\n", SCpnt->request.cmd); } - if (!SCpnt->request.bh || contiguous) { - /* case of page request (i.e. raw device), or unlinked buffer */ - this_count = SCpnt->request.nr_sectors; - buff = SCpnt->request.buffer; - SCpnt->use_sg = 0; - - } else if (SCpnt->host->sg_tablesize == 0 || - (scsi_need_isa_buffer && scsi_dma_free_sectors <= 10)) { - - /* Case of host adapter that cannot scatter-gather. We also - * come here if we are running low on DMA buffer memory. We set - * a threshold higher than that we would need for this request so - * we leave room for other requests. Even though we would not need - * it all, we need to be conservative, because if we run low enough - * we have no choice but to panic. + SCpnt->this_count = 0; + + /* If the host adapter can deal with very large scatter-gather + * requests, it is a waste of time to cluster + */ + contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 : 1); + bounce_buffer = NULL; + bounce_size = (SCpnt->request.nr_sectors << 9); + + /* First see if we need a bounce buffer for this request. If we do, make + * sure that we can allocate a buffer. Do not waste space by allocating + * a bounce buffer if we are straddling the 16Mb line */ - if (SCpnt->host->sg_tablesize != 0 && - scsi_need_isa_buffer && - scsi_dma_free_sectors <= 10) - printk("Warning: SCSI DMA buffer space running low. Using non scatter-gather I/O.\n"); - - this_count = SCpnt->request.current_nr_sectors; - buff = SCpnt->request.buffer; - SCpnt->use_sg = 0; - - } else { - - /* Scatter-gather capable host adapter */ - struct scatterlist * sgpnt; - int count, this_count_max; - int counted; + if (contiguous && SCpnt->request.bh && + virt_to_phys(SCpnt->request.bh->b_data) + + (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD + && SCpnt->host->unchecked_isa_dma) { + if (virt_to_phys(SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD) + bounce_buffer = (char *) scsi_malloc(bounce_size); + if (!bounce_buffer) + contiguous = 0; + } + if (contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext) + for (bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp, + bhp = bhp->b_reqnext) { + if (!CONTIGUOUS_BUFFERS(bh, bhp)) { + if (bounce_buffer) + scsi_free(bounce_buffer, bounce_size); + contiguous = 0; + break; + } + } + if (!SCpnt->request.bh || contiguous) { + + /* case of page request (i.e. raw device), or unlinked buffer */ + this_count = SCpnt->request.nr_sectors; + buff = SCpnt->request.buffer; + SCpnt->use_sg = 0; + + } else if (SCpnt->host->sg_tablesize == 0 || + (scsi_need_isa_buffer && scsi_dma_free_sectors <= 10)) { + + /* Case of host adapter that cannot scatter-gather. We also + * come here if we are running low on DMA buffer memory. We set + * a threshold higher than that we would need for this request so + * we leave room for other requests. Even though we would not need + * it all, we need to be conservative, because if we run low enough + * we have no choice but to panic. + */ + if (SCpnt->host->sg_tablesize != 0 && + scsi_need_isa_buffer && + scsi_dma_free_sectors <= 10) + printk("Warning: SCSI DMA buffer space running low. Using non scatter-gather I/O.\n"); + + this_count = SCpnt->request.current_nr_sectors; + buff = SCpnt->request.buffer; + SCpnt->use_sg = 0; - bh = SCpnt->request.bh; - this_count = 0; - this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff); - count = 0; - bhp = NULL; - while(bh) { - if ((this_count + (bh->b_size >> 9)) > this_count_max) break; - if(!bhp || !CONTIGUOUS_BUFFERS(bhp,bh) || - !CLUSTERABLE_DEVICE(SCpnt) || - (SCpnt->host->unchecked_isa_dma && - virt_to_phys(bh->b_data-1) == ISA_DMA_THRESHOLD)) { - if (count < SCpnt->host->sg_tablesize) count++; - else break; - } - this_count += (bh->b_size >> 9); - bhp = bh; - bh = bh->b_reqnext; - } -#if 0 - if(SCpnt->host->unchecked_isa_dma && - virt_to_phys(SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--; -#endif - SCpnt->use_sg = count; /* Number of chains */ - /* scsi_malloc can only allocate in chunks of 512 bytes */ - count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511; - - SCpnt->sglist_len = count; - max_sg = count / sizeof(struct scatterlist); - if(SCpnt->host->sg_tablesize < max_sg) - max_sg = SCpnt->host->sg_tablesize; - sgpnt = (struct scatterlist * ) scsi_malloc(count); - if (!sgpnt) { - printk("Warning - running *really* short on DMA buffers\n"); - SCpnt->use_sg = 0; /* No memory left - bail out */ - this_count = SCpnt->request.current_nr_sectors; - buff = SCpnt->request.buffer; } else { - memset(sgpnt, 0, count); /* Zero so it is easy to fill, but only - * if memory is available - */ - buff = (char *) sgpnt; - counted = 0; - for(count = 0, bh = SCpnt->request.bh, bhp = bh->b_reqnext; - count < SCpnt->use_sg && bh; - count++, bh = bhp) { - - bhp = bh->b_reqnext; - - if(!sgpnt[count].address) sgpnt[count].address = bh->b_data; - sgpnt[count].length += bh->b_size; - counted += bh->b_size >> 9; - - if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 > - ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) && - !sgpnt[count].alt_address) { - sgpnt[count].alt_address = sgpnt[count].address; - /* We try to avoid exhausting the DMA pool, since it is - * easier to control usage here. In other places we might - * have a more pressing need, and we would be screwed if - * we ran out */ - if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 10) { - sgpnt[count].address = NULL; - } else { - sgpnt[count].address = - (char *) scsi_malloc(sgpnt[count].length); - } - /* If we start running low on DMA buffers, we abort the - * scatter-gather operation, and free all of the memory - * we have allocated. We want to ensure that all scsi - * operations are able to do at least a non-scatter/gather - * operation */ - if(sgpnt[count].address == NULL){ /* Out of dma memory */ -#if 0 - printk("Warning: Running low on SCSI DMA buffers"); - /* Try switching back to a non s-g operation. */ - while(--count >= 0){ - if(sgpnt[count].alt_address) - scsi_free(sgpnt[count].address, - sgpnt[count].length); + + /* Scatter-gather capable host adapter */ + struct scatterlist *sgpnt; + int count, this_count_max; + int counted; + + bh = SCpnt->request.bh; + this_count = 0; + this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff); + count = 0; + bhp = NULL; + while (bh) { + if ((this_count + (bh->b_size >> 9)) > this_count_max) + break; + if (!bhp || !CONTIGUOUS_BUFFERS(bhp, bh) || + !CLUSTERABLE_DEVICE(SCpnt) || + (SCpnt->host->unchecked_isa_dma && + virt_to_phys(bh->b_data - 1) == ISA_DMA_THRESHOLD)) { + if (count < SCpnt->host->sg_tablesize) + count++; + else + break; } + this_count += (bh->b_size >> 9); + bhp = bh; + bh = bh->b_reqnext; + } +#if 0 + if (SCpnt->host->unchecked_isa_dma && + virt_to_phys(SCpnt->request.bh->b_data - 1) == ISA_DMA_THRESHOLD) + count--; +#endif + SCpnt->use_sg = count; /* Number of chains */ + /* scsi_malloc can only allocate in chunks of 512 bytes */ + count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511; + + SCpnt->sglist_len = count; + max_sg = count / sizeof(struct scatterlist); + if (SCpnt->host->sg_tablesize < max_sg) + max_sg = SCpnt->host->sg_tablesize; + sgpnt = (struct scatterlist *) scsi_malloc(count); + if (!sgpnt) { + printk("Warning - running *really* short on DMA buffers\n"); + SCpnt->use_sg = 0; /* No memory left - bail out */ this_count = SCpnt->request.current_nr_sectors; buff = SCpnt->request.buffer; - SCpnt->use_sg = 0; - scsi_free(sgpnt, SCpnt->sglist_len); + } else { + memset(sgpnt, 0, count); /* Zero so it is easy to fill, but only + * if memory is available + */ + buff = (char *) sgpnt; + counted = 0; + for (count = 0, bh = SCpnt->request.bh, bhp = bh->b_reqnext; + count < SCpnt->use_sg && bh; + count++, bh = bhp) { + + bhp = bh->b_reqnext; + + if (!sgpnt[count].address) + sgpnt[count].address = bh->b_data; + sgpnt[count].length += bh->b_size; + counted += bh->b_size >> 9; + + if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 > + ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) && + !sgpnt[count].alt_address) { + sgpnt[count].alt_address = sgpnt[count].address; + /* We try to avoid exhausting the DMA pool, since it is + * easier to control usage here. In other places we might + * have a more pressing need, and we would be screwed if + * we ran out */ + if (scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 10) { + sgpnt[count].address = NULL; + } else { + sgpnt[count].address = + (char *) scsi_malloc(sgpnt[count].length); + } + /* If we start running low on DMA buffers, we abort the + * scatter-gather operation, and free all of the memory + * we have allocated. We want to ensure that all scsi + * operations are able to do at least a non-scatter/gather + * operation */ + if (sgpnt[count].address == NULL) { /* Out of dma memory */ +#if 0 + printk("Warning: Running low on SCSI DMA buffers"); + /* Try switching back to a non s-g operation. */ + while (--count >= 0) { + if (sgpnt[count].alt_address) + scsi_free(sgpnt[count].address, + sgpnt[count].length); + } + this_count = SCpnt->request.current_nr_sectors; + buff = SCpnt->request.buffer; + SCpnt->use_sg = 0; + scsi_free(sgpnt, SCpnt->sglist_len); #endif - SCpnt->use_sg = count; - this_count = counted -= bh->b_size >> 9; - break; - } + SCpnt->use_sg = count; + this_count = counted -= bh->b_size >> 9; + break; + } + } + /* Only cluster buffers if we know that we can supply DMA + * buffers large enough to satisfy the request. Do not cluster + * a new request if this would mean that we suddenly need to + * start using DMA bounce buffers */ + if (bhp && CONTIGUOUS_BUFFERS(bh, bhp) + && CLUSTERABLE_DEVICE(SCpnt)) { + char *tmp; + + if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length + + bhp->b_size - 1 > ISA_DMA_THRESHOLD && + (SCpnt->host->unchecked_isa_dma) && + !sgpnt[count].alt_address) + continue; + + if (!sgpnt[count].alt_address) { + count--; + continue; + } + if (scsi_dma_free_sectors > 10) + tmp = (char *) scsi_malloc(sgpnt[count].length + + bhp->b_size); + else { + tmp = NULL; + max_sg = SCpnt->use_sg; + } + if (tmp) { + scsi_free(sgpnt[count].address, sgpnt[count].length); + sgpnt[count].address = tmp; + count--; + continue; + } + /* If we are allowed another sg chain, then increment + * counter so we can insert it. Otherwise we will end + up truncating */ + + if (SCpnt->use_sg < max_sg) + SCpnt->use_sg++; + } /* contiguous buffers */ + } /* for loop */ + + /* This is actually how many we are going to transfer */ + this_count = counted; + + if (count < SCpnt->use_sg || SCpnt->use_sg + > SCpnt->host->sg_tablesize) { + bh = SCpnt->request.bh; + printk("Use sg, count %d %x %d\n", + SCpnt->use_sg, count, scsi_dma_free_sectors); + printk("maxsg = %x, counted = %d this_count = %d\n", + max_sg, counted, this_count); + while (bh) { + printk("[%p %x] ", bh->b_data, bh->b_size); + bh = bh->b_reqnext; + } + if (SCpnt->use_sg < 16) + for (count = 0; count < SCpnt->use_sg; count++) + printk("{%d:%p %p %d} ", count, + sgpnt[count].address, + sgpnt[count].alt_address, + sgpnt[count].length); + panic("Ooops"); + } + if (SCpnt->request.cmd == WRITE) + for (count = 0; count < SCpnt->use_sg; count++) + if (sgpnt[count].alt_address) + memcpy(sgpnt[count].address, sgpnt[count].alt_address, + sgpnt[count].length); + } /* Able to malloc sgpnt */ + } /* Host adapter capable of scatter-gather */ + + /* Now handle the possibility of DMA to addresses > 16Mb */ + + if (SCpnt->use_sg == 0) { + if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && + (SCpnt->host->unchecked_isa_dma)) { + if (bounce_buffer) + buff = bounce_buffer; + else + buff = (char *) scsi_malloc(this_count << 9); + if (buff == NULL) { /* Try backing off a bit if we are low on mem */ + this_count = SCpnt->request.current_nr_sectors; + buff = (char *) scsi_malloc(this_count << 9); + if (!buff) + panic("Ran out of DMA buffers."); + } + if (SCpnt->request.cmd == WRITE) + memcpy(buff, (char *) SCpnt->request.buffer, this_count << 9); } + } + SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", + nbuff, + (SCpnt->request.cmd == WRITE) ? "writing" : "reading", + this_count, SCpnt->request.nr_sectors)); + + cmd[1] = (SCpnt->lun << 5) & 0xe0; + + if (rscsi_disks[dev].sector_size == 4096) { + if (block & 7) + panic("sd.c:Bad block number requested"); + if (this_count & 7) + panic("sd.c:Bad block number requested"); + block = block >> 3; + this_count = block >> 3; + } + if (rscsi_disks[dev].sector_size == 2048) { + if (block & 3) + panic("sd.c:Bad block number requested"); + if (this_count & 3) + panic("sd.c:Bad block number requested"); + block = block >> 2; + this_count = this_count >> 2; + } + if (rscsi_disks[dev].sector_size == 1024) { + if (block & 1) + panic("sd.c:Bad block number requested"); + if (this_count & 1) + panic("sd.c:Bad block number requested"); + block = block >> 1; + this_count = this_count >> 1; + } + if (rscsi_disks[dev].sector_size == 256) { + block = block << 1; + this_count = this_count << 1; + } + if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten) { + if (this_count > 0xffff) + this_count = 0xffff; + + cmd[0] += READ_10 - READ_6; + cmd[2] = (unsigned char) (block >> 24) & 0xff; + cmd[3] = (unsigned char) (block >> 16) & 0xff; + cmd[4] = (unsigned char) (block >> 8) & 0xff; + cmd[5] = (unsigned char) block & 0xff; + cmd[6] = cmd[9] = 0; + cmd[7] = (unsigned char) (this_count >> 8) & 0xff; + cmd[8] = (unsigned char) this_count & 0xff; + } else { + if (this_count > 0xff) + this_count = 0xff; - /* Only cluster buffers if we know that we can supply DMA - * buffers large enough to satisfy the request. Do not cluster - * a new request if this would mean that we suddenly need to - * start using DMA bounce buffers */ - if(bhp && CONTIGUOUS_BUFFERS(bh,bhp) - && CLUSTERABLE_DEVICE(SCpnt)) { - char * tmp; - - if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length + - bhp->b_size - 1 > ISA_DMA_THRESHOLD && - (SCpnt->host->unchecked_isa_dma) && - !sgpnt[count].alt_address) continue; - - if(!sgpnt[count].alt_address) {count--; continue; } - if(scsi_dma_free_sectors > 10) - tmp = (char *) scsi_malloc(sgpnt[count].length - + bhp->b_size); - else { - tmp = NULL; - max_sg = SCpnt->use_sg; - } - if(tmp){ - scsi_free(sgpnt[count].address, sgpnt[count].length); - sgpnt[count].address = tmp; - count--; - continue; - } - - /* If we are allowed another sg chain, then increment - * counter so we can insert it. Otherwise we will end - up truncating */ - - if (SCpnt->use_sg < max_sg) SCpnt->use_sg++; - } /* contiguous buffers */ - } /* for loop */ + cmd[1] |= (unsigned char) ((block >> 16) & 0x1f); + cmd[2] = (unsigned char) ((block >> 8) & 0xff); + cmd[3] = (unsigned char) block & 0xff; + cmd[4] = (unsigned char) this_count; + cmd[5] = 0; + } - /* This is actually how many we are going to transfer */ - this_count = counted; + /* + * We shouldn't disconnect in the middle of a sector, so with a dumb + * host adapter, it's safe to assume that we can at least transfer + * this many bytes between each connect / disconnect. + */ - if(count < SCpnt->use_sg || SCpnt->use_sg - > SCpnt->host->sg_tablesize){ - bh = SCpnt->request.bh; - printk("Use sg, count %d %x %d\n", - SCpnt->use_sg, count, scsi_dma_free_sectors); - printk("maxsg = %x, counted = %d this_count = %d\n", - max_sg, counted, this_count); - while(bh){ - printk("[%p %x] ", bh->b_data, bh->b_size); - bh = bh->b_reqnext; - } - if(SCpnt->use_sg < 16) - for(count=0; countuse_sg; count++) - printk("{%d:%p %p %d} ", count, - sgpnt[count].address, - sgpnt[count].alt_address, - sgpnt[count].length); - panic("Ooops"); - } - - if (SCpnt->request.cmd == WRITE) - for(count=0; countuse_sg; count++) - if(sgpnt[count].alt_address) - memcpy(sgpnt[count].address, sgpnt[count].alt_address, - sgpnt[count].length); - } /* Able to malloc sgpnt */ - } /* Host adapter capable of scatter-gather */ - - /* Now handle the possibility of DMA to addresses > 16Mb */ - - if(SCpnt->use_sg == 0){ - if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && - (SCpnt->host->unchecked_isa_dma)) { - if(bounce_buffer) - buff = bounce_buffer; - else - buff = (char *) scsi_malloc(this_count << 9); - if(buff == NULL) { /* Try backing off a bit if we are low on mem*/ - this_count = SCpnt->request.current_nr_sectors; - buff = (char *) scsi_malloc(this_count << 9); - if(!buff) panic("Ran out of DMA buffers."); - } - if (SCpnt->request.cmd == WRITE) - memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9); - } - } - SCSI_LOG_HLQUEUE(2,printk("%s : %s %d/%ld 512 byte blocks.\n", - nbuff, - (SCpnt->request.cmd == WRITE) ? "writing" : "reading", - this_count, SCpnt->request.nr_sectors)); - - cmd[1] = (SCpnt->lun << 5) & 0xe0; - - if (rscsi_disks[dev].sector_size == 4096){ - if(block & 7) panic("sd.c:Bad block number requested"); - if(this_count & 7) panic("sd.c:Bad block number requested"); - block = block >> 3; - this_count = block >> 3; - } - - if (rscsi_disks[dev].sector_size == 2048){ - if(block & 3) panic("sd.c:Bad block number requested"); - if(this_count & 3) panic("sd.c:Bad block number requested"); - block = block >> 2; - this_count = this_count >> 2; - } - - if (rscsi_disks[dev].sector_size == 1024){ - if(block & 1) panic("sd.c:Bad block number requested"); - if(this_count & 1) panic("sd.c:Bad block number requested"); - block = block >> 1; - this_count = this_count >> 1; - } - - if (rscsi_disks[dev].sector_size == 256){ - block = block << 1; - this_count = this_count << 1; - } - - if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten) - { - if (this_count > 0xffff) - this_count = 0xffff; - - cmd[0] += READ_10 - READ_6 ; - cmd[2] = (unsigned char) (block >> 24) & 0xff; - cmd[3] = (unsigned char) (block >> 16) & 0xff; - cmd[4] = (unsigned char) (block >> 8) & 0xff; - cmd[5] = (unsigned char) block & 0xff; - cmd[6] = cmd[9] = 0; - cmd[7] = (unsigned char) (this_count >> 8) & 0xff; - cmd[8] = (unsigned char) this_count & 0xff; - } - else - { - if (this_count > 0xff) - this_count = 0xff; - - cmd[1] |= (unsigned char) ((block >> 16) & 0x1f); - cmd[2] = (unsigned char) ((block >> 8) & 0xff); - cmd[3] = (unsigned char) block & 0xff; - cmd[4] = (unsigned char) this_count; - cmd[5] = 0; - } - - /* - * We shouldn't disconnect in the middle of a sector, so with a dumb - * host adapter, it's safe to assume that we can at least transfer - * this many bytes between each connect / disconnect. - */ - - SCpnt->transfersize = rscsi_disks[dev].sector_size; - SCpnt->underflow = this_count << 9; - SCpnt->cmd_len = 0; - scsi_do_cmd (SCpnt, (void *) cmd, buff, - this_count * rscsi_disks[dev].sector_size, - rw_intr, - (SCpnt->device->type == TYPE_DISK ? - SD_TIMEOUT : SD_MOD_TIMEOUT), - MAX_RETRIES); + SCpnt->transfersize = rscsi_disks[dev].sector_size; + SCpnt->underflow = this_count << 9; + SCpnt->cmd_len = 0; + scsi_do_cmd(SCpnt, (void *) cmd, buff, + this_count * rscsi_disks[dev].sector_size, + rw_intr, + (SCpnt->device->type == TYPE_DISK ? + SD_TIMEOUT : SD_MOD_TIMEOUT), + MAX_RETRIES); } -static int check_scsidisk_media_change(kdev_t full_dev){ - int retval; - int target; - struct inode inode; - int flag = 0; - - target = DEVICE_NR(full_dev); - - if (target >= sd_template.dev_max || - !rscsi_disks[target].device) { - printk("SCSI disk request error: invalid device.\n"); - return 0; - } +static int check_scsidisk_media_change(kdev_t full_dev) +{ + int retval; + int target; + struct inode inode; + int flag = 0; + + target = DEVICE_NR(full_dev); + + if (target >= sd_template.dev_max || + !rscsi_disks[target].device) { + printk("SCSI disk request error: invalid device.\n"); + return 0; + } + if (!rscsi_disks[target].device->removable) + return 0; - if(!rscsi_disks[target].device->removable) return 0; + /* + * If the device is offline, don't send any commands - just pretend as if + * the command failed. If the device ever comes back online, we can deal with + * it then. It is only because of unrecoverable errors that we would ever + * take a device offline in the first place. + */ + if (rscsi_disks[target].device->online == FALSE) { + rscsi_disks[target].ready = 0; + rscsi_disks[target].device->changed = 1; + return 1; /* This will force a flush, if called from + * check_disk_change */ + } + inode.i_rdev = full_dev; /* This is all we really need here */ + + /* Using Start/Stop enables differentiation between drive with + * no cartridge loaded - NOT READY, drive with changed cartridge - + * UNIT ATTENTION, or with same cartridge - GOOD STATUS. + * This also handles drives that auto spin down. eg iomega jaz 1GB + * as this will spin up the drive. + */ + retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_START_UNIT, 0); - /* - * If the device is offline, don't send any commands - just pretend as if - * the command failed. If the device ever comes back online, we can deal with - * it then. It is only because of unrecoverable errors that we would ever - * take a device offline in the first place. - */ - if( rscsi_disks[target].device->online == FALSE ) - { - rscsi_disks[target].ready = 0; - rscsi_disks[target].device->changed = 1; - return 1; /* This will force a flush, if called from - * check_disk_change */ - } - - inode.i_rdev = full_dev; /* This is all we really need here */ - - /* Using Start/Stop enables differentiation between drive with - * no cartridge loaded - NOT READY, drive with changed cartridge - - * UNIT ATTENTION, or with same cartridge - GOOD STATUS. - * This also handles drives that auto spin down. eg iomega jaz 1GB - * as this will spin up the drive. - */ - retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_START_UNIT, 0); - - if(retval){ /* Unable to test, unit probably not ready. This usually - * means there is no disc in the drive. Mark as changed, - * and we will figure it out later once the drive is - * available again. */ - - rscsi_disks[target].ready = 0; - rscsi_disks[target].device->changed = 1; - return 1; /* This will force a flush, if called from - * check_disk_change */ - } - - /* - * for removable scsi disk ( FLOPTICAL ) we have to recognise the - * presence of disk in the drive. This is kept in the Scsi_Disk - * struct and tested at open ! Daniel Roche ( dan@lectra.fr ) - */ - - rscsi_disks[target].ready = 1; /* FLOPTICAL */ - - retval = rscsi_disks[target].device->changed; - if(!flag) rscsi_disks[target].device->changed = 0; - return retval; + if (retval) { /* Unable to test, unit probably not ready. This usually + * means there is no disc in the drive. Mark as changed, + * and we will figure it out later once the drive is + * available again. */ + + rscsi_disks[target].ready = 0; + rscsi_disks[target].device->changed = 1; + return 1; /* This will force a flush, if called from + * check_disk_change */ + } + /* + * for removable scsi disk ( FLOPTICAL ) we have to recognise the + * presence of disk in the drive. This is kept in the Scsi_Disk + * struct and tested at open ! Daniel Roche ( dan@lectra.fr ) + */ + + rscsi_disks[target].ready = 1; /* FLOPTICAL */ + + retval = rscsi_disks[target].device->changed; + if (!flag) + rscsi_disks[target].device->changed = 0; + return retval; } -static void sd_init_done (Scsi_Cmnd * SCpnt) +static void sd_init_done(Scsi_Cmnd * SCpnt) { - struct request * req; + struct request *req; - req = &SCpnt->request; - req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ + req = &SCpnt->request; + req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ - if (req->sem != NULL) { - up(req->sem); - } + if (req->sem != NULL) { + up(req->sem); + } } - static int sd_init_onedisk(int i) { - unsigned char cmd[10]; - char nbuff[6]; - unsigned char *buffer; - unsigned long spintime; - int the_result, retries; - Scsi_Cmnd * SCpnt; - - /* - * Get the name of the disk, in case we need to log it somewhere. - */ - sd_devname(i, nbuff); - - /* - * If the device is offline, don't try and read capacity or any of the other - * nicities. - */ - if( rscsi_disks[i].device->online == FALSE ) - { - return i; - } - - spin_lock_irq(&io_request_lock); - - /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is - * considered a fatal error, and many devices report such an error - * just after a scsi bus reset. - */ - - SCpnt = scsi_allocate_device(NULL, rscsi_disks[i].device, 1); - buffer = (unsigned char *) scsi_malloc(512); - - spintime = 0; - - /* Spin up drives, as required. Only do this at boot time */ - /* Spinup needs to be done for module loads too. */ - do{ - retries = 0; - while(retries < 3) - { - cmd[0] = TEST_UNIT_READY; + unsigned char cmd[10]; + char nbuff[6]; + unsigned char *buffer; + unsigned long spintime; + int the_result, retries; + Scsi_Cmnd *SCpnt; + + /* + * Get the name of the disk, in case we need to log it somewhere. + */ + sd_devname(i, nbuff); + + /* + * If the device is offline, don't try and read capacity or any of the other + * nicities. + */ + if (rscsi_disks[i].device->online == FALSE) { + return i; + } + spin_lock_irq(&io_request_lock); + + /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is + * considered a fatal error, and many devices report such an error + * just after a scsi bus reset. + */ + + SCpnt = scsi_allocate_device(NULL, rscsi_disks[i].device, 1); + buffer = (unsigned char *) scsi_malloc(512); + + spintime = 0; + + /* Spin up drives, as required. Only do this at boot time */ + /* Spinup needs to be done for module loads too. */ + do { + retries = 0; + while (retries < 3) { + cmd[0] = TEST_UNIT_READY; + cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + memset((void *) &cmd[2], 0, 8); + SCpnt->cmd_len = 0; + SCpnt->sense_buffer[0] = 0; + SCpnt->sense_buffer[2] = 0; + + { + DECLARE_MUTEX_LOCKED(sem); + /* Mark as really busy again */ + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.sem = &sem; + scsi_do_cmd(SCpnt, + (void *) cmd, (void *) buffer, + 512, sd_init_done, SD_TIMEOUT, + MAX_RETRIES); + spin_unlock_irq(&io_request_lock); + down(&sem); + spin_lock_irq(&io_request_lock); + SCpnt->request.sem = NULL; + } + + the_result = SCpnt->result; + retries++; + if (the_result == 0 + || SCpnt->sense_buffer[2] != UNIT_ATTENTION) + break; + } + + /* Look for non-removable devices that return NOT_READY. + * Issue command to spin up drive for these cases. */ + if (the_result && !rscsi_disks[i].device->removable && + SCpnt->sense_buffer[2] == NOT_READY) { + unsigned long time1; + if (!spintime) { + printk("%s: Spinning up disk...", nbuff); + cmd[0] = START_STOP; + cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[1] |= 1; /* Return immediately */ + memset((void *) &cmd[2], 0, 8); + cmd[4] = 1; /* Start spin cycle */ + SCpnt->cmd_len = 0; + SCpnt->sense_buffer[0] = 0; + SCpnt->sense_buffer[2] = 0; + + { + DECLARE_MUTEX_LOCKED(sem); + /* Mark as really busy again */ + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.sem = &sem; + scsi_do_cmd(SCpnt, + (void *) cmd, (void *) buffer, + 512, sd_init_done, SD_TIMEOUT, + MAX_RETRIES); + spin_unlock_irq(&io_request_lock); + down(&sem); + spin_lock_irq(&io_request_lock); + SCpnt->request.sem = NULL; + } + + spintime = jiffies; + } + time1 = jiffies + HZ; + spin_unlock_irq(&io_request_lock); + while (jiffies < time1); /* Wait 1 second for next try */ + printk("."); + spin_lock_irq(&io_request_lock); + } + } while (the_result && spintime && spintime + 100 * HZ > jiffies); + if (spintime) { + if (the_result) + printk("not responding...\n"); + else + printk("ready\n"); + } + retries = 3; + do { + cmd[0] = READ_CAPACITY; cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; - memset ((void *) &cmd[2], 0, 8); + memset((void *) &cmd[2], 0, 8); + memset((void *) buffer, 0, 8); SCpnt->cmd_len = 0; SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[2] = 0; { - DECLARE_MUTEX_LOCKED(sem); - /* Mark as really busy again */ - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = &sem; - scsi_do_cmd (SCpnt, - (void *) cmd, (void *) buffer, - 512, sd_init_done, SD_TIMEOUT, - MAX_RETRIES); - spin_unlock_irq(&io_request_lock); - down(&sem); - spin_lock_irq(&io_request_lock); - SCpnt->request.sem = NULL; - } - - the_result = SCpnt->result; - retries++; - if( the_result == 0 - || SCpnt->sense_buffer[2] != UNIT_ATTENTION) - break; - } - - /* Look for non-removable devices that return NOT_READY. - * Issue command to spin up drive for these cases. */ - if(the_result && !rscsi_disks[i].device->removable && - SCpnt->sense_buffer[2] == NOT_READY) { - unsigned long time1; - if(!spintime){ - printk( "%s: Spinning up disk...", nbuff ); - cmd[0] = START_STOP; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; - cmd[1] |= 1; /* Return immediately */ - memset ((void *) &cmd[2], 0, 8); - cmd[4] = 1; /* Start spin cycle */ - SCpnt->cmd_len = 0; - SCpnt->sense_buffer[0] = 0; - SCpnt->sense_buffer[2] = 0; - - { - DECLARE_MUTEX_LOCKED(sem); + DECLARE_MUTEX_LOCKED(sem); /* Mark as really busy again */ SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = &sem; - scsi_do_cmd (SCpnt, - (void *) cmd, (void *) buffer, - 512, sd_init_done, SD_TIMEOUT, - MAX_RETRIES); + SCpnt->request.sem = &sem; + scsi_do_cmd(SCpnt, + (void *) cmd, (void *) buffer, + 8, sd_init_done, SD_TIMEOUT, + MAX_RETRIES); spin_unlock_irq(&io_request_lock); - down(&sem); + down(&sem); /* sleep until it is ready */ spin_lock_irq(&io_request_lock); - SCpnt->request.sem = NULL; - } - - spintime = jiffies; + SCpnt->request.sem = NULL; } - time1 = jiffies + HZ; - spin_unlock_irq(&io_request_lock); - while(jiffies < time1); /* Wait 1 second for next try */ - printk( "." ); - spin_lock_irq(&io_request_lock); - } - } while(the_result && spintime && spintime+100*HZ > jiffies); - if (spintime) { - if (the_result) - printk( "not responding...\n" ); - else - printk( "ready\n" ); - } + the_result = SCpnt->result; + retries--; - retries = 3; - do { - cmd[0] = READ_CAPACITY; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; - memset ((void *) &cmd[2], 0, 8); - memset ((void *) buffer, 0, 8); - SCpnt->cmd_len = 0; - SCpnt->sense_buffer[0] = 0; - SCpnt->sense_buffer[2] = 0; + } while (the_result && retries); - { - DECLARE_MUTEX_LOCKED(sem); - /* Mark as really busy again */ - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = &sem; - scsi_do_cmd (SCpnt, - (void *) cmd, (void *) buffer, - 8, sd_init_done, SD_TIMEOUT, - MAX_RETRIES); - spin_unlock_irq(&io_request_lock); - down(&sem); /* sleep until it is ready */ - spin_lock_irq(&io_request_lock); - SCpnt->request.sem = NULL; - } - - the_result = SCpnt->result; - retries--; - - } while(the_result && retries); - - /* - * The SCSI standard says: - * "READ CAPACITY is necessary for self configuring software" - * While not mandatory, support of READ CAPACITY is strongly encouraged. - * We used to die if we couldn't successfully do a READ CAPACITY. - * But, now we go on about our way. The side effects of this are - * - * 1. We can't know block size with certainty. I have said "512 bytes - * is it" as this is most common. - * - * 2. Recovery from when some one attempts to read past the end of the - * raw device will be slower. - */ - - if (the_result) - { - printk ("%s : READ CAPACITY failed.\n" - "%s : status = %x, message = %02x, host = %d, driver = %02x \n", - nbuff, nbuff, - status_byte(the_result), - msg_byte(the_result), - host_byte(the_result), - driver_byte(the_result) - ); - if (driver_byte(the_result) & DRIVER_SENSE) - printk("%s : extended sense code = %1x \n", - nbuff, SCpnt->sense_buffer[2] & 0xf); - else - printk("%s : sense not available. \n", nbuff); - - printk("%s : block size assumed to be 512 bytes, disk size 1GB. \n", - nbuff); - rscsi_disks[i].capacity = 0x1fffff; - rscsi_disks[i].sector_size = 512; - - /* Set dirty bit for removable devices if not ready - sometimes drives - * will not report this properly. */ - if(rscsi_disks[i].device->removable && - SCpnt->sense_buffer[2] == NOT_READY) - rscsi_disks[i].device->changed = 1; - - } - else - { /* - * FLOPTICAL , if read_capa is ok , drive is assumed to be ready + * The SCSI standard says: + * "READ CAPACITY is necessary for self configuring software" + * While not mandatory, support of READ CAPACITY is strongly encouraged. + * We used to die if we couldn't successfully do a READ CAPACITY. + * But, now we go on about our way. The side effects of this are + * + * 1. We can't know block size with certainty. I have said "512 bytes + * is it" as this is most common. + * + * 2. Recovery from when some one attempts to read past the end of the + * raw device will be slower. */ - rscsi_disks[i].ready = 1; - rscsi_disks[i].capacity = 1 + ((buffer[0] << 24) | - (buffer[1] << 16) | - (buffer[2] << 8) | - buffer[3]); - - rscsi_disks[i].sector_size = (buffer[4] << 24) | - (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; - - if (rscsi_disks[i].sector_size == 0) { - rscsi_disks[i].sector_size = 512; - printk("%s : sector size 0 reported, assuming 512.\n", nbuff); - } + if (the_result) { + printk("%s : READ CAPACITY failed.\n" + "%s : status = %x, message = %02x, host = %d, driver = %02x \n", + nbuff, nbuff, + status_byte(the_result), + msg_byte(the_result), + host_byte(the_result), + driver_byte(the_result) + ); + if (driver_byte(the_result) & DRIVER_SENSE) + printk("%s : extended sense code = %1x \n", + nbuff, SCpnt->sense_buffer[2] & 0xf); + else + printk("%s : sense not available. \n", nbuff); + printk("%s : block size assumed to be 512 bytes, disk size 1GB. \n", + nbuff); + rscsi_disks[i].capacity = 0x1fffff; + rscsi_disks[i].sector_size = 512; + + /* Set dirty bit for removable devices if not ready - sometimes drives + * will not report this properly. */ + if (rscsi_disks[i].device->removable && + SCpnt->sense_buffer[2] == NOT_READY) + rscsi_disks[i].device->changed = 1; - if (rscsi_disks[i].sector_size != 512 && - rscsi_disks[i].sector_size != 1024 && - rscsi_disks[i].sector_size != 2048 && - rscsi_disks[i].sector_size != 4096 && - rscsi_disks[i].sector_size != 256) - { - printk ("%s : unsupported sector size %d.\n", - nbuff, rscsi_disks[i].sector_size); - if(rscsi_disks[i].device->removable){ - rscsi_disks[i].capacity = 0; - } else { - printk ("scsi : deleting disk entry.\n"); - rscsi_disks[i].device = NULL; - sd_template.nr_dev--; - SD_GENDISK(i).nr_real--; - - /* Wake up a process waiting for device */ - wake_up(&SCpnt->device->device_wait); - scsi_release_command(SCpnt); - SCpnt = NULL; - - return i; - } + } else { + /* + * FLOPTICAL , if read_capa is ok , drive is assumed to be ready + */ + rscsi_disks[i].ready = 1; + + rscsi_disks[i].capacity = 1 + ((buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + buffer[3]); + + rscsi_disks[i].sector_size = (buffer[4] << 24) | + (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; + + if (rscsi_disks[i].sector_size == 0) { + rscsi_disks[i].sector_size = 512; + printk("%s : sector size 0 reported, assuming 512.\n", nbuff); + } + if (rscsi_disks[i].sector_size != 512 && + rscsi_disks[i].sector_size != 1024 && + rscsi_disks[i].sector_size != 2048 && + rscsi_disks[i].sector_size != 4096 && + rscsi_disks[i].sector_size != 256) { + printk("%s : unsupported sector size %d.\n", + nbuff, rscsi_disks[i].sector_size); + if (rscsi_disks[i].device->removable) { + rscsi_disks[i].capacity = 0; + } else { + printk("scsi : deleting disk entry.\n"); + rscsi_disks[i].device = NULL; + sd_template.nr_dev--; + SD_GENDISK(i).nr_real--; + + /* Wake up a process waiting for device */ + wake_up(&SCpnt->device->device_wait); + scsi_release_command(SCpnt); + SCpnt = NULL; + + return i; + } + } + if (rscsi_disks[i].sector_size == 2048) { + int m; + + /* + * We must fix the sd_blocksizes and sd_hardsizes + * to allow us to read the partition tables. + * The disk reading code does not allow for reading + * of partial sectors. + */ + for (m = i << 4; m < ((i + 1) << 4); m++) { + sd_blocksizes[m] = 2048; + } + } { + /* + * The msdos fs needs to know the hardware sector size + * So I have created this table. See ll_rw_blk.c + * Jacques Gelinas (Jacques@solucorp.qc.ca) + */ + int m, mb; + int sz_quot, sz_rem; + int hard_sector = rscsi_disks[i].sector_size; + /* There are 16 minors allocated for each major device */ + for (m = i << 4; m < ((i + 1) << 4); m++) { + sd_hardsizes[m] = hard_sector; + } + mb = rscsi_disks[i].capacity / 1024 * hard_sector / 1024; + /* sz = div(m/100, 10); this seems to not be in the libr */ + m = (mb + 50) / 100; + sz_quot = m / 10; + sz_rem = m - (10 * sz_quot); + printk("SCSI device %s: hdwr sector= %d bytes." + " Sectors= %d [%d MB] [%d.%1d GB]\n", + nbuff, hard_sector, rscsi_disks[i].capacity, + mb, sz_quot, sz_rem); + } + if (rscsi_disks[i].sector_size == 4096) + rscsi_disks[i].capacity <<= 3; + if (rscsi_disks[i].sector_size == 2048) + rscsi_disks[i].capacity <<= 2; /* Change into 512 byte sectors */ + if (rscsi_disks[i].sector_size == 1024) + rscsi_disks[i].capacity <<= 1; /* Change into 512 byte sectors */ + if (rscsi_disks[i].sector_size == 256) + rscsi_disks[i].capacity >>= 1; /* Change into 512 byte sectors */ } - if( rscsi_disks[i].sector_size == 2048 ) - { - int m; - - /* - * We must fix the sd_blocksizes and sd_hardsizes - * to allow us to read the partition tables. - * The disk reading code does not allow for reading - * of partial sectors. - */ - for (m=i<<4; m<((i+1)<<4); m++) - { - sd_blocksizes[m] = 2048; - } - } - { - /* - * The msdos fs needs to know the hardware sector size - * So I have created this table. See ll_rw_blk.c - * Jacques Gelinas (Jacques@solucorp.qc.ca) - */ - int m, mb; - int sz_quot, sz_rem; - int hard_sector = rscsi_disks[i].sector_size; - /* There are 16 minors allocated for each major device */ - for (m=i<<4; m<((i+1)<<4); m++){ - sd_hardsizes[m] = hard_sector; - } - mb = rscsi_disks[i].capacity / 1024 * hard_sector / 1024; - /* sz = div(m/100, 10); this seems to not be in the libr */ - m = (mb + 50) / 100; - sz_quot = m / 10; - sz_rem = m - (10 * sz_quot); - printk ("SCSI device %s: hdwr sector= %d bytes." - " Sectors= %d [%d MB] [%d.%1d GB]\n", - nbuff, hard_sector, rscsi_disks[i].capacity, - mb, sz_quot, sz_rem); - } - if(rscsi_disks[i].sector_size == 4096) - rscsi_disks[i].capacity <<= 3; - if(rscsi_disks[i].sector_size == 2048) - rscsi_disks[i].capacity <<= 2; /* Change into 512 byte sectors */ - if(rscsi_disks[i].sector_size == 1024) - rscsi_disks[i].capacity <<= 1; /* Change into 512 byte sectors */ - if(rscsi_disks[i].sector_size == 256) - rscsi_disks[i].capacity >>= 1; /* Change into 512 byte sectors */ - } - - - /* - * Unless otherwise specified, this is not write protected. - */ - rscsi_disks[i].write_prot = 0; - if ( rscsi_disks[i].device->removable && rscsi_disks[i].ready ) { - /* FLOPTICAL */ /* - * for removable scsi disk ( FLOPTICAL ) we have to recognise - * the Write Protect Flag. This flag is kept in the Scsi_Disk struct - * and tested at open ! - * Daniel Roche ( dan@lectra.fr ) + * Unless otherwise specified, this is not write protected. */ + rscsi_disks[i].write_prot = 0; + if (rscsi_disks[i].device->removable && rscsi_disks[i].ready) { + /* FLOPTICAL */ - memset ((void *) &cmd[0], 0, 8); - cmd[0] = MODE_SENSE; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; - cmd[2] = 1; /* page code 1 ?? */ - cmd[4] = 12; - SCpnt->cmd_len = 0; - SCpnt->sense_buffer[0] = 0; - SCpnt->sense_buffer[2] = 0; + /* + * for removable scsi disk ( FLOPTICAL ) we have to recognise + * the Write Protect Flag. This flag is kept in the Scsi_Disk struct + * and tested at open ! + * Daniel Roche ( dan@lectra.fr ) + */ - /* same code as READCAPA !! */ - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy again */ - SCpnt->request.sem = &sem; - scsi_do_cmd (SCpnt, - (void *) cmd, (void *) buffer, - 512, sd_init_done, SD_TIMEOUT, - MAX_RETRIES); - spin_unlock_irq(&io_request_lock); - down(&sem); - spin_lock_irq(&io_request_lock); - SCpnt->request.sem = NULL; - } - - the_result = SCpnt->result; - - if ( the_result ) { - printk ("%s: test WP failed, assume Write Protected\n",nbuff); - rscsi_disks[i].write_prot = 1; - } else { - rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0); - printk ("%s: Write Protect is %s\n",nbuff, - rscsi_disks[i].write_prot ? "on" : "off"); - } - - } /* check for write protect */ - - /* Wake up a process waiting for device */ - wake_up(&SCpnt->device->device_wait); - scsi_release_command(SCpnt); - SCpnt = NULL; - - rscsi_disks[i].ten = 1; - rscsi_disks[i].remap = 1; - scsi_free(buffer, 512); - spin_unlock_irq(&io_request_lock); - return i; + memset((void *) &cmd[0], 0, 8); + cmd[0] = MODE_SENSE; + cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[2] = 1; /* page code 1 ?? */ + cmd[4] = 12; + SCpnt->cmd_len = 0; + SCpnt->sense_buffer[0] = 0; + SCpnt->sense_buffer[2] = 0; + + /* same code as READCAPA !! */ + { + DECLARE_MUTEX_LOCKED(sem); + SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy again */ + SCpnt->request.sem = &sem; + scsi_do_cmd(SCpnt, + (void *) cmd, (void *) buffer, + 512, sd_init_done, SD_TIMEOUT, + MAX_RETRIES); + spin_unlock_irq(&io_request_lock); + down(&sem); + spin_lock_irq(&io_request_lock); + SCpnt->request.sem = NULL; + } + + the_result = SCpnt->result; + + if (the_result) { + printk("%s: test WP failed, assume Write Protected\n", nbuff); + rscsi_disks[i].write_prot = 1; + } else { + rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0); + printk("%s: Write Protect is %s\n", nbuff, + rscsi_disks[i].write_prot ? "on" : "off"); + } + + } /* check for write protect */ + /* Wake up a process waiting for device */ + wake_up(&SCpnt->device->device_wait); + scsi_release_command(SCpnt); + SCpnt = NULL; + + rscsi_disks[i].ten = 1; + rscsi_disks[i].remap = 1; + scsi_free(buffer, 512); + spin_unlock_irq(&io_request_lock); + return i; } /* @@ -1492,171 +1449,170 @@ static int sd_init() { - int i; + int i; - if (sd_template.dev_noticed == 0) return 0; + if (sd_template.dev_noticed == 0) + return 0; - if (!rscsi_disks) - sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS; + if (!rscsi_disks) + sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS; - if(sd_template.dev_max > N_SD_MAJORS * SCSI_DISKS_PER_MAJOR ) - sd_template.dev_max = N_SD_MAJORS * SCSI_DISKS_PER_MAJOR; + if (sd_template.dev_max > N_SD_MAJORS * SCSI_DISKS_PER_MAJOR) + sd_template.dev_max = N_SD_MAJORS * SCSI_DISKS_PER_MAJOR; - if(!sd_registered) { - for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) { - if (register_blkdev(SD_MAJOR(i),"sd",&sd_fops)) { - printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i)); - return 1; - } + if (!sd_registered) { + for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) { + if (register_blkdev(SD_MAJOR(i), "sd", &sd_fops)) { + printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i)); + return 1; + } + } + sd_registered++; } - sd_registered++; - } - - /* We do not support attaching loadable devices yet. */ - if(rscsi_disks) return 0; - - rscsi_disks = (Scsi_Disk *) - scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC); - memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk)); - - /* for every (necessary) major: */ - sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int)); - - sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - - for(i=0; i < sd_template.dev_max << 4; i++) { - sd_blocksizes[i] = 1024; - sd_hardsizes[i] = 512; - } - - for (i=0; i < N_USED_SD_MAJORS; i++) { - blksize_size[SD_MAJOR(i)] = sd_blocksizes + i * (SCSI_DISKS_PER_MAJOR << 4); - hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4); - } - sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) * - sizeof(struct hd_struct), - GFP_ATOMIC); - - if (N_USED_SD_MAJORS > 1) - sd_gendisks = (struct gendisk *) - kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC); - for (i=0; i < N_USED_SD_MAJORS; i++) { - sd_gendisks[i].major = SD_MAJOR(i); - sd_gendisks[i].major_name = "sd"; - sd_gendisks[i].minor_shift = 4; - sd_gendisks[i].max_p = 1 << 4; - sd_gendisks[i].max_nr = SCSI_DISKS_PER_MAJOR; - sd_gendisks[i].init = sd_geninit; - sd_gendisks[i].part = sd + (i * SCSI_DISKS_PER_MAJOR << 4); - sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4); - sd_gendisks[i].nr_real = 0; - sd_gendisks[i].next = sd_gendisks + i + 1; - sd_gendisks[i].real_devices = - (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR); - } - - LAST_SD_GENDISK.max_nr = - (sd_template.dev_max -1 ) % SCSI_DISKS_PER_MAJOR + 1; - LAST_SD_GENDISK.next = NULL; - return 0; + /* We do not support attaching loadable devices yet. */ + if (rscsi_disks) + return 0; + + rscsi_disks = (Scsi_Disk *) + scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC); + memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk)); + + /* for every (necessary) major: */ + sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); + memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int)); + + sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); + sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); + + for (i = 0; i < sd_template.dev_max << 4; i++) { + sd_blocksizes[i] = 1024; + sd_hardsizes[i] = 512; + } + + for (i = 0; i < N_USED_SD_MAJORS; i++) { + blksize_size[SD_MAJOR(i)] = sd_blocksizes + i * (SCSI_DISKS_PER_MAJOR << 4); + hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4); + } + sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) * + sizeof(struct hd_struct), + GFP_ATOMIC); + + if (N_USED_SD_MAJORS > 1) + sd_gendisks = (struct gendisk *) + kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC); + for (i = 0; i < N_USED_SD_MAJORS; i++) { + sd_gendisks[i].major = SD_MAJOR(i); + sd_gendisks[i].major_name = "sd"; + sd_gendisks[i].minor_shift = 4; + sd_gendisks[i].max_p = 1 << 4; + sd_gendisks[i].max_nr = SCSI_DISKS_PER_MAJOR; + sd_gendisks[i].init = sd_geninit; + sd_gendisks[i].part = sd + (i * SCSI_DISKS_PER_MAJOR << 4); + sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4); + sd_gendisks[i].nr_real = 0; + sd_gendisks[i].next = sd_gendisks + i + 1; + sd_gendisks[i].real_devices = + (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR); + } + + LAST_SD_GENDISK.max_nr = + (sd_template.dev_max - 1) % SCSI_DISKS_PER_MAJOR + 1; + LAST_SD_GENDISK.next = NULL; + return 0; } /* * sd_get_queue() returns the queue which corresponds to a given device. */ -static struct request **sd_get_queue (kdev_t dev) +static struct request **sd_get_queue(kdev_t dev) { return &blk_dev[MAJOR_NR].current_request; } - static void sd_finish() { - struct gendisk *gendisk; - int i; + struct gendisk *gendisk; + int i; - for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) { - /* FIXME: After 2.2 we should implement multiple sd queues */ - blk_dev[SD_MAJOR(i)].request_fn = DEVICE_REQUEST; - if (i) blk_dev[SD_MAJOR(i)].queue = sd_get_queue; - } - - for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next) - if (gendisk == sd_gendisks) - break; - if (gendisk == NULL) - { - LAST_SD_GENDISK.next = gendisk_head; - gendisk_head = sd_gendisks; - } - - for (i = 0; i < sd_template.dev_max; ++i) - if (!rscsi_disks[i].capacity && - rscsi_disks[i].device) - { - if (MODULE_FLAG - && !rscsi_disks[i].has_part_table) { - sd_sizes[i << 4] = rscsi_disks[i].capacity; - /* revalidate does sd_init_onedisk via MAYBE_REINIT*/ - revalidate_scsidisk(MKDEV_SD(i), 0); - } - else - i=sd_init_onedisk(i); - rscsi_disks[i].has_part_table = 1; - } - - /* If our host adapter is capable of scatter-gather, then we increase - * the read-ahead to 60 blocks (120 sectors). If not, we use - * a two block (4 sector) read ahead. We can only respect this with the - * granularity of every 16 disks (one device major). - */ - for (i=0; i < N_USED_SD_MAJORS; i++) { - read_ahead[SD_MAJOR(i)] = - (rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device - && rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device->host->sg_tablesize) - ? 120 /* 120 sector read-ahead */ - : 4; /* 4 sector read-ahead */ - } + for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) { + /* FIXME: After 2.2 we should implement multiple sd queues */ + blk_dev[SD_MAJOR(i)].request_fn = DEVICE_REQUEST; + if (i) + blk_dev[SD_MAJOR(i)].queue = sd_get_queue; + } + for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next) + if (gendisk == sd_gendisks) + break; + if (gendisk == NULL) { + LAST_SD_GENDISK.next = gendisk_head; + gendisk_head = sd_gendisks; + } + for (i = 0; i < sd_template.dev_max; ++i) + if (!rscsi_disks[i].capacity && + rscsi_disks[i].device) { + if (MODULE_FLAG + && !rscsi_disks[i].has_part_table) { + sd_sizes[i << 4] = rscsi_disks[i].capacity; + /* revalidate does sd_init_onedisk via MAYBE_REINIT */ + revalidate_scsidisk(MKDEV_SD(i), 0); + } else + i = sd_init_onedisk(i); + rscsi_disks[i].has_part_table = 1; + } + /* If our host adapter is capable of scatter-gather, then we increase + * the read-ahead to 60 blocks (120 sectors). If not, we use + * a two block (4 sector) read ahead. We can only respect this with the + * granularity of every 16 disks (one device major). + */ + for (i = 0; i < N_USED_SD_MAJORS; i++) { + read_ahead[SD_MAJOR(i)] = + (rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device + && rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device->host->sg_tablesize) + ? 120 /* 120 sector read-ahead */ + : 4; /* 4 sector read-ahead */ + } - return; + return; } -static int sd_detect(Scsi_Device * SDp){ - char nbuff[6]; - if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; - - sd_devname(sd_template.dev_noticed++, nbuff); - printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n", - SDp->removable ? "removable " : "", - nbuff, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); +static int sd_detect(Scsi_Device * SDp) +{ + char nbuff[6]; + if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) + return 0; + + sd_devname(sd_template.dev_noticed++, nbuff); + printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n", + SDp->removable ? "removable " : "", + nbuff, + SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - return 1; + return 1; } +static int sd_attach(Scsi_Device * SDp) +{ + Scsi_Disk *dpnt; + int i; -static int sd_attach(Scsi_Device * SDp){ - Scsi_Disk * dpnt; - int i; - - if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; + if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) + return 0; - if(sd_template.nr_dev >= sd_template.dev_max) { - SDp->attached--; - return 1; - } - - for(dpnt = rscsi_disks, i=0; idevice) break; + if (sd_template.nr_dev >= sd_template.dev_max) { + SDp->attached--; + return 1; + } + for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++) + if (!dpnt->device) + break; - if(i >= sd_template.dev_max) panic ("scsi_devices corrupt (sd)"); + if (i >= sd_template.dev_max) + panic("scsi_devices corrupt (sd)"); - SDp->scsi_request_fn = do_sd_request; - rscsi_disks[i].device = SDp; - rscsi_disks[i].has_part_table = 0; - sd_template.nr_dev++; - SD_GENDISK(i).nr_real++; - return 0; + SDp->scsi_request_fn = do_sd_request; + rscsi_disks[i].device = SDp; + rscsi_disks[i].has_part_table = 0; + sd_template.nr_dev++; + SD_GENDISK(i).nr_real++; + return 0; } #define DEVICE_BUSY rscsi_disks[target].device->busy @@ -1671,160 +1627,160 @@ * usage == 1 (we need an open channel to use an ioctl :-), so this * is our limit. */ -int revalidate_scsidisk(kdev_t dev, int maxusage) { - int target; - int max_p; - int start; - int i; - - target = DEVICE_NR(dev); - - if (DEVICE_BUSY || USAGE > maxusage) { - printk("Device busy for revalidation (usage=%d)\n", USAGE); - return -EBUSY; - } - DEVICE_BUSY = 1; - - max_p = sd_gendisks->max_p; - start = target << sd_gendisks->minor_shift; - - for (i=max_p - 1; i >=0 ; i--) { - int index = start+i; - kdev_t devi = MKDEV_SD_PARTITION(index); - struct super_block *sb = get_super(devi); - sync_dev(devi); - if (sb) invalidate_inodes(sb); - invalidate_buffers(devi); - sd_gendisks->part[index].start_sect = 0; - sd_gendisks->part[index].nr_sects = 0; - /* - * Reset the blocksize for everything so that we can read - * the partition table. Technically we will determine the - * correct block size when we revalidate, but we do this just - * to make sure that everything remains consistent. - */ - sd_blocksizes[index] = 1024; - if( rscsi_disks[target].sector_size == 2048 ) - sd_blocksizes[index] = 2048; - else - sd_blocksizes[index] = 1024; - } - -#ifdef MAYBE_REINIT - MAYBE_REINIT; -#endif +int revalidate_scsidisk(kdev_t dev, int maxusage) +{ + int target; + int max_p; + int start; + int i; - sd_gendisks->part[start].nr_sects = CAPACITY; - resetup_one_dev(&SD_GENDISK(target), - target % SCSI_DISKS_PER_MAJOR); + target = DEVICE_NR(dev); - DEVICE_BUSY = 0; - return 0; -} - -static int fop_revalidate_scsidisk(kdev_t dev){ - return revalidate_scsidisk(dev, 0); -} + if (DEVICE_BUSY || USAGE > maxusage) { + printk("Device busy for revalidation (usage=%d)\n", USAGE); + return -EBUSY; + } + DEVICE_BUSY = 1; + max_p = sd_gendisks->max_p; + start = target << sd_gendisks->minor_shift; -static void sd_detach(Scsi_Device * SDp) -{ - Scsi_Disk * dpnt; - int i, j; - int max_p; - int start; - - for(dpnt = rscsi_disks, i=0; idevice == SDp) { - - /* If we are disconnecting a disk driver, sync and invalidate - * everything */ - max_p = sd_gendisk.max_p; - start = i << sd_gendisk.minor_shift; - - for (j=max_p - 1; j >=0 ; j--) { - int index = start+j; + for (i = max_p - 1; i >= 0; i--) { + int index = start + i; kdev_t devi = MKDEV_SD_PARTITION(index); - struct super_block *sb = get_super(devi); + struct super_block *sb = get_super(devi); sync_dev(devi); - if (sb) invalidate_inodes(sb); + if (sb) + invalidate_inodes(sb); invalidate_buffers(devi); sd_gendisks->part[index].start_sect = 0; sd_gendisks->part[index].nr_sects = 0; - sd_sizes[index] = 0; - } - - dpnt->has_part_table = 0; - dpnt->device = NULL; - dpnt->capacity = 0; - SDp->attached--; - sd_template.dev_noticed--; - sd_template.nr_dev--; - SD_GENDISK(i).nr_real--; - return; + /* + * Reset the blocksize for everything so that we can read + * the partition table. Technically we will determine the + * correct block size when we revalidate, but we do this just + * to make sure that everything remains consistent. + */ + sd_blocksizes[index] = 1024; + if (rscsi_disks[target].sector_size == 2048) + sd_blocksizes[index] = 2048; + else + sd_blocksizes[index] = 1024; } - return; + +#ifdef MAYBE_REINIT + MAYBE_REINIT; +#endif + + sd_gendisks->part[start].nr_sects = CAPACITY; + resetup_one_dev(&SD_GENDISK(target), + target % SCSI_DISKS_PER_MAJOR); + + DEVICE_BUSY = 0; + return 0; +} + +static int fop_revalidate_scsidisk(kdev_t dev) +{ + return revalidate_scsidisk(dev, 0); +} +static void sd_detach(Scsi_Device * SDp) +{ + Scsi_Disk *dpnt; + int i, j; + int max_p; + int start; + + for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++) + if (dpnt->device == SDp) { + + /* If we are disconnecting a disk driver, sync and invalidate + * everything */ + max_p = sd_gendisk.max_p; + start = i << sd_gendisk.minor_shift; + + for (j = max_p - 1; j >= 0; j--) { + int index = start + j; + kdev_t devi = MKDEV_SD_PARTITION(index); + struct super_block *sb = get_super(devi); + sync_dev(devi); + if (sb) + invalidate_inodes(sb); + invalidate_buffers(devi); + sd_gendisks->part[index].start_sect = 0; + sd_gendisks->part[index].nr_sects = 0; + sd_sizes[index] = 0; + } + dpnt->has_part_table = 0; + dpnt->device = NULL; + dpnt->capacity = 0; + SDp->attached--; + sd_template.dev_noticed--; + sd_template.nr_dev--; + SD_GENDISK(i).nr_real--; + return; + } + return; } #ifdef MODULE -int init_module(void) { - sd_template.module = &__this_module; - return scsi_register_module(MODULE_SCSI_DEV, &sd_template); +int init_module(void) +{ + sd_template.module = &__this_module; + return scsi_register_module(MODULE_SCSI_DEV, &sd_template); } - -void cleanup_module( void) +void cleanup_module(void) { - struct gendisk ** prev_sdgd_link; - struct gendisk * sdgd; - int i; - int removed = 0; - - scsi_unregister_module(MODULE_SCSI_DEV, &sd_template); - - for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) - unregister_blkdev(SD_MAJOR(i),"sd"); - - sd_registered--; - if( rscsi_disks != NULL ) - { - scsi_init_free((char *) rscsi_disks, - sd_template.dev_max * sizeof(Scsi_Disk)); - scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int)); - scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int)); - scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int)); - scsi_init_free((char *) sd, - (sd_template.dev_max << 4) * sizeof(struct hd_struct)); + struct gendisk **prev_sdgd_link; + struct gendisk *sdgd; + int i; + int removed = 0; - /* - * Now remove sd_gendisks from the linked list - */ - prev_sdgd_link = &gendisk_head; - while ((sdgd = *prev_sdgd_link) != NULL) { - if (sdgd >= sd_gendisks && sdgd <= &LAST_SD_GENDISK) { - removed++; - *prev_sdgd_link = sdgd->next; - continue; - } - prev_sdgd_link = &sdgd->next; - } - - if (removed != N_USED_SD_MAJORS) - printk("%s %d sd_gendisks in disk chain", - removed > N_USED_SD_MAJORS ? "total" : "just", removed); - - } - - for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) { - blk_dev[SD_MAJOR(i)].request_fn = NULL; - blk_size[SD_MAJOR(i)] = NULL; - hardsect_size[SD_MAJOR(i)] = NULL; - read_ahead[SD_MAJOR(i)] = 0; - } - sd_template.dev_max = 0; - if (sd_gendisks != &sd_gendisk) kfree(sd_gendisks); + scsi_unregister_module(MODULE_SCSI_DEV, &sd_template); + + for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) + unregister_blkdev(SD_MAJOR(i), "sd"); + + sd_registered--; + if (rscsi_disks != NULL) { + scsi_init_free((char *) rscsi_disks, + sd_template.dev_max * sizeof(Scsi_Disk)); + scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int)); + scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int)); + scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int)); + scsi_init_free((char *) sd, + (sd_template.dev_max << 4) * sizeof(struct hd_struct)); + + /* + * Now remove sd_gendisks from the linked list + */ + prev_sdgd_link = &gendisk_head; + while ((sdgd = *prev_sdgd_link) != NULL) { + if (sdgd >= sd_gendisks && sdgd <= &LAST_SD_GENDISK) { + removed++; + *prev_sdgd_link = sdgd->next; + continue; + } + prev_sdgd_link = &sdgd->next; + } + + if (removed != N_USED_SD_MAJORS) + printk("%s %d sd_gendisks in disk chain", + removed > N_USED_SD_MAJORS ? "total" : "just", removed); + + } + for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) { + blk_dev[SD_MAJOR(i)].request_fn = NULL; + blk_size[SD_MAJOR(i)] = NULL; + hardsect_size[SD_MAJOR(i)] = NULL; + read_ahead[SD_MAJOR(i)] = 0; + } + sd_template.dev_max = 0; + if (sd_gendisks != &sd_gendisk) + kfree(sd_gendisks); } -#endif /* MODULE */ +#endif /* MODULE */ /* * Overrides for Emacs so that we almost follow Linus's tabbing style. diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/sd.h linux/drivers/scsi/sd.h --- v2.3.16/linux/drivers/scsi/sd.h Wed Aug 18 16:44:26 1999 +++ linux/drivers/scsi/sd.h Tue Sep 7 11:50:56 1999 @@ -1,19 +1,19 @@ /* - * sd.h Copyright (C) 1992 Drew Eckhardt - * SCSI disk driver header file by - * Drew Eckhardt + * sd.h Copyright (C) 1992 Drew Eckhardt + * SCSI disk driver header file by + * Drew Eckhardt * - * + * * - * Modified by Eric Youngdale eric@aib.com to - * add scatter-gather, multiple outstanding request, and other - * enhancements. + * Modified by Eric Youngdale eric@aib.com to + * add scatter-gather, multiple outstanding request, and other + * enhancements. */ #ifndef _SD_H #define _SD_H /* - $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/sd.h,v 1.1 1992/07/24 06:27:38 root Exp root $ -*/ + $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/sd.h,v 1.1 1992/07/24 06:27:38 root Exp root $ + */ #ifndef _SCSI_H #include "scsi.h" @@ -23,22 +23,22 @@ #include #endif -extern struct hd_struct * sd; +extern struct hd_struct *sd; typedef struct scsi_disk { - unsigned capacity; /* size in blocks */ - unsigned sector_size; /* size in bytes */ - Scsi_Device *device; - unsigned char ready; /* flag ready for FLOPTICAL */ - unsigned char write_prot; /* flag write_protect for rmvable dev */ - unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */ - unsigned char sector_bit_shift; /* power of 2 sectors per FS block */ - unsigned ten:1; /* support ten byte read / write */ - unsigned remap:1; /* support remapping */ - unsigned has_part_table:1; /* has partition table */ + unsigned capacity; /* size in blocks */ + unsigned sector_size; /* size in bytes */ + Scsi_Device *device; + unsigned char ready; /* flag ready for FLOPTICAL */ + unsigned char write_prot; /* flag write_protect for rmvable dev */ + unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */ + unsigned char sector_bit_shift; /* power of 2 sectors per FS block */ + unsigned ten:1; /* support ten byte read / write */ + unsigned remap:1; /* support remapping */ + unsigned has_part_table:1; /* has partition table */ } Scsi_Disk; -extern Scsi_Disk * rscsi_disks; +extern Scsi_Disk *rscsi_disks; extern int revalidate_scsidisk(kdev_t dev, int maxusage); @@ -67,4 +67,3 @@ * tab-width: 8 * End: */ - diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.3.16/linux/drivers/scsi/sr.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/scsi/sr.c Sat Sep 4 10:48:46 1999 @@ -1,27 +1,27 @@ /* * sr.c Copyright (C) 1992 David Giller - * Copyright (C) 1993, 1994, 1995 Eric Youngdale + * Copyright (C) 1993, 1994, 1995 Eric Youngdale * * adapted from: - * sd.c Copyright (C) 1992 Drew Eckhardt - * Linux scsi disk driver by - * Drew Eckhardt + * sd.c Copyright (C) 1992 Drew Eckhardt + * Linux scsi disk driver by + * Drew Eckhardt * * Modified by Eric Youngdale ericy@cais.com to * add scatter-gather, multiple outstanding request, and other * enhancements. * - * Modified by Eric Youngdale eric@aib.com to support loadable - * low-level scsi drivers. + * Modified by Eric Youngdale eric@aib.com to support loadable + * low-level scsi drivers. * - * Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to - * provide auto-eject. + * Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to + * provide auto-eject. * * Modified by Gerd Knorr to support the * generic cdrom interface * - * Modified by Jens Axboe - Uniform sr_packet() - * interface, capabilities probe additions, ioctl cleanups, etc. + * Modified by Jens Axboe - Uniform sr_packet() + * interface, capabilities probe additions, ioctl cleanups, etc. * */ @@ -44,13 +44,13 @@ #include "scsi.h" #include "hosts.h" #include "sr.h" -#include /* For the door lock/unlock commands */ +#include /* For the door lock/unlock commands */ #include "constants.h" -MODULE_PARM(xa_test,"i"); /* see sr_ioctl.c */ +MODULE_PARM(xa_test, "i"); /* see sr_ioctl.c */ -#define MAX_RETRIES 3 -#define SR_TIMEOUT (30 * HZ) +#define MAX_RETRIES 3 +#define SR_TIMEOUT (30 * HZ) static int sr_init(void); static void sr_finish(void); @@ -58,55 +58,58 @@ static int sr_detect(Scsi_Device *); static void sr_detach(Scsi_Device *); -struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM, - SCSI_CDROM_MAJOR, 0, 0, 0, 1, - sr_detect, sr_init, - sr_finish, sr_attach, sr_detach}; +struct Scsi_Device_Template sr_template = { + NULL, "cdrom", "sr", NULL, TYPE_ROM, + SCSI_CDROM_MAJOR, 0, 0, 0, 1, + sr_detect, sr_init, + sr_finish, sr_attach, sr_detach +}; -Scsi_CD * scsi_CDs = NULL; -static int * sr_sizes = NULL; +Scsi_CD *scsi_CDs = NULL; +static int *sr_sizes = NULL; -static int * sr_blocksizes = NULL; +static int *sr_blocksizes = NULL; -static int sr_open(struct cdrom_device_info*, int); +static int sr_open(struct cdrom_device_info *, int); void get_sectorsize(int); void get_capabilities(int); -void requeue_sr_request (Scsi_Cmnd * SCpnt); -static int sr_media_change(struct cdrom_device_info*, int); +void requeue_sr_request(Scsi_Cmnd * SCpnt); +static int sr_media_change(struct cdrom_device_info *, int); static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *); static void sr_release(struct cdrom_device_info *cdi) { if (scsi_CDs[MINOR(cdi->dev)].sector_size > 2048) - sr_set_blocklength(MINOR(cdi->dev),2048); + sr_set_blocklength(MINOR(cdi->dev), 2048); sync_dev(cdi->dev); scsi_CDs[MINOR(cdi->dev)].device->access_count--; if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module) __MOD_DEC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module); - if(sr_template.module) - __MOD_DEC_USE_COUNT(sr_template.module); + if (sr_template.module) + __MOD_DEC_USE_COUNT(sr_template.module); } -static struct cdrom_device_ops sr_dops = { - sr_open, /* open */ - sr_release, /* release */ - sr_drive_status, /* drive status */ - sr_media_change, /* media changed */ - sr_tray_move, /* tray move */ - sr_lock_door, /* lock door */ - sr_select_speed, /* select speed */ - NULL, /* select disc */ - sr_get_last_session, /* get last session */ - sr_get_mcn, /* get universal product code */ - sr_reset, /* hard reset */ - sr_audio_ioctl, /* audio ioctl */ - sr_dev_ioctl, /* device-specific ioctl */ - CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK | CDC_SELECT_SPEED | - CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | - CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW | +static struct cdrom_device_ops sr_dops = +{ + sr_open, /* open */ + sr_release, /* release */ + sr_drive_status, /* drive status */ + sr_media_change, /* media changed */ + sr_tray_move, /* tray move */ + sr_lock_door, /* lock door */ + sr_select_speed, /* select speed */ + NULL, /* select disc */ + sr_get_last_session, /* get last session */ + sr_get_mcn, /* get universal product code */ + sr_reset, /* hard reset */ + sr_audio_ioctl, /* audio ioctl */ + sr_dev_ioctl, /* device-specific ioctl */ + CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | + CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | + CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET, - 0, + 0, sr_packet }; @@ -120,48 +123,47 @@ * an inode for that to work, and we do not always have one. */ -int sr_media_change(struct cdrom_device_info *cdi, int slot){ +int sr_media_change(struct cdrom_device_info *cdi, int slot) +{ int retval; - if (CDSL_CURRENT != slot) { - /* no changer support */ - return -EINVAL; - } - + if (CDSL_CURRENT != slot) { + /* no changer support */ + return -EINVAL; + } retval = scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device, - SCSI_IOCTL_TEST_UNIT_READY, 0); + SCSI_IOCTL_TEST_UNIT_READY, 0); - if(retval) - { - /* Unable to test, unit probably not ready. This usually + if (retval) { + /* Unable to test, unit probably not ready. This usually * means there is no disc in the drive. Mark as changed, * and we will figure it out later once the drive is * available again. */ - scsi_CDs[MINOR(cdi->dev)].device->changed = 1; - return 1; /* This will force a flush, if called from - * check_disk_change */ + scsi_CDs[MINOR(cdi->dev)].device->changed = 1; + return 1; /* This will force a flush, if called from + * check_disk_change */ }; retval = scsi_CDs[MINOR(cdi->dev)].device->changed; - scsi_CDs[MINOR(cdi->dev)].device->changed = 0; - /* If the disk changed, the capacity will now be different, - * so we force a re-read of this information */ - if (retval) { + scsi_CDs[MINOR(cdi->dev)].device->changed = 0; + /* If the disk changed, the capacity will now be different, + * so we force a re-read of this information */ + if (retval) { /* check multisession offset etc */ - sr_cd_check(cdi); - - /* - * If the disk changed, the capacity will now be different, - * so we force a re-read of this information - * Force 2048 for the sector size so that filesystems won't - * be trying to use something that is too small if the disc - * has changed. - */ - scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1; + sr_cd_check(cdi); + + /* + * If the disk changed, the capacity will now be different, + * so we force a re-read of this information + * Force 2048 for the sector size so that filesystems won't + * be trying to use something that is too small if the disc + * has changed. + */ + scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1; - scsi_CDs[MINOR(cdi->dev)].sector_size = 2048; - } + scsi_CDs[MINOR(cdi->dev)].sector_size = 2048; + } return retval; } @@ -170,7 +172,7 @@ * end of a SCSI read / write, and will take on of several actions based on success or failure. */ -static void rw_intr (Scsi_Cmnd * SCpnt) +static void rw_intr(Scsi_Cmnd * SCpnt) { int result = SCpnt->result; int this_count = SCpnt->this_count; @@ -178,137 +180,130 @@ int block_sectors = 0; #ifdef DEBUG - printk("sr.c done: %x %x\n",result, SCpnt->request.bh->b_data); + printk("sr.c done: %x %x\n", result, SCpnt->request.bh->b_data); #endif - /* - Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial success. - Since this is a relatively rare error condition, no care is taken to - avoid unnecessary additional work such as memcpy's that could be avoided. - */ + /* + Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial success. + Since this is a relatively rare error condition, no care is taken to + avoid unnecessary additional work such as memcpy's that could be avoided. + */ - if (driver_byte(result) != 0 && /* An error occurred */ - SCpnt->sense_buffer[0] == 0xF0 && /* Sense data is valid */ + if (driver_byte(result) != 0 && /* An error occurred */ + SCpnt->sense_buffer[0] == 0xF0 && /* Sense data is valid */ (SCpnt->sense_buffer[2] == MEDIUM_ERROR || SCpnt->sense_buffer[2] == VOLUME_OVERFLOW || - SCpnt->sense_buffer[2] == ILLEGAL_REQUEST)) - { - long error_sector = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | - SCpnt->sense_buffer[6]; - int device_nr = DEVICE_NR(SCpnt->request.rq_dev); - if (SCpnt->request.bh != NULL) - block_sectors = SCpnt->request.bh->b_size >> 9; - if (block_sectors < 4) block_sectors = 4; - if (scsi_CDs[device_nr].sector_size == 2048) - error_sector <<= 2; - error_sector &= ~ (block_sectors - 1); - good_sectors = error_sector - SCpnt->request.sector; - if (good_sectors < 0 || good_sectors >= this_count) - good_sectors = 0; - /* - The SCSI specification allows for the value returned by READ - CAPACITY to be up to 75 2K sectors past the last readable - block. Therefore, if we hit a medium error within the last - 75 2K sectors, we decrease the saved size value. - */ - if ((error_sector >> 1) < sr_sizes[device_nr] && - scsi_CDs[device_nr].capacity - error_sector < 4*75) - sr_sizes[device_nr] = error_sector >> 1; - } - - if (good_sectors > 0) - { /* Some sectors were read successfully. */ - if (SCpnt->use_sg == 0) { - if (SCpnt->buffer != SCpnt->request.buffer) - { - int offset; - offset = (SCpnt->request.sector % 4) << 9; - memcpy((char *)SCpnt->request.buffer, - (char *)SCpnt->buffer + offset, - good_sectors << 9); - /* Even though we are not using scatter-gather, we look - * ahead and see if there is a linked request for the - * other half of this buffer. If there is, then satisfy - * it. */ - if((offset == 0) && good_sectors == 2 && - SCpnt->request.nr_sectors > good_sectors && - SCpnt->request.bh && - SCpnt->request.bh->b_reqnext && - SCpnt->request.bh->b_reqnext->b_size == 1024) { - memcpy((char *)SCpnt->request.bh->b_reqnext->b_data, - (char *)SCpnt->buffer + 1024, - 1024); - good_sectors += 2; - }; + SCpnt->sense_buffer[2] == ILLEGAL_REQUEST)) { + long error_sector = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | + SCpnt->sense_buffer[6]; + int device_nr = DEVICE_NR(SCpnt->request.rq_dev); + if (SCpnt->request.bh != NULL) + block_sectors = SCpnt->request.bh->b_size >> 9; + if (block_sectors < 4) + block_sectors = 4; + if (scsi_CDs[device_nr].sector_size == 2048) + error_sector <<= 2; + error_sector &= ~(block_sectors - 1); + good_sectors = error_sector - SCpnt->request.sector; + if (good_sectors < 0 || good_sectors >= this_count) + good_sectors = 0; + /* + The SCSI specification allows for the value returned by READ + CAPACITY to be up to 75 2K sectors past the last readable + block. Therefore, if we hit a medium error within the last + 75 2K sectors, we decrease the saved size value. + */ + if ((error_sector >> 1) < sr_sizes[device_nr] && + scsi_CDs[device_nr].capacity - error_sector < 4 * 75) + sr_sizes[device_nr] = error_sector >> 1; + } + if (good_sectors > 0) { /* Some sectors were read successfully. */ + if (SCpnt->use_sg == 0) { + if (SCpnt->buffer != SCpnt->request.buffer) { + int offset; + offset = (SCpnt->request.sector % 4) << 9; + memcpy((char *) SCpnt->request.buffer, + (char *) SCpnt->buffer + offset, + good_sectors << 9); + /* Even though we are not using scatter-gather, we look + * ahead and see if there is a linked request for the + * other half of this buffer. If there is, then satisfy + * it. */ + if ((offset == 0) && good_sectors == 2 && + SCpnt->request.nr_sectors > good_sectors && + SCpnt->request.bh && + SCpnt->request.bh->b_reqnext && + SCpnt->request.bh->b_reqnext->b_size == 1024) { + memcpy((char *) SCpnt->request.bh->b_reqnext->b_data, + (char *) SCpnt->buffer + 1024, + 1024); + good_sectors += 2; + }; - scsi_free(SCpnt->buffer, 2048); - } - } else { - struct scatterlist * sgpnt; - int i; - sgpnt = (struct scatterlist *) SCpnt->buffer; - for(i=0; iuse_sg; i++) { - if (sgpnt[i].alt_address) { - if (sgpnt[i].alt_address != sgpnt[i].address) { - memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); - }; - scsi_free(sgpnt[i].address, sgpnt[i].length); + scsi_free(SCpnt->buffer, 2048); + } + } else { + struct scatterlist *sgpnt; + int i; + sgpnt = (struct scatterlist *) SCpnt->buffer; + for (i = 0; i < SCpnt->use_sg; i++) { + if (sgpnt[i].alt_address) { + if (sgpnt[i].alt_address != sgpnt[i].address) { + memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); + }; + scsi_free(sgpnt[i].address, sgpnt[i].length); + }; + }; + scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ + if (SCpnt->request.sector % 4) + good_sectors -= 2; + /* See if there is a padding record at the end that needs to be removed */ + if (good_sectors > SCpnt->request.nr_sectors) + good_sectors -= 2; }; - }; - scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ - if(SCpnt->request.sector % 4) good_sectors -= 2; - /* See if there is a padding record at the end that needs to be removed */ - if(good_sectors > SCpnt->request.nr_sectors) - good_sectors -= 2; - }; #ifdef DEBUG - printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors, + printk("(%x %x %x) ", SCpnt->request.bh, SCpnt->request.nr_sectors, good_sectors); #endif - if (SCpnt->request.nr_sectors > this_count) - { + if (SCpnt->request.nr_sectors > this_count) { SCpnt->request.errors = 0; if (!SCpnt->request.bh) - panic("sr.c: linked page request (%lx %x)", - SCpnt->request.sector, this_count); - } - - SCpnt = end_scsi_request(SCpnt, 1, good_sectors); /* All done */ - if (result == 0) - { - requeue_sr_request(SCpnt); - return; - } - } - - if (good_sectors == 0) { - /* We only come through here if no sectors were read successfully. */ - - /* Free up any indirection buffers we allocated for DMA purposes. */ - if (SCpnt->use_sg) { - struct scatterlist * sgpnt; - int i; - sgpnt = (struct scatterlist *) SCpnt->buffer; - for(i=0; iuse_sg; i++) { - if (sgpnt[i].alt_address) { - scsi_free(sgpnt[i].address, sgpnt[i].length); - } - } - scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ - } else { - if (SCpnt->buffer != SCpnt->request.buffer) - scsi_free(SCpnt->buffer, SCpnt->bufflen); + panic("sr.c: linked page request (%lx %x)", + SCpnt->request.sector, this_count); + } + SCpnt = end_scsi_request(SCpnt, 1, good_sectors); /* All done */ + if (result == 0) { + requeue_sr_request(SCpnt); + return; + } } + if (good_sectors == 0) { + /* We only come through here if no sectors were read successfully. */ - } + /* Free up any indirection buffers we allocated for DMA purposes. */ + if (SCpnt->use_sg) { + struct scatterlist *sgpnt; + int i; + sgpnt = (struct scatterlist *) SCpnt->buffer; + for (i = 0; i < SCpnt->use_sg; i++) { + if (sgpnt[i].alt_address) { + scsi_free(sgpnt[i].address, sgpnt[i].length); + } + } + scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ + } else { + if (SCpnt->buffer != SCpnt->request.buffer) + scsi_free(SCpnt->buffer, SCpnt->bufflen); + } + } if (driver_byte(result) != 0) { if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) { if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) { /* detected disc change. set a bit and quietly refuse - * further access. */ + * further access. */ scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1; SCpnt = end_scsi_request(SCpnt, 0, this_count); @@ -316,10 +311,9 @@ return; } } - if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) { printk("sr%d: CD-ROM error: ", - DEVICE_NR(SCpnt->request.rq_dev)); + DEVICE_NR(SCpnt->request.rq_dev)); print_sense("sr", SCpnt); printk("command was: "); print_command(SCpnt->cmnd); @@ -330,95 +324,87 @@ return; } else { SCpnt = end_scsi_request(SCpnt, 0, this_count); - requeue_sr_request(SCpnt); /* Do next request */ + requeue_sr_request(SCpnt); /* Do next request */ return; } } - if (SCpnt->sense_buffer[2] == NOT_READY) { printk(KERN_INFO "sr%d: CD-ROM not ready. Make sure you have a disc in the drive.\n", - DEVICE_NR(SCpnt->request.rq_dev)); + DEVICE_NR(SCpnt->request.rq_dev)); SCpnt = end_scsi_request(SCpnt, 0, this_count); - requeue_sr_request(SCpnt); /* Do next request */ + requeue_sr_request(SCpnt); /* Do next request */ return; } - if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) { - printk("scsi%d: MEDIUM ERROR on " - "channel %d, id %d, lun %d, CDB: ", - SCpnt->host->host_no, (int) SCpnt->channel, - (int) SCpnt->target, (int) SCpnt->lun); - print_command(SCpnt->cmnd); - print_sense("sr", SCpnt); - SCpnt = end_scsi_request(SCpnt, 0, block_sectors); - requeue_sr_request(SCpnt); - return; + printk("scsi%d: MEDIUM ERROR on " + "channel %d, id %d, lun %d, CDB: ", + SCpnt->host->host_no, (int) SCpnt->channel, + (int) SCpnt->target, (int) SCpnt->lun); + print_command(SCpnt->cmnd); + print_sense("sr", SCpnt); + SCpnt = end_scsi_request(SCpnt, 0, block_sectors); + requeue_sr_request(SCpnt); + return; } - if (SCpnt->sense_buffer[2] == VOLUME_OVERFLOW) { - printk("scsi%d: VOLUME OVERFLOW on " - "channel %d, id %d, lun %d, CDB: ", - SCpnt->host->host_no, (int) SCpnt->channel, - (int) SCpnt->target, (int) SCpnt->lun); - print_command(SCpnt->cmnd); - print_sense("sr", SCpnt); - SCpnt = end_scsi_request(SCpnt, 0, block_sectors); - requeue_sr_request(SCpnt); - return; + printk("scsi%d: VOLUME OVERFLOW on " + "channel %d, id %d, lun %d, CDB: ", + SCpnt->host->host_no, (int) SCpnt->channel, + (int) SCpnt->target, (int) SCpnt->lun); + print_command(SCpnt->cmnd); + print_sense("sr", SCpnt); + SCpnt = end_scsi_request(SCpnt, 0, block_sectors); + requeue_sr_request(SCpnt); + return; } - } - + } /* We only get this far if we have an error we have not recognized */ - if(result) { - printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", - scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no, - scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->id, - scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, - result); - - if (status_byte(result) == CHECK_CONDITION) - print_sense("sr", SCpnt); - - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); - requeue_sr_request(SCpnt); - } + if (result) { + printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", + scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no, + scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->id, + scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, + result); + + if (status_byte(result) == CHECK_CONDITION) + print_sense("sr", SCpnt); + + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); + requeue_sr_request(SCpnt); + } } static int sr_open(struct cdrom_device_info *cdi, int purpose) { - check_disk_change(cdi->dev); + check_disk_change(cdi->dev); - if( MINOR(cdi->dev) >= sr_template.dev_max - || !scsi_CDs[MINOR(cdi->dev)].device) - { - return -ENXIO; /* No such device */ - } - - /* - * If the device is in error recovery, wait until it is done. - * If the device is offline, then disallow any access to it. - */ - if( !scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device) ) - { - return -ENXIO; - } - - scsi_CDs[MINOR(cdi->dev)].device->access_count++; - if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module) - __MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module); - if(sr_template.module) - __MOD_INC_USE_COUNT(sr_template.module); - - /* If this device did not have media in the drive at boot time, then - * we would have been unable to get the sector size. Check to see if - * this is the case, and try again. - */ + if (MINOR(cdi->dev) >= sr_template.dev_max + || !scsi_CDs[MINOR(cdi->dev)].device) { + return -ENXIO; /* No such device */ + } + /* + * If the device is in error recovery, wait until it is done. + * If the device is offline, then disallow any access to it. + */ + if (!scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device)) { + return -ENXIO; + } + scsi_CDs[MINOR(cdi->dev)].device->access_count++; + if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module) + __MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module); + if (sr_template.module) + __MOD_INC_USE_COUNT(sr_template.module); + + /* If this device did not have media in the drive at boot time, then + * we would have been unable to get the sector size. Check to see if + * this is the case, and try again. + */ - if(scsi_CDs[MINOR(cdi->dev)].needs_sector_size) - get_sectorsize(MINOR(cdi->dev)); + if (scsi_CDs[MINOR(cdi->dev)].needs_sector_size) + get_sectorsize(MINOR(cdi->dev)); - return 0; + return 0; } /* @@ -427,111 +413,106 @@ * translate them to SCSI commands. */ -static void do_sr_request (void) +static void do_sr_request(void) { - Scsi_Cmnd * SCpnt = NULL; - struct request * req = NULL; - Scsi_Device * SDev; - int flag = 0; - - while (1==1){ - if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { - return; - }; + Scsi_Cmnd *SCpnt = NULL; + struct request *req = NULL; + Scsi_Device *SDev; + int flag = 0; - INIT_SCSI_REQUEST; + while (1 == 1) { + if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { + return; + }; - SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device; + INIT_SCSI_REQUEST; - /* - * If the host for this device is in error recovery mode, don't - * do anything at all here. When the host leaves error recovery - * mode, it will automatically restart things and start queueing - * commands again. - */ - if( SDev->host->in_recovery ) - { - return; - } + SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device; - /* - * I am not sure where the best place to do this is. We need - * to hook in a place where we are likely to come if in user - * space. - */ - if( SDev->was_reset ) - { - /* - * We need to relock the door, but we might - * be in an interrupt handler. Only do this - * from user space, since we do not want to - * sleep from an interrupt. - */ - if( SDev->removable && !in_interrupt() ) - { - spin_unlock_irq(&io_request_lock); /* FIXME!!!! */ - scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); - spin_lock_irq(&io_request_lock); /* FIXME!!!! */ - /* scsi_ioctl may allow CURRENT to change, so start over. */ - SDev->was_reset = 0; - continue; - } - SDev->was_reset = 0; - } - - /* we do lazy blocksize switching (when reading XA sectors, - * see CDROMREADMODE2 ioctl) */ - if (scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].sector_size > 2048) { - if (!in_interrupt()) - sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev),2048); + /* + * If the host for this device is in error recovery mode, don't + * do anything at all here. When the host leaves error recovery + * mode, it will automatically restart things and start queueing + * commands again. + */ + if (SDev->host->in_recovery) { + return; + } + /* + * I am not sure where the best place to do this is. We need + * to hook in a place where we are likely to come if in user + * space. + */ + if (SDev->was_reset) { + /* + * We need to relock the door, but we might + * be in an interrupt handler. Only do this + * from user space, since we do not want to + * sleep from an interrupt. + */ + if (SDev->removable && !in_interrupt()) { + spin_unlock_irq(&io_request_lock); /* FIXME!!!! */ + scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); + spin_lock_irq(&io_request_lock); /* FIXME!!!! */ + /* scsi_ioctl may allow CURRENT to change, so start over. */ + SDev->was_reset = 0; + continue; + } + SDev->was_reset = 0; + } + /* we do lazy blocksize switching (when reading XA sectors, + * see CDROMREADMODE2 ioctl) */ + if (scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].sector_size > 2048) { + if (!in_interrupt()) + sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev), 2048); #if 1 - else - printk("sr: can't switch blocksize: in interrupt\n"); + else + printk("sr: can't switch blocksize: in interrupt\n"); #endif - } - - if (flag++ == 0) - SCpnt = scsi_allocate_device(&CURRENT, - scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0); - else SCpnt = NULL; - - /* This is a performance enhancement. We dig down into the request list and - * try to find a queueable request (i.e. device not busy, and host able to - * accept another command. If we find one, then we queue it. This can - * make a big difference on systems with more than one disk drive. We want - * to have the interrupts off when monkeying with the request list, because - * otherwise the kernel might try to slip in a request in between somewhere. */ - - if (!SCpnt && sr_template.nr_dev > 1){ - struct request *req1; - req1 = NULL; - req = CURRENT; - while(req){ - SCpnt = scsi_request_queueable(req, - scsi_CDs[DEVICE_NR(req->rq_dev)].device); - if(SCpnt) break; - req1 = req; - req = req->next; - } - if (SCpnt && req->rq_status == RQ_INACTIVE) { - if (req == CURRENT) - CURRENT = CURRENT->next; + } + if (flag++ == 0) + SCpnt = scsi_allocate_device(&CURRENT, + scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0); else - req1->next = req->next; - } - } + SCpnt = NULL; - if (!SCpnt) - return; /* Could not find anything to do */ + /* This is a performance enhancement. We dig down into the request list and + * try to find a queueable request (i.e. device not busy, and host able to + * accept another command. If we find one, then we queue it. This can + * make a big difference on systems with more than one disk drive. We want + * to have the interrupts off when monkeying with the request list, because + * otherwise the kernel might try to slip in a request in between somewhere. */ + + if (!SCpnt && sr_template.nr_dev > 1) { + struct request *req1; + req1 = NULL; + req = CURRENT; + while (req) { + SCpnt = scsi_request_queueable(req, + scsi_CDs[DEVICE_NR(req->rq_dev)].device); + if (SCpnt) + break; + req1 = req; + req = req->next; + } + if (SCpnt && req->rq_status == RQ_INACTIVE) { + if (req == CURRENT) + CURRENT = CURRENT->next; + else + req1->next = req->next; + } + } + if (!SCpnt) + return; /* Could not find anything to do */ - wake_up(&wait_for_request); + wake_up(&wait_for_request); - /* Queue command */ - requeue_sr_request(SCpnt); - } /* While */ + /* Queue command */ + requeue_sr_request(SCpnt); + } /* While */ } -void requeue_sr_request (Scsi_Cmnd * SCpnt) +void requeue_sr_request(Scsi_Cmnd * SCpnt) { unsigned int dev, block, realcount; unsigned char cmd[10], *buffer, tries; @@ -539,244 +520,234 @@ tries = 2; - repeat: - if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) { +repeat: + if (!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) { do_sr_request(); return; } - - dev = MINOR(SCpnt->request.rq_dev); + dev = MINOR(SCpnt->request.rq_dev); block = SCpnt->request.sector; buffer = NULL; this_count = 0; if (dev >= sr_template.nr_dev) { - /* printk("CD-ROM request error: invalid device.\n"); */ + /* printk("CD-ROM request error: invalid device.\n"); */ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); tries = 2; goto repeat; } - if (!scsi_CDs[dev].use) { - /* printk("CD-ROM request error: device marked not in use.\n"); */ + /* printk("CD-ROM request error: device marked not in use.\n"); */ + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + tries = 2; + goto repeat; + } + if (!scsi_CDs[dev].device->online) { SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); tries = 2; goto repeat; } - - if( !scsi_CDs[dev].device->online ) - { - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); - tries = 2; - goto repeat; - } - if (scsi_CDs[dev].device->changed) { - /* - * quietly refuse to do anything to a changed disc - * until the changed bit has been reset - */ - /* printk("CD-ROM has been changed. Prohibiting further I/O.\n"); */ + /* + * quietly refuse to do anything to a changed disc + * until the changed bit has been reset + */ + /* printk("CD-ROM has been changed. Prohibiting further I/O.\n"); */ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); tries = 2; goto repeat; } - - switch (SCpnt->request.cmd) - { - case WRITE: - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); - goto repeat; - break; - case READ : - cmd[0] = READ_6; - break; - default : - panic ("Unknown sr command %d\n", SCpnt->request.cmd); - } + switch (SCpnt->request.cmd) { + case WRITE: + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + break; + case READ: + cmd[0] = READ_6; + break; + default: + panic("Unknown sr command %d\n", SCpnt->request.cmd); + } cmd[1] = (SCpnt->lun << 5) & 0xe0; - /* - * Now do the grungy work of figuring out which sectors we need, and - * where in memory we are going to put them. - * - * The variables we need are: - * - * this_count= number of 512 byte sectors being read - * block = starting cdrom sector to read. - * realcount = # of cdrom sectors to read - * - * The major difference between a scsi disk and a scsi cdrom - * is that we will always use scatter-gather if we can, because we can - * work around the fact that the buffer cache has a block size of 1024, - * and we have 2048 byte sectors. This code should work for buffers that - * are any multiple of 512 bytes long. - */ + /* + * Now do the grungy work of figuring out which sectors we need, and + * where in memory we are going to put them. + * + * The variables we need are: + * + * this_count= number of 512 byte sectors being read + * block = starting cdrom sector to read. + * realcount = # of cdrom sectors to read + * + * The major difference between a scsi disk and a scsi cdrom + * is that we will always use scatter-gather if we can, because we can + * work around the fact that the buffer cache has a block size of 1024, + * and we have 2048 byte sectors. This code should work for buffers that + * are any multiple of 512 bytes long. + */ SCpnt->use_sg = 0; if (SCpnt->host->sg_tablesize > 0 && (!scsi_need_isa_buffer || - scsi_dma_free_sectors >= 10)) { - struct buffer_head * bh; - struct scatterlist * sgpnt; - int count, this_count_max; - bh = SCpnt->request.bh; - this_count = 0; - count = 0; - this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4; - /* Calculate how many links we can use. First see if we need - * a padding record at the start */ - this_count = SCpnt->request.sector % 4; - if(this_count) count++; - while(bh && count < SCpnt->host->sg_tablesize) { - if ((this_count + (bh->b_size >> 9)) > this_count_max) break; - this_count += (bh->b_size >> 9); - count++; - bh = bh->b_reqnext; - }; - /* Fix up in case of an odd record at the end */ - end_rec = 0; - if(this_count % 4) { - if (count < SCpnt->host->sg_tablesize) { - count++; - end_rec = (4 - (this_count % 4)) << 9; - this_count += 4 - (this_count % 4); - } else { - count--; - this_count -= (this_count % 4); - }; - }; - SCpnt->use_sg = count; /* Number of chains */ - /* scsi_malloc can only allocate in chunks of 512 bytes */ - count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511; - - SCpnt->sglist_len = count; - sgpnt = (struct scatterlist * ) scsi_malloc(count); - if (!sgpnt) { - printk("Warning - running *really* short on DMA buffers\n"); - SCpnt->use_sg = 0; /* No memory left - bail out */ - } else { - buffer = (unsigned char *) sgpnt; - count = 0; - bh = SCpnt->request.bh; - if(SCpnt->request.sector % 4) { - sgpnt[count].length = (SCpnt->request.sector % 4) << 9; - sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); - if(!sgpnt[count].address) panic("SCSI DMA pool exhausted."); - sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete - if needed */ - count++; - }; - for(bh = SCpnt->request.bh; count < SCpnt->use_sg; - count++, bh = bh->b_reqnext) { - if (bh) { /* Need a placeholder at the end of the record? */ - sgpnt[count].address = bh->b_data; - sgpnt[count].length = bh->b_size; - sgpnt[count].alt_address = NULL; - } else { - sgpnt[count].address = (char *) scsi_malloc(end_rec); - if(!sgpnt[count].address) panic("SCSI DMA pool exhausted."); - sgpnt[count].length = end_rec; - sgpnt[count].alt_address = sgpnt[count].address; - if (count+1 != SCpnt->use_sg) panic("Bad sr request list"); - break; + scsi_dma_free_sectors >= 10)) { + struct buffer_head *bh; + struct scatterlist *sgpnt; + int count, this_count_max; + bh = SCpnt->request.bh; + this_count = 0; + count = 0; + this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4; + /* Calculate how many links we can use. First see if we need + * a padding record at the start */ + this_count = SCpnt->request.sector % 4; + if (this_count) + count++; + while (bh && count < SCpnt->host->sg_tablesize) { + if ((this_count + (bh->b_size >> 9)) > this_count_max) + break; + this_count += (bh->b_size >> 9); + count++; + bh = bh->b_reqnext; }; - if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 > - ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) { - sgpnt[count].alt_address = sgpnt[count].address; - /* We try to avoid exhausting the DMA pool, since it is easier - * to control usage here. In other places we might have a more - * pressing need, and we would be screwed if we ran out */ - if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 5) { - sgpnt[count].address = NULL; - } else { - sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); - }; - /* If we start running low on DMA buffers, we abort the scatter-gather - * operation, and free all of the memory we have allocated. We want to - * ensure that all scsi operations are able to do at least a non-scatter/gather - * operation */ - if(sgpnt[count].address == NULL){ /* Out of dma memory */ - printk("Warning: Running low on SCSI DMA buffers\n"); - /* Try switching back to a non scatter-gather operation. */ - while(--count >= 0){ - if(sgpnt[count].alt_address) - scsi_free(sgpnt[count].address, sgpnt[count].length); + /* Fix up in case of an odd record at the end */ + end_rec = 0; + if (this_count % 4) { + if (count < SCpnt->host->sg_tablesize) { + count++; + end_rec = (4 - (this_count % 4)) << 9; + this_count += 4 - (this_count % 4); + } else { + count--; + this_count -= (this_count % 4); }; - SCpnt->use_sg = 0; - scsi_free(buffer, SCpnt->sglist_len); - break; - }; /* if address == NULL */ - }; /* if need DMA fixup */ - }; /* for loop to fill list */ + }; + SCpnt->use_sg = count; /* Number of chains */ + /* scsi_malloc can only allocate in chunks of 512 bytes */ + count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511; + + SCpnt->sglist_len = count; + sgpnt = (struct scatterlist *) scsi_malloc(count); + if (!sgpnt) { + printk("Warning - running *really* short on DMA buffers\n"); + SCpnt->use_sg = 0; /* No memory left - bail out */ + } else { + buffer = (unsigned char *) sgpnt; + count = 0; + bh = SCpnt->request.bh; + if (SCpnt->request.sector % 4) { + sgpnt[count].length = (SCpnt->request.sector % 4) << 9; + sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); + if (!sgpnt[count].address) + panic("SCSI DMA pool exhausted."); + sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete + if needed */ + count++; + }; + for (bh = SCpnt->request.bh; count < SCpnt->use_sg; + count++, bh = bh->b_reqnext) { + if (bh) { /* Need a placeholder at the end of the record? */ + sgpnt[count].address = bh->b_data; + sgpnt[count].length = bh->b_size; + sgpnt[count].alt_address = NULL; + } else { + sgpnt[count].address = (char *) scsi_malloc(end_rec); + if (!sgpnt[count].address) + panic("SCSI DMA pool exhausted."); + sgpnt[count].length = end_rec; + sgpnt[count].alt_address = sgpnt[count].address; + if (count + 1 != SCpnt->use_sg) + panic("Bad sr request list"); + break; + }; + if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 > + ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) { + sgpnt[count].alt_address = sgpnt[count].address; + /* We try to avoid exhausting the DMA pool, since it is easier + * to control usage here. In other places we might have a more + * pressing need, and we would be screwed if we ran out */ + if (scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 5) { + sgpnt[count].address = NULL; + } else { + sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); + }; + /* If we start running low on DMA buffers, we abort the scatter-gather + * operation, and free all of the memory we have allocated. We want to + * ensure that all scsi operations are able to do at least a non-scatter/gather + * operation */ + if (sgpnt[count].address == NULL) { /* Out of dma memory */ + printk("Warning: Running low on SCSI DMA buffers\n"); + /* Try switching back to a non scatter-gather operation. */ + while (--count >= 0) { + if (sgpnt[count].alt_address) + scsi_free(sgpnt[count].address, sgpnt[count].length); + }; + SCpnt->use_sg = 0; + scsi_free(buffer, SCpnt->sglist_len); + break; + }; /* if address == NULL */ + }; /* if need DMA fixup */ + }; /* for loop to fill list */ #ifdef DEBUG - printk("SR: %d %d %d %d %d *** ",SCpnt->use_sg, SCpnt->request.sector, - this_count, - SCpnt->request.current_nr_sectors, - SCpnt->request.nr_sectors); - for(count=0; countuse_sg; count++) - printk("SGlist: %d %x %x %x\n", count, - sgpnt[count].address, - sgpnt[count].alt_address, - sgpnt[count].length); + printk("SR: %d %d %d %d %d *** ", SCpnt->use_sg, SCpnt->request.sector, + this_count, + SCpnt->request.current_nr_sectors, + SCpnt->request.nr_sectors); + for (count = 0; count < SCpnt->use_sg; count++) + printk("SGlist: %d %x %x %x\n", count, + sgpnt[count].address, + sgpnt[count].alt_address, + sgpnt[count].length); #endif - }; /* Able to allocate scatter-gather list */ + }; /* Able to allocate scatter-gather list */ }; - if (SCpnt->use_sg == 0){ - /* We cannot use scatter-gather. Do this the old fashion way */ - if (!SCpnt->request.bh) - this_count = SCpnt->request.nr_sectors; - else - this_count = (SCpnt->request.bh->b_size >> 9); + if (SCpnt->use_sg == 0) { + /* We cannot use scatter-gather. Do this the old fashion way */ + if (!SCpnt->request.bh) + this_count = SCpnt->request.nr_sectors; + else + this_count = (SCpnt->request.bh->b_size >> 9); - start = block % 4; - if (start) - { - this_count = ((this_count > 4 - start) ? - (4 - start) : (this_count)); - buffer = (unsigned char *) scsi_malloc(2048); - } - else if (this_count < 4) - { - buffer = (unsigned char *) scsi_malloc(2048); - } - else - { - this_count -= this_count % 4; - buffer = (unsigned char *) SCpnt->request.buffer; - if (virt_to_phys(buffer) + (this_count << 9) > ISA_DMA_THRESHOLD && - SCpnt->host->unchecked_isa_dma) - buffer = (unsigned char *) scsi_malloc(this_count << 9); - } + start = block % 4; + if (start) { + this_count = ((this_count > 4 - start) ? + (4 - start) : (this_count)); + buffer = (unsigned char *) scsi_malloc(2048); + } else if (this_count < 4) { + buffer = (unsigned char *) scsi_malloc(2048); + } else { + this_count -= this_count % 4; + buffer = (unsigned char *) SCpnt->request.buffer; + if (virt_to_phys(buffer) + (this_count << 9) > ISA_DMA_THRESHOLD && + SCpnt->host->unchecked_isa_dma) + buffer = (unsigned char *) scsi_malloc(this_count << 9); + } }; if (scsi_CDs[dev].sector_size == 2048) - block = block >> 2; /* These are the sectors that the cdrom uses */ + block = block >> 2; /* These are the sectors that the cdrom uses */ else - block = block & 0xfffffffc; + block = block & 0xfffffffc; realcount = (this_count + 3) / 4; - if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2; + if (scsi_CDs[dev].sector_size == 512) + realcount = realcount << 2; - /* - * Note: The scsi standard says that READ_6 is *optional*, while - * READ_10 is mandatory. Thus there is no point in using - * READ_6. - */ - if (scsi_CDs[dev].ten) - - { - if (realcount > 0xffff) - { + /* + * Note: The scsi standard says that READ_6 is *optional*, while + * READ_10 is mandatory. Thus there is no point in using + * READ_6. + */ + if (scsi_CDs[dev].ten) { + if (realcount > 0xffff) { realcount = 0xffff; this_count = realcount * (scsi_CDs[dev].sector_size >> 9); - } - - cmd[0] += READ_10 - READ_6 ; + } + cmd[0] += READ_10 - READ_6; cmd[2] = (unsigned char) (block >> 24) & 0xff; cmd[3] = (unsigned char) (block >> 16) & 0xff; cmd[4] = (unsigned char) (block >> 8) & 0xff; @@ -784,167 +755,172 @@ cmd[6] = cmd[9] = 0; cmd[7] = (unsigned char) (realcount >> 8) & 0xff; cmd[8] = (unsigned char) realcount & 0xff; - } - else - { - if (realcount > 0xff) - { - realcount = 0xff; - this_count = realcount * (scsi_CDs[dev].sector_size >> 9); + } else { + if (realcount > 0xff) { + realcount = 0xff; + this_count = realcount * (scsi_CDs[dev].sector_size >> 9); + } + cmd[1] |= (unsigned char) ((block >> 16) & 0x1f); + cmd[2] = (unsigned char) ((block >> 8) & 0xff); + cmd[3] = (unsigned char) block & 0xff; + cmd[4] = (unsigned char) realcount; + cmd[5] = 0; } - cmd[1] |= (unsigned char) ((block >> 16) & 0x1f); - cmd[2] = (unsigned char) ((block >> 8) & 0xff); - cmd[3] = (unsigned char) block & 0xff; - cmd[4] = (unsigned char) realcount; - cmd[5] = 0; - } - #ifdef DEBUG - { - int i; - printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count); - printk("Use sg: %d\n", SCpnt->use_sg); - printk("Dumping command: "); - for(i=0; i<12; i++) printk("%2.2x ", cmd[i]); - printk("\n"); - }; + { + int i; + printk("ReadCD: %d %d %d %d\n", block, realcount, buffer, this_count); + printk("Use sg: %d\n", SCpnt->use_sg); + printk("Dumping command: "); + for (i = 0; i < 12; i++) + printk("%2.2x ", cmd[i]); + printk("\n"); + }; #endif - /* Some dumb host adapters can speed transfers by knowing the - * minimum transfersize in advance. - * - * We shouldn't disconnect in the middle of a sector, but the cdrom - * sector size can be larger than the size of a buffer and the - * transfer may be split to the size of a buffer. So it's safe to - * assume that we can at least transfer the minimum of the buffer - * size (1024) and the sector size between each connect / disconnect. - */ + /* Some dumb host adapters can speed transfers by knowing the + * minimum transfersize in advance. + * + * We shouldn't disconnect in the middle of a sector, but the cdrom + * sector size can be larger than the size of a buffer and the + * transfer may be split to the size of a buffer. So it's safe to + * assume that we can at least transfer the minimum of the buffer + * size (1024) and the sector size between each connect / disconnect. + */ - SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ? - 1024 : scsi_CDs[dev].sector_size; + SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ? + 1024 : scsi_CDs[dev].sector_size; SCpnt->this_count = this_count; - scsi_do_cmd (SCpnt, (void *) cmd, buffer, - realcount * scsi_CDs[dev].sector_size, - rw_intr, SR_TIMEOUT, MAX_RETRIES); + scsi_do_cmd(SCpnt, (void *) cmd, buffer, + realcount * scsi_CDs[dev].sector_size, + rw_intr, SR_TIMEOUT, MAX_RETRIES); } -static int sr_detect(Scsi_Device * SDp){ +static int sr_detect(Scsi_Device * SDp) +{ - if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0; + if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) + return 0; - printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", - sr_template.dev_noticed++, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", + sr_template.dev_noticed++, + SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - return 1; + return 1; } -static int sr_attach(Scsi_Device * SDp){ - Scsi_CD * cpnt; - int i; - - if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1; - - if (sr_template.nr_dev >= sr_template.dev_max) - { - SDp->attached--; - return 1; - } +static int sr_attach(Scsi_Device * SDp) +{ + Scsi_CD *cpnt; + int i; - for(cpnt = scsi_CDs, i=0; idevice) break; + if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) + return 1; - if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)"); + if (sr_template.nr_dev >= sr_template.dev_max) { + SDp->attached--; + return 1; + } + for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++) + if (!cpnt->device) + break; + + if (i >= sr_template.dev_max) + panic("scsi_devices corrupt (sr)"); - SDp->scsi_request_fn = do_sr_request; - scsi_CDs[i].device = SDp; + SDp->scsi_request_fn = do_sr_request; + scsi_CDs[i].device = SDp; - sr_template.nr_dev++; - if(sr_template.nr_dev > sr_template.dev_max) - panic ("scsi_devices corrupt (sr)"); - return 0; + sr_template.nr_dev++; + if (sr_template.nr_dev > sr_template.dev_max) + panic("scsi_devices corrupt (sr)"); + return 0; } -static void sr_init_done (Scsi_Cmnd * SCpnt) +static void sr_init_done(Scsi_Cmnd * SCpnt) { - struct request * req; + struct request *req; - req = &SCpnt->request; - req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ + req = &SCpnt->request; + req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ - if (req->sem != NULL) { - up(req->sem); - } + if (req->sem != NULL) { + up(req->sem); + } } -void get_sectorsize(int i){ - unsigned char cmd[10]; - unsigned char *buffer; - int the_result, retries; - Scsi_Cmnd * SCpnt; - unsigned long flags; - - buffer = (unsigned char *) scsi_malloc(512); - SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1); - - retries = 3; - do { - cmd[0] = READ_CAPACITY; - cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; - memset ((void *) &cmd[2], 0, 8); - SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ - SCpnt->cmd_len = 0; +void get_sectorsize(int i) +{ + unsigned char cmd[10]; + unsigned char *buffer; + int the_result, retries; + Scsi_Cmnd *SCpnt; + unsigned long flags; - memset(buffer, 0, 8); + buffer = (unsigned char *) scsi_malloc(512); + SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1); - /* Do the command and wait.. */ - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.sem = &sem; - spin_lock_irqsave(&io_request_lock, flags); - scsi_do_cmd (SCpnt, - (void *) cmd, (void *) buffer, - 512, sr_init_done, SR_TIMEOUT, - MAX_RETRIES); - spin_unlock_irqrestore(&io_request_lock, flags); - down(&sem); - } - - the_result = SCpnt->result; - retries--; - - } while(the_result && retries); - - - wake_up(&SCpnt->device->device_wait); - scsi_release_command(SCpnt); - SCpnt = NULL; - - if (the_result) { - scsi_CDs[i].capacity = 0x1fffff; - scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ - scsi_CDs[i].needs_sector_size = 1; - } else { - if (cdrom_get_last_written(MKDEV(MAJOR_NR, i), - (long*)&scsi_CDs[i].capacity)) { - scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | - (buffer[1] << 16) | - (buffer[2] << 8) | - buffer[3]); - } - scsi_CDs[i].sector_size = (buffer[4] << 24) | - (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; - switch (scsi_CDs[i].sector_size) { - /* - * HP 4020i CD-Recorder reports 2340 byte sectors - * Philips CD-Writers report 2352 byte sectors - * - * Use 2k sectors for them.. - */ - case 0: case 2340: case 2352: + retries = 3; + do { + cmd[0] = READ_CAPACITY; + cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; + memset((void *) &cmd[2], 0, 8); + SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ + SCpnt->cmd_len = 0; + + memset(buffer, 0, 8); + + /* Do the command and wait.. */ + { + DECLARE_MUTEX_LOCKED(sem); + SCpnt->request.sem = &sem; + spin_lock_irqsave(&io_request_lock, flags); + scsi_do_cmd(SCpnt, + (void *) cmd, (void *) buffer, + 512, sr_init_done, SR_TIMEOUT, + MAX_RETRIES); + spin_unlock_irqrestore(&io_request_lock, flags); + down(&sem); + } + + the_result = SCpnt->result; + retries--; + + } while (the_result && retries); + + + wake_up(&SCpnt->device->device_wait); + scsi_release_command(SCpnt); + SCpnt = NULL; + + if (the_result) { + scsi_CDs[i].capacity = 0x1fffff; + scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ + scsi_CDs[i].needs_sector_size = 1; + } else { +#if 0 + if (cdrom_get_last_written(MKDEV(MAJOR_NR, i), + (long *) &scsi_CDs[i].capacity)) +#endif + scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + buffer[3]); + scsi_CDs[i].sector_size = (buffer[4] << 24) | + (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; + switch (scsi_CDs[i].sector_size) { + /* + * HP 4020i CD-Recorder reports 2340 byte sectors + * Philips CD-Writers report 2352 byte sectors + * + * Use 2k sectors for them.. + */ + case 0: + case 2340: + case 2352: scsi_CDs[i].sector_size = 2048; /* fall through */ case 2048: @@ -953,94 +929,95 @@ case 512: break; default: - printk ("sr%d: unsupported sector size %d.\n", - i, scsi_CDs[i].sector_size); + printk("sr%d: unsupported sector size %d.\n", + i, scsi_CDs[i].sector_size); scsi_CDs[i].capacity = 0; scsi_CDs[i].needs_sector_size = 1; - } + } - /* - * Add this so that we have the ability to correctly gauge - * what the device is capable of. - */ - scsi_CDs[i].needs_sector_size = 0; - sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); - }; - scsi_free(buffer, 512); + /* + * Add this so that we have the ability to correctly gauge + * what the device is capable of. + */ + scsi_CDs[i].needs_sector_size = 0; + sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); + }; + scsi_free(buffer, 512); } -void get_capabilities(int i){ - unsigned char cmd[6]; - unsigned char *buffer; - int rc,n; - - static char *loadmech[] = { - "caddy", - "tray", - "pop-up", - "", - "changer", - "changer", - "", - "" - }; - - buffer = (unsigned char *) scsi_malloc(512); - cmd[0] = MODE_SENSE; - cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; - cmd[2] = 0x2a; - cmd[4] = 128; - cmd[3] = cmd[5] = 0; - rc = sr_do_ioctl(i, cmd, buffer, 128, 1); - - if (-EINVAL == rc) { - /* failed, drive has'nt this mode page */ - scsi_CDs[i].cdi.speed = 1; - /* disable speed select, drive probably can't do this either */ - scsi_CDs[i].cdi.mask |= CDC_SELECT_SPEED; - scsi_free(buffer, 512); - return; - } - - n = buffer[3]+4; - scsi_CDs[i].cdi.speed = ((buffer[n+8] << 8) + buffer[n+9])/176; - scsi_CDs[i].readcd_known = 1; - scsi_CDs[i].readcd_cdda = buffer[n+5] & 0x01; - /* print some capability bits */ - printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n",i, - ((buffer[n+14] << 8) + buffer[n+15])/176, - scsi_CDs[i].cdi.speed, - buffer[n+3]&0x01 ? "writer " : "", /* CD Writer */ - buffer[n+2]&0x02 ? "cd/rw " : "", /* can read rewriteable */ - buffer[n+4]&0x20 ? "xa/form2 " : "", /* can read xa/from2 */ - buffer[n+5]&0x01 ? "cdda " : "", /* can read audio data */ - loadmech[buffer[n+6]>>5]); - if ((buffer[n+6] >> 5) == 0) - /* caddy drives can't close tray... */ - scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; - if ((buffer[n+2] & 0x8) == 0) - /* not a DVD drive */ - scsi_CDs[i].cdi.mask |= CDC_DVD; - if ((buffer[n+3] & 0x20) == 0) - /* can't write DVD-RAM media */ - scsi_CDs[i].cdi.mask |= CDC_DVD_RAM; - if ((buffer[n+3] & 0x10) == 0) - /* can't write DVD-R media */ - scsi_CDs[i].cdi.mask |= CDC_DVD_R; - if ((buffer[n+3] & 0x2) == 0) - /* can't write CD-RW media */ - scsi_CDs[i].cdi.mask |= CDC_CD_RW; - if ((buffer[n+3] & 0x1) == 0) - /* can't write CD-R media */ - scsi_CDs[i].cdi.mask |= CDC_CD_R; +void get_capabilities(int i) +{ + unsigned char cmd[6]; + unsigned char *buffer; + int rc, n; + + static char *loadmech[] = + { + "caddy", + "tray", + "pop-up", + "", + "changer", + "changer", + "", + "" + }; + + buffer = (unsigned char *) scsi_malloc(512); + cmd[0] = MODE_SENSE; + cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; + cmd[2] = 0x2a; + cmd[4] = 128; + cmd[3] = cmd[5] = 0; + rc = sr_do_ioctl(i, cmd, buffer, 128, 1); + + if (-EINVAL == rc) { + /* failed, drive has'nt this mode page */ + scsi_CDs[i].cdi.speed = 1; + /* disable speed select, drive probably can't do this either */ + scsi_CDs[i].cdi.mask |= CDC_SELECT_SPEED; + scsi_free(buffer, 512); + return; + } + n = buffer[3] + 4; + scsi_CDs[i].cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176; + scsi_CDs[i].readcd_known = 1; + scsi_CDs[i].readcd_cdda = buffer[n + 5] & 0x01; + /* print some capability bits */ + printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n", i, + ((buffer[n + 14] << 8) + buffer[n + 15]) / 176, + scsi_CDs[i].cdi.speed, + buffer[n + 3] & 0x01 ? "writer " : "", /* CD Writer */ + buffer[n + 2] & 0x02 ? "cd/rw " : "", /* can read rewriteable */ + buffer[n + 4] & 0x20 ? "xa/form2 " : "", /* can read xa/from2 */ + buffer[n + 5] & 0x01 ? "cdda " : "", /* can read audio data */ + loadmech[buffer[n + 6] >> 5]); + if ((buffer[n + 6] >> 5) == 0) + /* caddy drives can't close tray... */ + scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; + if ((buffer[n + 2] & 0x8) == 0) + /* not a DVD drive */ + scsi_CDs[i].cdi.mask |= CDC_DVD; + if ((buffer[n + 3] & 0x20) == 0) + /* can't write DVD-RAM media */ + scsi_CDs[i].cdi.mask |= CDC_DVD_RAM; + if ((buffer[n + 3] & 0x10) == 0) + /* can't write DVD-R media */ + scsi_CDs[i].cdi.mask |= CDC_DVD_R; + if ((buffer[n + 3] & 0x2) == 0) + /* can't write CD-RW media */ + scsi_CDs[i].cdi.mask |= CDC_CD_RW; + if ((buffer[n + 3] & 0x1) == 0) + /* can't write CD-R media */ + scsi_CDs[i].cdi.mask |= CDC_CD_R; - scsi_free(buffer, 512); + scsi_free(buffer, 512); } /* * sr_packet() is the entry point for the generic commands generated * by the Uniform CD-ROM layer. -*/ + */ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc) { Scsi_Cmnd *SCpnt; @@ -1048,12 +1025,12 @@ DECLARE_MUTEX_LOCKED(sem); unsigned long flags; int stat; - + /* get the device */ SCpnt = scsi_allocate_device(NULL, device, 1); if (SCpnt == NULL) return -ENODEV; /* this just doesn't seem right /axboe */ - + /* set the LUN */ cgc->cmd[1] |= device->lun << 5; @@ -1064,18 +1041,18 @@ SCpnt->cmd_len = 0; SCpnt->request.sem = &sem; spin_lock_irqsave(&io_request_lock, flags); - scsi_do_cmd (SCpnt, (void *)cgc->cmd, (void *)cgc->buffer, cgc->buflen, - sr_init_done, SR_TIMEOUT, MAX_RETRIES); + scsi_do_cmd(SCpnt, (void *) cgc->cmd, (void *) cgc->buffer, cgc->buflen, + sr_init_done, SR_TIMEOUT, MAX_RETRIES); spin_unlock_irqrestore(&io_request_lock, flags); down(&sem); - + stat = SCpnt->result; /* release */ - SCpnt->request.rq_dev = MKDEV(0,0); + SCpnt->request.rq_dev = MKDEV(0, 0); scsi_release_command(SCpnt); SCpnt = NULL; - + return stat; } @@ -1083,159 +1060,162 @@ static int sr_init() { - int i; + int i; - if(sr_template.dev_noticed == 0) return 0; + if (sr_template.dev_noticed == 0) + return 0; - if(!sr_registered) { - if (register_blkdev(MAJOR_NR,"sr",&cdrom_fops)) { - printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR); - return 1; + if (!sr_registered) { + if (register_blkdev(MAJOR_NR, "sr", &cdrom_fops)) { + printk("Unable to get major %d for SCSI-CD\n", MAJOR_NR); + return 1; + } + sr_registered++; } - sr_registered++; - } - - - if (scsi_CDs) return 0; - sr_template.dev_max = - sr_template.dev_noticed + SR_EXTRA_DEVS; - scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); - memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD)); + if (scsi_CDs) + return 0; + sr_template.dev_max = + sr_template.dev_noticed + SR_EXTRA_DEVS; + scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); + memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD)); - sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); - memset(sr_sizes, 0, sr_template.dev_max * sizeof(int)); + sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); + memset(sr_sizes, 0, sr_template.dev_max * sizeof(int)); - sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * - sizeof(int), GFP_ATOMIC); + sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * + sizeof(int), GFP_ATOMIC); - /* - * These are good guesses for the time being. - */ - for(i=0;ichanged = 1; /* force recheck CD type */ + for (i = 0; i < sr_template.nr_dev; ++i) { + /* If we have already seen this, then skip it. Comes up + * with loadable modules. */ + if (scsi_CDs[i].capacity) + continue; + scsi_CDs[i].capacity = 0x1fffff; + scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ + scsi_CDs[i].needs_sector_size = 1; + scsi_CDs[i].device->changed = 1; /* force recheck CD type */ #if 0 - /* seems better to leave this for later */ - get_sectorsize(i); - printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size); + /* seems better to leave this for later */ + get_sectorsize(i); + printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size); #endif - scsi_CDs[i].use = 1; - scsi_CDs[i].ten = 1; - scsi_CDs[i].remap = 1; - scsi_CDs[i].readcd_known = 0; - scsi_CDs[i].readcd_cdda = 0; - sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); - - scsi_CDs[i].cdi.ops = &sr_dops; - scsi_CDs[i].cdi.handle = &scsi_CDs[i]; - scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR,i); - scsi_CDs[i].cdi.mask = 0; - scsi_CDs[i].cdi.capacity = 1; - get_capabilities(i); - sr_vendor_init(i); - - sprintf(name, "sr%d", i); - strcpy(scsi_CDs[i].cdi.name, name); - register_cdrom(&scsi_CDs[i].cdi); - } - - - /* If our host adapter is capable of scatter-gather, then we increase - * the read-ahead to 16 blocks (32 sectors). If not, we use - * a two block (4 sector) read ahead. */ - if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize) - read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */ - else - read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */ + scsi_CDs[i].use = 1; + scsi_CDs[i].ten = 1; + scsi_CDs[i].remap = 1; + scsi_CDs[i].readcd_known = 0; + scsi_CDs[i].readcd_cdda = 0; + sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); + + scsi_CDs[i].cdi.ops = &sr_dops; + scsi_CDs[i].cdi.handle = &scsi_CDs[i]; + scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i); + scsi_CDs[i].cdi.mask = 0; + scsi_CDs[i].cdi.capacity = 1; + get_capabilities(i); + sr_vendor_init(i); + + sprintf(name, "sr%d", i); + strcpy(scsi_CDs[i].cdi.name, name); + register_cdrom(&scsi_CDs[i].cdi); + } + + + /* If our host adapter is capable of scatter-gather, then we increase + * the read-ahead to 16 blocks (32 sectors). If not, we use + * a two block (4 sector) read ahead. */ + if (scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize) + read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */ + else + read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */ - return; + return; } static void sr_detach(Scsi_Device * SDp) { - Scsi_CD * cpnt; - int i; + Scsi_CD *cpnt; + int i; - for(cpnt = scsi_CDs, i=0; idevice == SDp) { - kdev_t devi = MKDEV(MAJOR_NR, i); - struct super_block * sb = get_super(devi); - - /* - * Since the cdrom is read-only, no need to sync the device. - * We should be kind to our buffer cache, however. - */ - if (sb) invalidate_inodes(sb); - invalidate_buffers(devi); - - /* - * Reset things back to a sane state so that one can re-load a new - * driver (perhaps the same one). - */ - unregister_cdrom(&(cpnt->cdi)); - cpnt->device = NULL; - cpnt->capacity = 0; - SDp->attached--; - sr_template.nr_dev--; - sr_template.dev_noticed--; - sr_sizes[i] = 0; - return; - } - return; + for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++) + if (cpnt->device == SDp) { + kdev_t devi = MKDEV(MAJOR_NR, i); + struct super_block *sb = get_super(devi); + + /* + * Since the cdrom is read-only, no need to sync the device. + * We should be kind to our buffer cache, however. + */ + if (sb) + invalidate_inodes(sb); + invalidate_buffers(devi); + + /* + * Reset things back to a sane state so that one can re-load a new + * driver (perhaps the same one). + */ + unregister_cdrom(&(cpnt->cdi)); + cpnt->device = NULL; + cpnt->capacity = 0; + SDp->attached--; + sr_template.nr_dev--; + sr_template.dev_noticed--; + sr_sizes[i] = 0; + return; + } + return; } #ifdef MODULE -int init_module(void) { - sr_template.module = &__this_module; - return scsi_register_module(MODULE_SCSI_DEV, &sr_template); +int init_module(void) +{ + sr_template.module = &__this_module; + return scsi_register_module(MODULE_SCSI_DEV, &sr_template); } -void cleanup_module( void) +void cleanup_module(void) { - scsi_unregister_module(MODULE_SCSI_DEV, &sr_template); - unregister_blkdev(MAJOR_NR, "sr"); - sr_registered--; - if(scsi_CDs != NULL) { - scsi_init_free((char *) scsi_CDs, - (sr_template.dev_noticed + SR_EXTRA_DEVS) - * sizeof(Scsi_CD)); - - scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int)); - sr_sizes = NULL; - - scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int)); - sr_blocksizes = NULL; - } - - blksize_size[MAJOR_NR] = NULL; - blk_dev[MAJOR_NR].request_fn = NULL; - blk_size[MAJOR_NR] = NULL; - read_ahead[MAJOR_NR] = 0; + scsi_unregister_module(MODULE_SCSI_DEV, &sr_template); + unregister_blkdev(MAJOR_NR, "sr"); + sr_registered--; + if (scsi_CDs != NULL) { + scsi_init_free((char *) scsi_CDs, + (sr_template.dev_noticed + SR_EXTRA_DEVS) + * sizeof(Scsi_CD)); + + scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int)); + sr_sizes = NULL; - sr_template.dev_max = 0; + scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int)); + sr_blocksizes = NULL; + } + blksize_size[MAJOR_NR] = NULL; + blk_dev[MAJOR_NR].request_fn = NULL; + blk_size[MAJOR_NR] = NULL; + read_ahead[MAJOR_NR] = 0; + + sr_template.dev_max = 0; } -#endif /* MODULE */ + +#endif /* MODULE */ /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h --- v2.3.16/linux/drivers/scsi/sr.h Sat Jun 13 13:05:22 1998 +++ linux/drivers/scsi/sr.h Sat Sep 4 10:48:46 1999 @@ -3,11 +3,11 @@ * CD-ROM disk driver header file * * adapted from: - * sd.h Copyright (C) 1992 Drew Eckhardt - * SCSI disk driver header file by - * Drew Eckhardt + * sd.h Copyright (C) 1992 Drew Eckhardt + * SCSI disk driver header file by + * Drew Eckhardt * - * + * * * Modified by Eric Youngdale eric@aib.com to * add scatter-gather, multiple outstanding request, and other @@ -19,46 +19,45 @@ #include "scsi.h" -typedef struct - { - unsigned capacity; /* size in blocks */ - unsigned sector_size; /* size in bytes */ - Scsi_Device *device; - unsigned int vendor; /* vendor code, see sr_vendor.c */ - unsigned long ms_offset; /* for reading multisession-CD's */ - unsigned char sector_bit_size; /* sector size = 2^sector_bit_size */ - unsigned char sector_bit_shift; /* sectors/FS block = 2^sector_bit_shift*/ - unsigned needs_sector_size:1; /* needs to get sector size */ - unsigned ten:1; /* support ten byte commands */ - unsigned remap:1; /* support remapping */ - unsigned use:1; /* is this device still supportable */ - unsigned xa_flag:1; /* CD has XA sectors ? */ - unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ - unsigned readcd_cdda:1; /* reading audio data using READ_CD */ +typedef struct { + unsigned capacity; /* size in blocks */ + unsigned sector_size; /* size in bytes */ + Scsi_Device *device; + unsigned int vendor; /* vendor code, see sr_vendor.c */ + unsigned long ms_offset; /* for reading multisession-CD's */ + unsigned char sector_bit_size; /* sector size = 2^sector_bit_size */ + unsigned char sector_bit_shift; /* sectors/FS block = 2^sector_bit_shift */ + unsigned needs_sector_size:1; /* needs to get sector size */ + unsigned ten:1; /* support ten byte commands */ + unsigned remap:1; /* support remapping */ + unsigned use:1; /* is this device still supportable */ + unsigned xa_flag:1; /* CD has XA sectors ? */ + unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ + unsigned readcd_cdda:1; /* reading audio data using READ_CD */ struct cdrom_device_info cdi; - } Scsi_CD; - -extern Scsi_CD * scsi_CDs; - -int sr_do_ioctl(int, unsigned char*, void*, unsigned, int); - -int sr_lock_door(struct cdrom_device_info*, int); -int sr_tray_move(struct cdrom_device_info*, int); -int sr_drive_status(struct cdrom_device_info*, int); -int sr_disk_status(struct cdrom_device_info*); -int sr_get_last_session(struct cdrom_device_info*, struct cdrom_multisession*); -int sr_get_mcn(struct cdrom_device_info*, struct cdrom_mcn*); -int sr_reset(struct cdrom_device_info*); +} Scsi_CD; + +extern Scsi_CD *scsi_CDs; + +int sr_do_ioctl(int, unsigned char *, void *, unsigned, int); + +int sr_lock_door(struct cdrom_device_info *, int); +int sr_tray_move(struct cdrom_device_info *, int); +int sr_drive_status(struct cdrom_device_info *, int); +int sr_disk_status(struct cdrom_device_info *); +int sr_get_last_session(struct cdrom_device_info *, struct cdrom_multisession *); +int sr_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *); +int sr_reset(struct cdrom_device_info *); int sr_select_speed(struct cdrom_device_info *cdi, int speed); -int sr_audio_ioctl(struct cdrom_device_info*, unsigned int, void*); -int sr_dev_ioctl(struct cdrom_device_info*, unsigned int, unsigned long); +int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); +int sr_dev_ioctl(struct cdrom_device_info *, unsigned int, unsigned long); int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest); int sr_is_xa(int minor); /* sr_vendor.c */ void sr_vendor_init(int minor); -int sr_cd_check(struct cdrom_device_info*); +int sr_cd_check(struct cdrom_device_info *); int sr_set_blocklength(int minor, int blocklength); #endif diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c --- v2.3.16/linux/drivers/scsi/sr_vendor.c Mon May 10 13:01:21 1999 +++ linux/drivers/scsi/sr_vendor.c Sat Sep 4 10:48:46 1999 @@ -60,8 +60,7 @@ #define VENDOR_ID (scsi_CDs[minor].vendor) -void -sr_vendor_init(int minor) +void sr_vendor_init(int minor) { #ifndef CONFIG_BLK_DEV_SR_VENDOR VENDOR_ID = VENDOR_SCSI3; @@ -104,8 +103,7 @@ /* small handy function for switching block length using MODE SELECT, * used by sr_read_sector() */ -int -sr_set_blocklength(int minor, int blocklength) +int sr_set_blocklength(int minor, int blocklength) { unsigned char *buffer; /* the buffer for the ioctl */ unsigned char cmd[12]; /* the scsi-command */ diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.3.16/linux/drivers/scsi/st.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/scsi/st.c Sat Sep 4 10:48:46 1999 @@ -1,19 +1,19 @@ /* - SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying - file README.st for more information. + SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying + file README.st for more information. - History: - Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. - Contribution and ideas from several people including (in alphabetical - order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, - Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale. - - Copyright 1992 - 1999 Kai Makisara - email Kai.Makisara@metla.fi - - Last modified: Sat Aug 7 13:54:31 1999 by makisara@kai.makisara.local - Some small formal changes - aeb, 950809 -*/ + History: + Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. + Contribution and ideas from several people including (in alphabetical + order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, + Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale. + + Copyright 1992 - 1999 Kai Makisara + email Kai.Makisara@metla.fi + + Last modified: Sat Aug 7 13:54:31 1999 by makisara@kai.makisara.local + Some small formal changes - aeb, 950809 + */ #include @@ -67,14 +67,25 @@ MODULE_PARM(max_buffers, "i"); MODULE_PARM(max_sg_segs, "i"); #else + static struct st_dev_parm { - char *name; - int *val; + char *name; + int *val; } parms[] __initdata = { - {"buffer_kbs", &buffer_kbs}, - {"write_threshold_kbs", &write_threshold_kbs}, - {"max_buffers", &max_buffers}, - {"max_sg_segs", &max_sg_segs}}; + { + "buffer_kbs", &buffer_kbs + }, + { + "write_threshold_kbs", &write_threshold_kbs + }, + { + "max_buffers", &max_buffers + }, + { + "max_sg_segs", &max_sg_segs + } +}; + #endif @@ -115,7 +126,7 @@ static int st_max_buffers = ST_MAX_BUFFERS; static int st_max_sg_segs = ST_MAX_SG; -static Scsi_Tape * scsi_tapes = NULL; +static Scsi_Tape *scsi_tapes = NULL; static int modes_defined = FALSE; @@ -130,142 +141,137 @@ static int st_detect(Scsi_Device *); static void st_detach(Scsi_Device *); -struct Scsi_Device_Template st_template = {NULL, "tape", "st", NULL, TYPE_TAPE, - SCSI_TAPE_MAJOR, 0, 0, 0, 0, - st_detect, st_init, - NULL, st_attach, st_detach}; +struct Scsi_Device_Template st_template = +{NULL, "tape", "st", NULL, TYPE_TAPE, + SCSI_TAPE_MAJOR, 0, 0, 0, 0, + st_detect, st_init, + NULL, st_attach, st_detach}; static int st_compression(Scsi_Tape *, int); static int find_partition(struct inode *); static int update_partition(struct inode *); -static int st_int_ioctl(struct inode * inode, unsigned int cmd_in, +static int st_int_ioctl(struct inode *inode, unsigned int cmd_in, unsigned long arg); + - /* Convert the result to success code */ - static int -st_chk_result(Scsi_Cmnd * SCpnt) +static int st_chk_result(Scsi_Cmnd * SCpnt) { - int dev = TAPE_NR(SCpnt->request.rq_dev); - int result = SCpnt->result; - unsigned char * sense = SCpnt->sense_buffer, scode; -#if DEBUG - const char *stp; -#endif - - if (!result /* && SCpnt->sense_buffer[0] == 0 */ ) - return 0; - - if (driver_byte(result) & DRIVER_SENSE) - scode = sense[2] & 0x0f; - else { - sense[0] = 0; /* We don't have sense data if this byte is zero */ - scode = 0; - } - -#if DEBUG - if (debugging) { - printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", - dev, result, - SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2], - SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5], - SCpnt->request_bufflen); - if (driver_byte(result) & DRIVER_SENSE) - print_sense("st", SCpnt); - } - else -#endif - if (!(driver_byte(result) & DRIVER_SENSE) || - ((sense[0] & 0x70) == 0x70 && - scode != NO_SENSE && - scode != RECOVERED_ERROR && -/* scode != UNIT_ATTENTION && */ - scode != BLANK_CHECK && - scode != VOLUME_OVERFLOW && - SCpnt->data_cmnd[0] != MODE_SENSE && - SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ - if (driver_byte(result) & DRIVER_SENSE) { - printk(KERN_WARNING "st%d: Error with sense data: ", dev); - print_sense("st", SCpnt); - } - else - printk(KERN_WARNING - "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", - dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK, - host_byte(result)); - } + int dev = TAPE_NR(SCpnt->request.rq_dev); + int result = SCpnt->result; + unsigned char *sense = SCpnt->sense_buffer, scode; +#if DEBUG + const char *stp; +#endif + + if (!result /* && SCpnt->sense_buffer[0] == 0 */ ) + return 0; + + if (driver_byte(result) & DRIVER_SENSE) + scode = sense[2] & 0x0f; + else { + sense[0] = 0; /* We don't have sense data if this byte is zero */ + scode = 0; + } - if ((sense[0] & 0x70) == 0x70 && - scode == RECOVERED_ERROR +#if DEBUG + if (debugging) { + printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", + dev, result, + SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2], + SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5], + SCpnt->request_bufflen); + if (driver_byte(result) & DRIVER_SENSE) + print_sense("st", SCpnt); + } else +#endif + if (!(driver_byte(result) & DRIVER_SENSE) || + ((sense[0] & 0x70) == 0x70 && + scode != NO_SENSE && + scode != RECOVERED_ERROR && +/* scode != UNIT_ATTENTION && */ + scode != BLANK_CHECK && + scode != VOLUME_OVERFLOW && + SCpnt->data_cmnd[0] != MODE_SENSE && + SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ + if (driver_byte(result) & DRIVER_SENSE) { + printk(KERN_WARNING "st%d: Error with sense data: ", dev); + print_sense("st", SCpnt); + } else + printk(KERN_WARNING + "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", + dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK, + host_byte(result)); + } + if ((sense[0] & 0x70) == 0x70 && + scode == RECOVERED_ERROR #if ST_RECOVERED_WRITE_FATAL - && SCpnt->data_cmnd[0] != WRITE_6 - && SCpnt->data_cmnd[0] != WRITE_FILEMARKS + && SCpnt->data_cmnd[0] != WRITE_6 + && SCpnt->data_cmnd[0] != WRITE_FILEMARKS #endif - ) { - scsi_tapes[dev].recover_count++; - scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT); -#if DEBUG - if (debugging) { - if (SCpnt->data_cmnd[0] == READ_6) - stp = "read"; - else if (SCpnt->data_cmnd[0] == WRITE_6) - stp = "write"; - else - stp = "ioctl"; - printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp, - scsi_tapes[dev].recover_count); - } -#endif - if ((sense[2] & 0xe0) == 0) - return 0; - } - return (-EIO); + ) { + scsi_tapes[dev].recover_count++; + scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT); +#if DEBUG + if (debugging) { + if (SCpnt->data_cmnd[0] == READ_6) + stp = "read"; + else if (SCpnt->data_cmnd[0] == WRITE_6) + stp = "write"; + else + stp = "ioctl"; + printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp, + scsi_tapes[dev].recover_count); + } +#endif + if ((sense[2] & 0xe0) == 0) + return 0; + } + return (-EIO); } /* Wakeup from interrupt */ - static void -st_sleep_done (Scsi_Cmnd * SCpnt) +static void st_sleep_done(Scsi_Cmnd * SCpnt) { - unsigned int st_nbr; - int remainder; - Scsi_Tape * STp; - - if ((st_nbr = TAPE_NR(SCpnt->request.rq_dev)) < st_template.nr_dev) { - STp = &(scsi_tapes[st_nbr]); - if ((STp->buffer)->writing && - (SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x40)) { - /* EOM at write-behind, has all been written? */ - if ((SCpnt->sense_buffer[0] & 0x80) != 0) - remainder = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; - else - remainder = 0; - if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW || - remainder > 0) - (STp->buffer)->last_result = SCpnt->result; /* Error */ - else - (STp->buffer)->last_result = INT_MAX; /* OK */ - } - else - (STp->buffer)->last_result = SCpnt->result; - SCpnt->request.rq_status = RQ_SCSI_DONE; - (STp->buffer)->last_SCpnt = SCpnt; + unsigned int st_nbr; + int remainder; + Scsi_Tape *STp; + + if ((st_nbr = TAPE_NR(SCpnt->request.rq_dev)) < st_template.nr_dev) { + STp = &(scsi_tapes[st_nbr]); + if ((STp->buffer)->writing && + (SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x40)) { + /* EOM at write-behind, has all been written? */ + if ((SCpnt->sense_buffer[0] & 0x80) != 0) + remainder = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + else + remainder = 0; + if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW || + remainder > 0) + (STp->buffer)->last_result = SCpnt->result; /* Error */ + else + (STp->buffer)->last_result = INT_MAX; /* OK */ + } else + (STp->buffer)->last_result = SCpnt->result; + SCpnt->request.rq_status = RQ_SCSI_DONE; + (STp->buffer)->last_SCpnt = SCpnt; #if DEBUG - STp->write_pending = 0; + STp->write_pending = 0; #endif - up(SCpnt->request.sem); - } + up(SCpnt->request.sem); + } #if DEBUG - else if (debugging) - printk(KERN_ERR "st?: Illegal interrupt device %x\n", st_nbr); + else if (debugging) + printk(KERN_ERR "st?: Illegal interrupt device %x\n", st_nbr); #endif } @@ -273,2462 +279,2351 @@ /* Do the scsi command. Waits until command performed if do_wait is true. Otherwise write_behind_check() is used to check that the command has finished. */ - static Scsi_Cmnd * -st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes, - int timeout, int retries, int do_wait) -{ - unsigned long flags; - unsigned char *bp; - - spin_lock_irqsave(&io_request_lock, flags); - if (SCpnt == NULL) - if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) { - printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt)); - spin_unlock_irqrestore(&io_request_lock, flags); - return NULL; - } - - cmd[1] |= (SCpnt->lun << 5) & 0xe0; - init_MUTEX_LOCKED(&STp->sem); - SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ? - (STp->buffer)->use_sg : 0; - if (SCpnt->use_sg) { - bp = (char *)&((STp->buffer)->sg[0]); - if ((STp->buffer)->sg_segs < SCpnt->use_sg) - SCpnt->use_sg = (STp->buffer)->sg_segs; - } - else - bp = (STp->buffer)->b_data; - SCpnt->cmd_len = 0; - SCpnt->request.sem = &(STp->sem); - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.rq_dev = STp->devt; - - scsi_do_cmd(SCpnt, (void *)cmd, bp, bytes, - st_sleep_done, timeout, retries); - spin_unlock_irqrestore(&io_request_lock, flags); - - if (do_wait) { - down(SCpnt->request.sem); +static Scsi_Cmnd * + st_do_scsi(Scsi_Cmnd * SCpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes, + int timeout, int retries, int do_wait) +{ + unsigned long flags; + unsigned char *bp; + + spin_lock_irqsave(&io_request_lock, flags); + if (SCpnt == NULL) + if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) { + printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt)); + spin_unlock_irqrestore(&io_request_lock, flags); + return NULL; + } + cmd[1] |= (SCpnt->lun << 5) & 0xe0; + init_MUTEX_LOCKED(&STp->sem); + SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ? + (STp->buffer)->use_sg : 0; + if (SCpnt->use_sg) { + bp = (char *) &((STp->buffer)->sg[0]); + if ((STp->buffer)->sg_segs < SCpnt->use_sg) + SCpnt->use_sg = (STp->buffer)->sg_segs; + } else + bp = (STp->buffer)->b_data; + SCpnt->cmd_len = 0; + SCpnt->request.sem = &(STp->sem); + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.rq_dev = STp->devt; + + scsi_do_cmd(SCpnt, (void *) cmd, bp, bytes, + st_sleep_done, timeout, retries); + spin_unlock_irqrestore(&io_request_lock, flags); - (STp->buffer)->last_result_fatal = st_chk_result(SCpnt); - } + if (do_wait) { + down(SCpnt->request.sem); - return SCpnt; + (STp->buffer)->last_result_fatal = st_chk_result(SCpnt); + } + return SCpnt; } /* Handle the write-behind checking (downs the semaphore) */ - static void -write_behind_check(Scsi_Tape *STp) +static void write_behind_check(Scsi_Tape * STp) { - ST_buffer * STbuffer; - ST_partstat * STps; + ST_buffer *STbuffer; + ST_partstat *STps; - STbuffer = STp->buffer; + STbuffer = STp->buffer; #if DEBUG - if (STp->write_pending) - STp->nbr_waits++; - else - STp->nbr_finished++; + if (STp->write_pending) + STp->nbr_waits++; + else + STp->nbr_finished++; #endif - down(&(STp->sem)); + down(&(STp->sem)); - (STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt); - scsi_release_command((STp->buffer)->last_SCpnt); + (STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt); + scsi_release_command((STp->buffer)->last_SCpnt); - if (STbuffer->writing < STbuffer->buffer_bytes) + if (STbuffer->writing < STbuffer->buffer_bytes) #if 0 - memcpy(STbuffer->b_data, - STbuffer->b_data + STbuffer->writing, - STbuffer->buffer_bytes - STbuffer->writing); + memcpy(STbuffer->b_data, + STbuffer->b_data + STbuffer->writing, + STbuffer->buffer_bytes - STbuffer->writing); #else - printk(KERN_WARNING "st: write_behind_check: something left in buffer!\n"); + printk(KERN_WARNING "st: write_behind_check: something left in buffer!\n"); #endif - STbuffer->buffer_bytes -= STbuffer->writing; - STps = &(STp->ps[STp->partition]); - if (STps->drv_block >= 0) { - if (STp->block_size == 0) - STps->drv_block++; - else - STps->drv_block += STbuffer->writing / STp->block_size; - } - STbuffer->writing = 0; + STbuffer->buffer_bytes -= STbuffer->writing; + STps = &(STp->ps[STp->partition]); + if (STps->drv_block >= 0) { + if (STp->block_size == 0) + STps->drv_block++; + else + STps->drv_block += STbuffer->writing / STp->block_size; + } + STbuffer->writing = 0; - return; + return; } /* Step over EOF if it has been inadvertently crossed (ioctl not used because it messes up the block number). */ - static int -cross_eof(Scsi_Tape *STp, int forward) +static int cross_eof(Scsi_Tape * STp, int forward) { - Scsi_Cmnd *SCpnt; - unsigned char cmd[10]; + Scsi_Cmnd *SCpnt; + unsigned char cmd[10]; - cmd[0] = SPACE; - cmd[1] = 0x01; /* Space FileMarks */ - if (forward) { - cmd[2] = cmd[3] = 0; - cmd[4] = 1; - } - else - cmd[2] = cmd[3] = cmd[4] = 0xff; /* -1 filemarks */ - cmd[5] = 0; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n", - TAPE_NR(STp->devt), forward ? "forward" : "backward"); -#endif - - SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE); - if (!SCpnt) - return (-EBUSY); - - scsi_release_command(SCpnt); - SCpnt = NULL; - - if ((STp->buffer)->last_result != 0) - printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n", - TAPE_NR(STp->devt), forward ? "forward" : "backward"); - - return (STp->buffer)->last_result_fatal; -} + cmd[0] = SPACE; + cmd[1] = 0x01; /* Space FileMarks */ + if (forward) { + cmd[2] = cmd[3] = 0; + cmd[4] = 1; + } else + cmd[2] = cmd[3] = cmd[4] = 0xff; /* -1 filemarks */ + cmd[5] = 0; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n", + TAPE_NR(STp->devt), forward ? "forward" : "backward"); +#endif + SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE); + if (!SCpnt) + return (-EBUSY); -/* Flush the write buffer (never need to write if variable blocksize). */ - static int -flush_write_buffer(Scsi_Tape *STp) -{ - int offset, transfer, blks; - int result; - unsigned char cmd[10]; - Scsi_Cmnd *SCpnt; - ST_partstat * STps; - - if ((STp->buffer)->writing) { - write_behind_check(STp); - if ((STp->buffer)->last_result_fatal) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Async write error (flush) %x.\n", - TAPE_NR(STp->devt), (STp->buffer)->last_result); -#endif - if ((STp->buffer)->last_result == INT_MAX) - return (-ENOSPC); - return (-EIO); - } - } - - if (STp->block_size == 0) - return 0; - - result = 0; - if (STp->dirty == 1) { - - offset = (STp->buffer)->buffer_bytes; - transfer = ((offset + STp->block_size - 1) / - STp->block_size) * STp->block_size; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Flushing %d bytes.\n", TAPE_NR(STp->devt), transfer); -#endif - memset((STp->buffer)->b_data + offset, 0, transfer - offset); - - memset(cmd, 0, 10); - cmd[0] = WRITE_6; - cmd[1] = 1; - blks = transfer / STp->block_size; - cmd[2] = blks >> 16; - cmd[3] = blks >> 8; - cmd[4] = blks; - - SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES, - TRUE); - if (!SCpnt) - return (-EBUSY); - - STps = &(STp->ps[STp->partition]); - if ((STp->buffer)->last_result_fatal != 0) { - if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x40) && - (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) { - STp->dirty = 0; - (STp->buffer)->buffer_bytes = 0; - result = (-ENOSPC); - } - else { - printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt)); - result = (-EIO); - } - STps->drv_block = (-1); - } - else { - if (STps->drv_block >= 0) - STps->drv_block += blks; - STp->dirty = 0; - (STp->buffer)->buffer_bytes = 0; - } - scsi_release_command(SCpnt); - SCpnt = NULL; - } - return result; -} + scsi_release_command(SCpnt); + SCpnt = NULL; + if ((STp->buffer)->last_result != 0) + printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n", + TAPE_NR(STp->devt), forward ? "forward" : "backward"); -/* Flush the tape buffer. The tape will be positioned correctly unless - seek_next is true. */ - static int -flush_buffer(struct inode * inode, struct file * filp, int seek_next) -{ - int backspace, result; - Scsi_Tape * STp; - ST_buffer * STbuffer; - ST_partstat * STps; - int dev = TAPE_NR(inode->i_rdev); - - STp = &(scsi_tapes[dev]); - STbuffer = STp->buffer; - - /* - * If there was a bus reset, block further access - * to this device. - */ - if( STp->device->was_reset ) - return (-EIO); - - if (STp->ready != ST_READY) - return 0; - - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING) /* Writing */ - return flush_write_buffer(STp); - - if (STp->block_size == 0) - return 0; - - backspace = ((STp->buffer)->buffer_bytes + - (STp->buffer)->read_pointer) / STp->block_size - - ((STp->buffer)->read_pointer + STp->block_size - 1) / - STp->block_size; - (STp->buffer)->buffer_bytes = 0; - (STp->buffer)->read_pointer = 0; - result = 0; - if (!seek_next) { - if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, FALSE); /* Back over the EOF hit */ - if (!result) - STps->eof = ST_NOEOF; - else { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - } - } - if (!result && backspace > 0) - result = st_int_ioctl(inode, MTBSR, backspace); - } - else if (STps->eof == ST_FM_HIT) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_NOEOF; - } - - return result; - -} - - /* Set the mode parameters */ - static int -set_mode_densblk(struct inode * inode, Scsi_Tape *STp, ST_mode *STm) -{ - int set_it = FALSE; - unsigned long arg; - int dev = TAPE_NR(inode->i_rdev); - - if (!STp->density_changed && - STm->default_density >= 0 && - STm->default_density != STp->density) { - arg = STm->default_density; - set_it = TRUE; - } - else - arg = STp->density; - arg <<= MT_ST_DENSITY_SHIFT; - if (!STp->blksize_changed && - STm->default_blksize >= 0 && - STm->default_blksize != STp->block_size) { - arg |= STm->default_blksize; - set_it = TRUE; - } - else - arg |= STp->block_size; - if (set_it && - st_int_ioctl(inode, SET_DENS_AND_BLK, arg)) { - printk(KERN_WARNING - "st%d: Can't set default block size to %d bytes and density %x.\n", - dev, STm->default_blksize, STm->default_density); - if (modes_defined) - return (-EINVAL); - } - return 0; + return (STp->buffer)->last_result_fatal; } - -/* Open the device */ - static int -scsi_tape_open(struct inode * inode, struct file * filp) + +/* Flush the write buffer (never need to write if variable blocksize). */ +static int flush_write_buffer(Scsi_Tape * STp) { - unsigned short flags; - int i, need_dma_buffer, new_session = FALSE; - unsigned char cmd[10]; - Scsi_Cmnd * SCpnt; - Scsi_Tape * STp; - ST_mode * STm; - ST_partstat * STps; - int dev = TAPE_NR(inode->i_rdev); - int mode = TAPE_MODE(inode->i_rdev); - - if (dev >= st_template.dev_max || !scsi_tapes[dev].device) - return (-ENXIO); - - if( !scsi_block_when_processing_errors(scsi_tapes[dev].device) ) { - return -ENXIO; - } - - STp = &(scsi_tapes[dev]); - if (STp->in_use) { -#if DEBUG - printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); -#endif - return (-EBUSY); - } - STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0; - - if (mode != STp->current_mode) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", - dev, STp->current_mode, mode); -#endif - new_session = TRUE; - STp->current_mode = mode; - } - STm = &(STp->modes[STp->current_mode]); - - /* Allocate a buffer for this user */ - need_dma_buffer = STp->restr_dma; - for (i=0; i < st_nbr_buffers; i++) - if (!st_buffers[i]->in_use && - (!need_dma_buffer || st_buffers[i]->dma)) - break; - if (i >= st_nbr_buffers) { - STp->buffer = new_tape_buffer(FALSE, need_dma_buffer); - if (STp->buffer == NULL) { - printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev); - return (-EBUSY); - } - } - else - STp->buffer = st_buffers[i]; - (STp->buffer)->in_use = 1; - (STp->buffer)->writing = 0; - (STp->buffer)->last_result_fatal = 0; - (STp->buffer)->use_sg = STp->device->host->sg_tablesize; - - /* Compute the usable buffer size for this SCSI adapter */ - if (!(STp->buffer)->use_sg) - (STp->buffer)->buffer_size = (STp->buffer)->sg[0].length; - else { - for (i=0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg && - i < (STp->buffer)->sg_segs; i++) - (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length; - } - - flags = filp->f_flags; - STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); - - STp->dirty = 0; - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - } - STp->ready = ST_READY; - STp->recover_count = 0; -#if DEBUG - STp->nbr_waits = STp->nbr_finished = 0; -#endif - - if (scsi_tapes[dev].device->host->hostt->module) - __MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); - if(st_template.module) - __MOD_INC_USE_COUNT(st_template.module); - - memset ((void *) &cmd[0], 0, 10); - cmd[0] = TEST_UNIT_READY; - - SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES, - TRUE); - if (!SCpnt) { - if (scsi_tapes[dev].device->host->hostt->module) - __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); - if(st_template.module) - __MOD_DEC_USE_COUNT(st_template.module); - return (-EBUSY); - } - - if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ - memset ((void *) &cmd[0], 0, 10); - cmd[0] = TEST_UNIT_READY; - - SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES, - TRUE); - - (STp->device)->was_reset = 0; - STp->partition = STp->new_partition = 0; - if (STp->can_partitions) - STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = FALSE; - STps->drv_block = 0; - STps->drv_file = 0 ; - } - new_session = TRUE; - } - - if ((STp->buffer)->last_result_fatal != 0) { - if ((STp->device)->scsi_level >= SCSI_2 && - (SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY && - SCpnt->sense_buffer[12] == 0x3a) { /* Check ASC */ - STp->ready = ST_NO_TAPE; - } else - STp->ready = ST_NOT_READY; - scsi_release_command(SCpnt); - SCpnt = NULL; - STp->density = 0; /* Clear the erroneous "residue" */ - STp->write_prot = 0; - STp->block_size = 0; - STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); - STp->partition = STp->new_partition = 0; - STp->door_locked = ST_UNLOCKED; - STp->in_use = 1; - return 0; - } - - if (STp->omit_blklims) - STp->min_block = STp->max_block = (-1); - else { - memset ((void *) &cmd[0], 0, 10); - cmd[0] = READ_BLOCK_LIMITS; - - SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES, TRUE); - - if (!SCpnt->result && !SCpnt->sense_buffer[0]) { - STp->max_block = ((STp->buffer)->b_data[1] << 16) | - ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; - STp->min_block = ((STp->buffer)->b_data[4] << 8) | - (STp->buffer)->b_data[5]; + int offset, transfer, blks; + int result; + unsigned char cmd[10]; + Scsi_Cmnd *SCpnt; + ST_partstat *STps; + + if ((STp->buffer)->writing) { + write_behind_check(STp); + if ((STp->buffer)->last_result_fatal) { #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block, - STp->max_block); + if (debugging) + printk(ST_DEB_MSG "st%d: Async write error (flush) %x.\n", + TAPE_NR(STp->devt), (STp->buffer)->last_result); #endif - } - else { - STp->min_block = STp->max_block = (-1); + if ((STp->buffer)->last_result == INT_MAX) + return (-ENOSPC); + return (-EIO); + } + } + if (STp->block_size == 0) + return 0; + + result = 0; + if (STp->dirty == 1) { + + offset = (STp->buffer)->buffer_bytes; + transfer = ((offset + STp->block_size - 1) / + STp->block_size) * STp->block_size; #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev); + if (debugging) + printk(ST_DEB_MSG "st%d: Flushing %d bytes.\n", TAPE_NR(STp->devt), transfer); #endif - } - } + memset((STp->buffer)->b_data + offset, 0, transfer - offset); + + memset(cmd, 0, 10); + cmd[0] = WRITE_6; + cmd[1] = 1; + blks = transfer / STp->block_size; + cmd[2] = blks >> 16; + cmd[3] = blks >> 8; + cmd[4] = blks; + + SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES, + TRUE); + if (!SCpnt) + return (-EBUSY); + + STps = &(STp->ps[STp->partition]); + if ((STp->buffer)->last_result_fatal != 0) { + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x40) && + (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) { + STp->dirty = 0; + (STp->buffer)->buffer_bytes = 0; + result = (-ENOSPC); + } else { + printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt)); + result = (-EIO); + } + STps->drv_block = (-1); + } else { + if (STps->drv_block >= 0) + STps->drv_block += blks; + STp->dirty = 0; + (STp->buffer)->buffer_bytes = 0; + } + scsi_release_command(SCpnt); + SCpnt = NULL; + } + return result; +} - memset ((void *) &cmd[0], 0, 10); - cmd[0] = MODE_SENSE; - cmd[4] = 12; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE); +/* Flush the tape buffer. The tape will be positioned correctly unless + seek_next is true. */ +static int flush_buffer(struct inode *inode, struct file *filp, int seek_next) +{ + int backspace, result; + Scsi_Tape *STp; + ST_buffer *STbuffer; + ST_partstat *STps; + int dev = TAPE_NR(inode->i_rdev); + + STp = &(scsi_tapes[dev]); + STbuffer = STp->buffer; + + /* + * If there was a bus reset, block further access + * to this device. + */ + if (STp->device->was_reset) + return (-EIO); - if ((STp->buffer)->last_result_fatal != 0) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev); -#endif - STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */ - (STp->buffer)->last_result_fatal = 0; /* Prevent error propagation */ - STp->drv_write_prot = 0; - } - else { + if (STp->ready != ST_READY) + return 0; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", - dev, - (STp->buffer)->b_data[0], (STp->buffer)->b_data[1], - (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]); -#endif + STps = &(STp->ps[STp->partition]); + if (STps->rw == ST_WRITING) /* Writing */ + return flush_write_buffer(STp); - if ((STp->buffer)->b_data[3] >= 8) { - STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7; - STp->density = (STp->buffer)->b_data[4]; - STp->block_size = (STp->buffer)->b_data[9] * 65536 + - (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Density %x, tape length: %x, drv buffer: %d\n", - dev, STp->density, (STp->buffer)->b_data[5] * 65536 + - (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7], - STp->drv_buffer); -#endif - } - - 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_command(SCpnt); - (STp->buffer)->in_use = 0; - STp->buffer = NULL; - if (scsi_tapes[dev].device->host->hostt->module) - __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); - if(st_template.module) - __MOD_DEC_USE_COUNT(st_template.module); - return (-EIO); - } - STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; - } - scsi_release_command(SCpnt); - SCpnt = NULL; - - if (STp->block_size > 0) - (STp->buffer)->buffer_blocks = (STp->buffer)->buffer_size / STp->block_size; - else - (STp->buffer)->buffer_blocks = 1; - (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; - -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev, - STp->block_size, (STp->buffer)->buffer_size, - (STp->buffer)->buffer_blocks); -#endif - - if (STp->drv_write_prot) { - STp->write_prot = 1; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Write protected\n", dev); -#endif - if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { - (STp->buffer)->in_use = 0; - STp->buffer = NULL; - if (scsi_tapes[dev].device->host->hostt->module) - __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); - if(st_template.module) - __MOD_DEC_USE_COUNT(st_template.module); - return (-EROFS); - } - } - - if (STp->can_partitions && STp->nbr_partitions < 1) { - /* This code is reached when the device is opened for the first time - after the driver has been initialized with tape in the drive and the - partition support has been enabled. */ -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Updating partition number in status.\n", dev); -#endif - if ((STp->partition = find_partition(inode)) < 0) { - (STp->buffer)->in_use = 0; - STp->buffer = NULL; - if (scsi_tapes[dev].device->host->hostt->module) - __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); - if(st_template.module) - __MOD_DEC_USE_COUNT(st_template.module); - return STp->partition; - } - STp->new_partition = STp->partition; - STp->nbr_partitions = 1; /* This guess will be updated when necessary */ - } - - if (new_session) { /* Change the drive parameters for the new mode */ - STp->density_changed = STp->blksize_changed = FALSE; - STp->compression_changed = FALSE; - if (!(STm->defaults_for_writes) && - (i = set_mode_densblk(inode, STp, STm)) < 0) { - (STp->buffer)->in_use = 0; - STp->buffer = NULL; - if (scsi_tapes[dev].device->host->hostt->module) - __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); - if(st_template.module) - __MOD_DEC_USE_COUNT(st_template.module); - return i; - } - if (STp->default_drvbuffer != 0xff) { - if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer)) - printk(KERN_WARNING "st%d: Can't set default drive buffering to %d.\n", - dev, STp->default_drvbuffer); - } - } + if (STp->block_size == 0) + return 0; - STp->in_use = 1; + backspace = ((STp->buffer)->buffer_bytes + + (STp->buffer)->read_pointer) / STp->block_size - + ((STp->buffer)->read_pointer + STp->block_size - 1) / + STp->block_size; + (STp->buffer)->buffer_bytes = 0; + (STp->buffer)->read_pointer = 0; + result = 0; + if (!seek_next) { + if (STps->eof == ST_FM_HIT) { + result = cross_eof(STp, FALSE); /* Back over the EOF hit */ + if (!result) + STps->eof = ST_NOEOF; + else { + if (STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + } + } + if (!result && backspace > 0) + result = st_int_ioctl(inode, MTBSR, backspace); + } else if (STps->eof == ST_FM_HIT) { + if (STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + STps->eof = ST_NOEOF; + } + return result; - return 0; } - -/* Flush the tape buffer before close */ - static int -scsi_tape_flush(struct file * filp) +/* Set the mode parameters */ +static int set_mode_densblk(struct inode *inode, Scsi_Tape * STp, ST_mode * STm) { - int result = 0, result2; - static unsigned char cmd[10]; - Scsi_Cmnd * SCpnt; - Scsi_Tape * STp; - ST_mode * STm; - ST_partstat * STps; - - struct inode *inode = filp->f_dentry->d_inode; - kdev_t devt = inode->i_rdev; - int dev; - - if (file_count(filp) > 1) + int set_it = FALSE; + unsigned long arg; + int dev = TAPE_NR(inode->i_rdev); + + if (!STp->density_changed && + STm->default_density >= 0 && + STm->default_density != STp->density) { + arg = STm->default_density; + set_it = TRUE; + } else + arg = STp->density; + arg <<= MT_ST_DENSITY_SHIFT; + if (!STp->blksize_changed && + STm->default_blksize >= 0 && + STm->default_blksize != STp->block_size) { + arg |= STm->default_blksize; + set_it = TRUE; + } else + arg |= STp->block_size; + if (set_it && + st_int_ioctl(inode, SET_DENS_AND_BLK, arg)) { + printk(KERN_WARNING + "st%d: Can't set default block size to %d bytes and density %x.\n", + dev, STm->default_blksize, STm->default_density); + if (modes_defined) + return (-EINVAL); + } return 0; +} + + +/* Open the device */ +static int scsi_tape_open(struct inode *inode, struct file *filp) +{ + unsigned short flags; + int i, need_dma_buffer, new_session = FALSE; + unsigned char cmd[10]; + Scsi_Cmnd *SCpnt; + Scsi_Tape *STp; + ST_mode *STm; + ST_partstat *STps; + int dev = TAPE_NR(inode->i_rdev); + int mode = TAPE_MODE(inode->i_rdev); - dev = TAPE_NR(devt); - STp = &(scsi_tapes[dev]); - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); + if (dev >= st_template.dev_max || !scsi_tapes[dev].device) + return (-ENXIO); + + if (!scsi_block_when_processing_errors(scsi_tapes[dev].device)) { + return -ENXIO; + } + STp = &(scsi_tapes[dev]); + if (STp->in_use) { +#if DEBUG + printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); +#endif + return (-EBUSY); + } + STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0; - if (STp->can_partitions && - (result = update_partition(inode)) < 0) { + if (mode != STp->current_mode) { #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: update_partition at close failed.\n", dev); + if (debugging) + printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", + dev, STp->current_mode, mode); #endif - goto out; - } + new_session = TRUE; + STp->current_mode = mode; + } + STm = &(STp->modes[STp->current_mode]); - if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) { + /* Allocate a buffer for this user */ + need_dma_buffer = STp->restr_dma; + for (i = 0; i < st_nbr_buffers; i++) + if (!st_buffers[i]->in_use && + (!need_dma_buffer || st_buffers[i]->dma)) + break; + if (i >= st_nbr_buffers) { + STp->buffer = new_tape_buffer(FALSE, need_dma_buffer); + if (STp->buffer == NULL) { + printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev); + return (-EBUSY); + } + } else + STp->buffer = st_buffers[i]; + (STp->buffer)->in_use = 1; + (STp->buffer)->writing = 0; + (STp->buffer)->last_result_fatal = 0; + (STp->buffer)->use_sg = STp->device->host->sg_tablesize; + + /* Compute the usable buffer size for this SCSI adapter */ + if (!(STp->buffer)->use_sg) + (STp->buffer)->buffer_size = (STp->buffer)->sg[0].length; + else { + for (i = 0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg && + i < (STp->buffer)->sg_segs; i++) + (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length; + } - result = flush_write_buffer(STp); + flags = filp->f_flags; + STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); + STp->dirty = 0; + for (i = 0; i < ST_NBR_PARTITIONS; i++) { + STps = &(STp->ps[i]); + STps->rw = ST_IDLE; + } + STp->ready = ST_READY; + STp->recover_count = 0; #if DEBUG - if (debugging) { - printk(ST_DEB_MSG "st%d: File length %ld bytes.\n", - dev, (long)(filp->f_pos)); - printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n", - dev, STp->nbr_waits, STp->nbr_finished); - } + STp->nbr_waits = STp->nbr_finished = 0; #endif - if (result == 0 || result == (-ENOSPC)) { + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if (st_template.module) + __MOD_INC_USE_COUNT(st_template.module); - memset(cmd, 0, 10); - cmd[0] = WRITE_FILEMARKS; - cmd[4] = 1 + STp->two_fm; + memset((void *) &cmd[0], 0, 10); + cmd[0] = TEST_UNIT_READY; - SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES, + SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES, TRUE); - if (!SCpnt) - goto out; - - if ((STp->buffer)->last_result_fatal != 0 && - ((SCpnt->sense_buffer[0] & 0x70) != 0x70 || - (SCpnt->sense_buffer[2] & 0x4f) != 0x40 || - ((SCpnt->sense_buffer[0] & 0x80) != 0 && - (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] | - SCpnt->sense_buffer[5] | - SCpnt->sense_buffer[6]) == 0))) { - /* Filter out successful write at EOM */ - scsi_release_command(SCpnt); - SCpnt = NULL; - printk(KERN_ERR "st%d: Error on write filemark.\n", dev); - if (result == 0) - result = (-EIO); + if (!SCpnt) { + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if (st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); + return (-EBUSY); } - else { - scsi_release_command(SCpnt); - SCpnt = NULL; - if (STps->drv_file >= 0) - STps->drv_file++ ; - STps->drv_block = 0; - if (STp->two_fm) - cross_eof(STp, FALSE); - STps->eof = ST_FM; - } - } - -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n", - dev, cmd[4]); -#endif - } - else if (!STp->rew_at_close) { - STps = &(STp->ps[STp->partition]); - if (!STm->sysv || STps->rw != ST_READING) { - if (STp->can_bsr) - result = flush_buffer(inode, filp, 0); - else if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, FALSE); - if (result) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ + memset((void *) &cmd[0], 0, 10); + cmd[0] = TEST_UNIT_READY; + + SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES, + TRUE); + + (STp->device)->was_reset = 0; + STp->partition = STp->new_partition = 0; + if (STp->can_partitions) + STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ + for (i = 0; i < ST_NBR_PARTITIONS; i++) { + STps = &(STp->ps[i]); + STps->rw = ST_IDLE; + STps->eof = ST_NOEOF; + STps->at_sm = 0; + STps->last_block_valid = FALSE; + STps->drv_block = 0; + STps->drv_file = 0; } - else - STps->eof = ST_NOEOF; - } + new_session = TRUE; } - else if ((STps->eof == ST_NOEOF && - !(result = cross_eof(STp, TRUE))) || - STps->eof == ST_FM_HIT) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } - } - -out: - if (STp->rew_at_close) { - result2 = st_int_ioctl(inode, MTREW, 1); - if (result == 0) - result = result2; - } - - return result; -} - - -/* Close the device and release it */ - static int -scsi_tape_close(struct inode * inode, struct file * filp) -{ - int result = 0; - Scsi_Tape * STp; - - kdev_t devt = inode->i_rdev; - int dev; - - dev = TAPE_NR(devt); - STp = &(scsi_tapes[dev]); - - if (STp->door_locked == ST_LOCKED_AUTO) - st_int_ioctl(inode, MTUNLOCK, 0); + if ((STp->buffer)->last_result_fatal != 0) { + if ((STp->device)->scsi_level >= SCSI_2 && + (SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY && + SCpnt->sense_buffer[12] == 0x3a) { /* Check ASC */ + STp->ready = ST_NO_TAPE; + } else + STp->ready = ST_NOT_READY; + scsi_release_command(SCpnt); + SCpnt = NULL; + STp->density = 0; /* Clear the erroneous "residue" */ + STp->write_prot = 0; + STp->block_size = 0; + STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); + STp->partition = STp->new_partition = 0; + STp->door_locked = ST_UNLOCKED; + STp->in_use = 1; + return 0; + } + if (STp->omit_blklims) + STp->min_block = STp->max_block = (-1); + else { + memset((void *) &cmd[0], 0, 10); + cmd[0] = READ_BLOCK_LIMITS; - if (STp->buffer != NULL) { - normalize_buffer(STp->buffer); - (STp->buffer)->in_use = 0; - } + SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES, TRUE); - STp->in_use = 0; - if (scsi_tapes[dev].device->host->hostt->module) - __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); - if(st_template.module) - __MOD_DEC_USE_COUNT(st_template.module); + if (!SCpnt->result && !SCpnt->sense_buffer[0]) { + STp->max_block = ((STp->buffer)->b_data[1] << 16) | + ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; + STp->min_block = ((STp->buffer)->b_data[4] << 8) | + (STp->buffer)->b_data[5]; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block, + STp->max_block); +#endif + } else { + STp->min_block = STp->max_block = (-1); +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev); +#endif + } + } - return result; -} + memset((void *) &cmd[0], 0, 10); + cmd[0] = MODE_SENSE; + cmd[4] = 12; - -/* Write command */ -static ssize_t -st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos) -{ - struct inode *inode = filp->f_dentry->d_inode; - ssize_t total; - ssize_t i, do_count, blks, retval, transfer; - int write_threshold; - int doing_write = 0; - static unsigned char cmd[10]; - const char *b_point; - Scsi_Cmnd * SCpnt = NULL; - Scsi_Tape * STp; - ST_mode * STm; - ST_partstat * STps; - int dev = TAPE_NR(inode->i_rdev); - - STp = &(scsi_tapes[dev]); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(STp->device) ) { - return -ENXIO; - } - - if (ppos != &filp->f_pos) { - /* "A request was outside the capabilities of the device." */ - return -ENXIO; - } - - if (STp->ready != ST_READY) { - if (STp->ready == ST_NO_TAPE) - return (-ENOMEDIUM); - else - return (-EIO); - } - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) - return (-ENXIO); - if (count == 0) - return 0; - - /* - * If there was a bus reset, block further access - * to this device. - */ - if( STp->device->was_reset ) - return (-EIO); - -#if DEBUG - if (!STp->in_use) { - printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); - return (-EIO); - } -#endif - - /* 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); - } + SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE); - if (STp->can_partitions && - (retval = update_partition(inode)) < 0) - return retval; - STps = &(STp->ps[STp->partition]); - - if (STp->write_prot) - return (-EACCES); - - if (STp->block_size == 0 && - count > (STp->buffer)->buffer_size && - !enlarge_buffer(STp->buffer, count, STp->restr_dma)) - return (-EOVERFLOW); - - if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && - !st_int_ioctl(inode, MTLOCK, 0)) - STp->door_locked = ST_LOCKED_AUTO; - - if (STps->rw == ST_READING) { - retval = flush_buffer(inode, filp, 0); - if (retval) - return retval; - STps->rw = ST_WRITING; - } - else if (STps->rw != ST_WRITING && - STps->drv_file == 0 && STps->drv_block == 0) { - if ((retval = set_mode_densblk(inode, STp, STm)) < 0) - return retval; - 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 ((STp->buffer)->writing) { - write_behind_check(STp); - if ((STp->buffer)->last_result_fatal) { + if ((STp->buffer)->last_result_fatal != 0) { #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", dev, - (STp->buffer)->last_result); -#endif - if ((STp->buffer)->last_result == INT_MAX) - STps->eof = ST_EOM_OK; - else - STps->eof = ST_EOM_ERROR; - } - } - if (STps->eof == ST_EOM_OK) - return (-ENOSPC); - else if (STps->eof == ST_EOM_ERROR) - return (-EIO); - - /* 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); - - 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 (debugging) + printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev); #endif - write_threshold = 1; - } - else - write_threshold = (STp->buffer)->buffer_blocks * STp->block_size; - if (!STm->do_async_writes) - write_threshold--; - - total = count; - - memset(cmd, 0, 10); - cmd[0] = WRITE_6; - cmd[1] = (STp->block_size != 0); - - STps->rw = ST_WRITING; - - b_point = buf; - while ((STp->block_size == 0 && !STm->do_async_writes && count > 0) || - (STp->block_size != 0 && - (STp->buffer)->buffer_bytes + count > write_threshold)) - { - doing_write = 1; - if (STp->block_size == 0) - do_count = count; - else { - do_count = (STp->buffer)->buffer_blocks * STp->block_size - - (STp->buffer)->buffer_bytes; - if (do_count > count) - do_count = count; - } - - i = append_to_buffer(b_point, STp->buffer, do_count); - if (i) { - if (SCpnt != NULL) { - scsi_release_command(SCpnt); - SCpnt = NULL; - } - return i; - } - - if (STp->block_size == 0) - blks = transfer = do_count; - else { - blks = (STp->buffer)->buffer_bytes / - STp->block_size; - transfer = blks * STp->block_size; - } - cmd[2] = blks >> 16; - cmd[3] = blks >> 8; - cmd[4] = blks; - - SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout, - MAX_WRITE_RETRIES, TRUE); - if (!SCpnt) - return (-EBUSY); + STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */ + (STp->buffer)->last_result_fatal = 0; /* Prevent error propagation */ + STp->drv_write_prot = 0; + } else { - if ((STp->buffer)->last_result_fatal != 0) { #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Error on write:\n", dev); + if (debugging) + printk(ST_DEB_MSG "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", + dev, + (STp->buffer)->b_data[0], (STp->buffer)->b_data[1], + (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]); #endif - if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x40)) { - if (STp->block_size != 0 && (SCpnt->sense_buffer[0] & 0x80) != 0) - transfer = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; - else if (STp->block_size == 0 && - (SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW) - transfer = do_count; - else - transfer = 0; - if (STp->block_size != 0) - transfer *= STp->block_size; - if (transfer <= do_count) { - filp->f_pos += do_count - transfer; - count -= do_count - transfer; - if (STps->drv_block >= 0) { - if (STp->block_size == 0 && transfer < do_count) - STps->drv_block++; - else if (STp->block_size != 0) - STps->drv_block += (do_count - transfer) / STp->block_size; - } - STps->eof = ST_EOM_OK; - retval = (-ENOSPC); /* EOM within current request */ -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: EOM with %d bytes unwritten.\n", - dev, transfer); -#endif - } - else { - STps->eof = ST_EOM_ERROR; - STps->drv_block = (-1); /* Too cautious? */ - retval = (-EIO); /* EOM for old data */ + + if ((STp->buffer)->b_data[3] >= 8) { + STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7; + STp->density = (STp->buffer)->b_data[4]; + STp->block_size = (STp->buffer)->b_data[9] * 65536 + + (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]; #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: EOM with lost data.\n", dev); + if (debugging) + printk(ST_DEB_MSG "st%d: Density %x, tape length: %x, drv buffer: %d\n", + dev, STp->density, (STp->buffer)->b_data[5] * 65536 + + (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7], + STp->drv_buffer); #endif - } - } - else { - STps->drv_block = (-1); /* Too cautious? */ - retval = (-EIO); + } + 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_command(SCpnt); + (STp->buffer)->in_use = 0; + STp->buffer = NULL; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if (st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); + return (-EIO); + } + STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; } - - scsi_release_command(SCpnt); - SCpnt = NULL; - (STp->buffer)->buffer_bytes = 0; - STp->dirty = 0; - if (count < total) - return total - count; - else - return retval; - } - filp->f_pos += do_count; - b_point += do_count; - count -= do_count; - if (STps->drv_block >= 0) { - if (STp->block_size == 0) - STps->drv_block++; - else - STps->drv_block += blks; - } - (STp->buffer)->buffer_bytes = 0; - STp->dirty = 0; - } - if (count != 0) { - STp->dirty = 1; - i = append_to_buffer(b_point, STp->buffer, count); - if (i) { - if (SCpnt != NULL) { - scsi_release_command(SCpnt); - SCpnt = NULL; - } - return i; - } - filp->f_pos += count; - count = 0; - } - - if (doing_write && (STp->buffer)->last_result_fatal != 0) { - scsi_release_command(SCpnt); - SCpnt = NULL; - return (STp->buffer)->last_result_fatal; - } - - if (STm->do_async_writes && - (((STp->buffer)->buffer_bytes >= STp->write_threshold && - (STp->buffer)->buffer_bytes >= STp->block_size) || - STp->block_size == 0) ) { - /* Schedule an asynchronous write */ - if (STp->block_size == 0) - (STp->buffer)->writing = (STp->buffer)->buffer_bytes; - else - (STp->buffer)->writing = ((STp->buffer)->buffer_bytes / - STp->block_size) * STp->block_size; - STp->dirty = !((STp->buffer)->writing == - (STp->buffer)->buffer_bytes); - - if (STp->block_size == 0) - blks = (STp->buffer)->writing; - else - blks = (STp->buffer)->writing / STp->block_size; - cmd[2] = blks >> 16; - cmd[3] = blks >> 8; - cmd[4] = blks; -#if DEBUG - STp->write_pending = 1; -#endif - - SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout, - MAX_WRITE_RETRIES, FALSE); - if (SCpnt == NULL) - return (-EIO); - } - else if (SCpnt != NULL) { scsi_release_command(SCpnt); SCpnt = NULL; - } - STps->at_sm &= (total == 0); - if (total > 0) - STps->eof = ST_NOEOF; - return( total); -} - -/* Read data from the tape. Returns zero in the normal case, one if the - eof status has changed, and the negative error code in case of a - fatal error. Otherwise updates the buffer and the eof state. */ -static long -read_tape(struct inode *inode, long count, Scsi_Cmnd **aSCpnt) -{ - int transfer, blks, bytes; - static unsigned char cmd[10]; - Scsi_Cmnd *SCpnt; - Scsi_Tape *STp; - ST_mode * STm; - ST_partstat * STps; - int dev = TAPE_NR(inode->i_rdev); - int retval = 0; - - if (count == 0) - return 0; - - STp = &(scsi_tapes[dev]); - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); - if (STps->eof == ST_FM_HIT) - return 1; + if (STp->block_size > 0) + (STp->buffer)->buffer_blocks = (STp->buffer)->buffer_size / STp->block_size; + else + (STp->buffer)->buffer_blocks = 1; + (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; - memset(cmd, 0, 10); - cmd[0] = READ_6; - cmd[1] = (STp->block_size != 0); - if (STp->block_size == 0) - blks = bytes = count; - else { - if (STm->do_read_ahead) { - blks = (STp->buffer)->buffer_blocks; - bytes = blks * STp->block_size; - } - else { - bytes = count; - if (bytes > (STp->buffer)->buffer_size) - bytes = (STp->buffer)->buffer_size; - blks = bytes / STp->block_size; - bytes = blks * STp->block_size; - } - } - cmd[2] = blks >> 16; - cmd[3] = blks >> 8; - cmd[4] = blks; - - SCpnt = *aSCpnt; - SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES, TRUE); - *aSCpnt = SCpnt; - if (!SCpnt) - return (-EBUSY); - - (STp->buffer)->read_pointer = 0; - STps->at_sm = 0; - - /* Something to check */ - if ((STp->buffer)->last_result_fatal) { - retval = 1; #if DEBUG if (debugging) - printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", - dev, - SCpnt->sense_buffer[0], SCpnt->sense_buffer[1], - SCpnt->sense_buffer[2], SCpnt->sense_buffer[3], - SCpnt->sense_buffer[4], SCpnt->sense_buffer[5], - SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]); -#endif - if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */ - - if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) - SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */ - - if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ - /* Compute the residual count */ - if ((SCpnt->sense_buffer[0] & 0x80) != 0) - transfer = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; - else - transfer = 0; - if (STp->block_size == 0 && - (SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR) - transfer = bytes; - - if (SCpnt->sense_buffer[2] & 0x20) { /* ILI */ - if (STp->block_size == 0) { - if (transfer <= 0) - transfer = 0; - (STp->buffer)->buffer_bytes = bytes - transfer; - } - else { - scsi_release_command(SCpnt); - SCpnt = *aSCpnt = NULL; - if (transfer == blks) { /* We did not get anything, error */ - printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev); - if (STps->drv_block >= 0) - STps->drv_block += blks - transfer + 1; - st_int_ioctl(inode, MTBSR, 1); - return (-EIO); - } - /* We have some data, deliver it */ - (STp->buffer)->buffer_bytes = (blks - transfer) * - STp->block_size; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG - "st%d: ILI but enough data received %ld %d.\n", - dev, count, (STp->buffer)->buffer_bytes); -#endif - if (STps->drv_block >= 0) - STps->drv_block += 1; - if (st_int_ioctl(inode, MTBSR, 1)) - return (-EIO); - } - } - else if (SCpnt->sense_buffer[2] & 0x80) { /* FM overrides EOM */ - if (STps->eof != ST_FM_HIT) - STps->eof = ST_FM_HIT; - else - STps->eof = ST_EOD_2; - if (STp->block_size == 0) - (STp->buffer)->buffer_bytes = 0; - else - (STp->buffer)->buffer_bytes = - bytes - transfer * STp->block_size; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG - "st%d: EOF detected (%d bytes read).\n", - dev, (STp->buffer)->buffer_bytes); + printk(ST_DEB_MSG "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev, + STp->block_size, (STp->buffer)->buffer_size, + (STp->buffer)->buffer_blocks); #endif - } - else if (SCpnt->sense_buffer[2] & 0x40) { - if (STps->eof == ST_FM) - STps->eof = ST_EOD_1; - else - STps->eof = ST_EOM_OK; - if (STp->block_size == 0) - (STp->buffer)->buffer_bytes = bytes - transfer; - else - (STp->buffer)->buffer_bytes = - bytes - transfer * STp->block_size; + + if (STp->drv_write_prot) { + STp->write_prot = 1; #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", - dev, (STp->buffer)->buffer_bytes); + if (debugging) + printk(ST_DEB_MSG "st%d: Write protected\n", dev); #endif + if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { + (STp->buffer)->in_use = 0; + STp->buffer = NULL; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if (st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); + return (-EROFS); } - } /* end of EOF, EOM, ILI test */ - else { /* nonzero sense key */ + } + if (STp->can_partitions && STp->nbr_partitions < 1) { + /* This code is reached when the device is opened for the first time + after the driver has been initialized with tape in the drive and the + partition support has been enabled. */ #if DEBUG if (debugging) - printk(ST_DEB_MSG "st%d: Tape error while reading.\n", dev); -#endif - STps->drv_block = (-1); - if (STps->eof == ST_FM && - (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG - "st%d: Zero returned for first BLANK CHECK after EOF.\n", - dev); + printk(ST_DEB_MSG "st%d: Updating partition number in status.\n", dev); #endif - STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */ + if ((STp->partition = find_partition(inode)) < 0) { + (STp->buffer)->in_use = 0; + STp->buffer = NULL; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if (st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); + return STp->partition; } - else /* Some other extended sense code */ - retval = (-EIO); - } - } /* End of extended sense test */ - else { /* Non-extended sense */ - retval = (STp->buffer)->last_result_fatal; + STp->new_partition = STp->partition; + STp->nbr_partitions = 1; /* This guess will be updated when necessary */ } + if (new_session) { /* Change the drive parameters for the new mode */ + STp->density_changed = STp->blksize_changed = FALSE; + STp->compression_changed = FALSE; + if (!(STm->defaults_for_writes) && + (i = set_mode_densblk(inode, STp, STm)) < 0) { + (STp->buffer)->in_use = 0; + STp->buffer = NULL; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if (st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); + return i; + } + if (STp->default_drvbuffer != 0xff) { + if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer)) + printk(KERN_WARNING "st%d: Can't set default drive buffering to %d.\n", + dev, STp->default_drvbuffer); + } + } + STp->in_use = 1; - } /* End of error handling */ - else /* Read successful */ - (STp->buffer)->buffer_bytes = bytes; - - if (STps->drv_block >= 0) { - if (STp->block_size == 0) - STps->drv_block++; - else - STps->drv_block += (STp->buffer)->buffer_bytes / STp->block_size; - } - - return retval; + return 0; } - -/* Read command */ -static ssize_t -st_read(struct file * filp, char * buf, size_t count, loff_t *ppos) + +/* Flush the tape buffer before close */ +static int scsi_tape_flush(struct file *filp) { - struct inode * inode = filp->f_dentry->d_inode; - ssize_t total; - ssize_t i, transfer; - int special; - Scsi_Cmnd * SCpnt = NULL; - Scsi_Tape * STp; - ST_mode * STm; - ST_partstat * STps; - int dev = TAPE_NR(inode->i_rdev); - - STp = &(scsi_tapes[dev]); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(STp->device) ) { - return -ENXIO; - } - - if (ppos != &filp->f_pos) { - /* "A request was outside the capabilities of the device." */ - return -ENXIO; - } - - if (STp->ready != ST_READY) { - if (STp->ready == ST_NO_TAPE) - return (-ENOMEDIUM); - else - return (-EIO); - } - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) - return (-ENXIO); -#if DEBUG - if (!STp->in_use) { - printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); - return (-EIO); - } -#endif - - if (STp->can_partitions && - (total = update_partition(inode)) < 0) - return total; - - if (STp->block_size == 0 && - count > (STp->buffer)->buffer_size && - !enlarge_buffer(STp->buffer, count, STp->restr_dma)) - return (-EOVERFLOW); - - if (!(STm->do_read_ahead) && STp->block_size != 0 && - (count % STp->block_size) != 0) - return (-EIO); /* Read must be integral number of blocks */ - - if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && - !st_int_ioctl(inode, MTLOCK, 0)) - STp->door_locked = ST_LOCKED_AUTO; - - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING) { - transfer = flush_buffer(inode, filp, 0); - if (transfer) - return transfer; - STps->rw = ST_READING; - } - -#if DEBUG - if (debugging && STps->eof != ST_NOEOF) - printk(ST_DEB_MSG "st%d: EOF/EOM flag up (%d). Bytes %d\n", dev, - STps->eof, (STp->buffer)->buffer_bytes); -#endif - if ((STp->buffer)->buffer_bytes == 0 && - STps->eof >= ST_EOD_1) { - if (STps->eof < ST_EOD) { - STps->eof += 1; - return 0; - } - return (-EIO); /* EOM or Blank Check */ - } - - /* Check the buffer writability before any tape movement. Don't alter - buffer data. */ - 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); - - STps->rw = ST_READING; - - - /* Loop until enough data in buffer or a special condition found */ - for (total = 0, special = 0; total < count && !special; ) { - - /* Get new data if the buffer is empty */ - if ((STp->buffer)->buffer_bytes == 0) { - special = read_tape(inode, count - total, &SCpnt); - if (special < 0) { /* No need to continue read */ - if (SCpnt != NULL) { - scsi_release_command(SCpnt); - } - return special; - } - } + int result = 0, result2; + static unsigned char cmd[10]; + Scsi_Cmnd *SCpnt; + Scsi_Tape *STp; + ST_mode *STm; + ST_partstat *STps; + + struct inode *inode = filp->f_dentry->d_inode; + kdev_t devt = inode->i_rdev; + int dev; + + if (file_count(filp) > 1) + return 0; + + dev = TAPE_NR(devt); + STp = &(scsi_tapes[dev]); + STm = &(STp->modes[STp->current_mode]); + STps = &(STp->ps[STp->partition]); - /* Move the data from driver buffer to user buffer */ - if ((STp->buffer)->buffer_bytes > 0) { + if (STp->can_partitions && + (result = update_partition(inode)) < 0) { #if DEBUG - if (debugging && STps->eof != ST_NOEOF) - printk(ST_DEB_MSG "st%d: EOF up (%d). Left %d, needed %d.\n", dev, - STps->eof, (STp->buffer)->buffer_bytes, count - total); + if (debugging) + printk(ST_DEB_MSG "st%d: update_partition at close failed.\n", dev); #endif - transfer = (STp->buffer)->buffer_bytes < count - total ? - (STp->buffer)->buffer_bytes : count - total; - i = from_buffer(STp->buffer, buf, transfer); - if (i) { - if (SCpnt != NULL) { - scsi_release_command(SCpnt); - SCpnt = NULL; - } - return i; + goto out; } - filp->f_pos += transfer; - buf += transfer; - total += transfer; - } - - if (STp->block_size == 0) - break; /* Read only one variable length block */ + if (STps->rw == ST_WRITING && !(STp->device)->was_reset) { - } /* for (total = 0, special = 0; total < count && !special; ) */ + result = flush_write_buffer(STp); - if (SCpnt != NULL) { - scsi_release_command(SCpnt); - SCpnt = NULL; - } +#if DEBUG + if (debugging) { + printk(ST_DEB_MSG "st%d: File length %ld bytes.\n", + dev, (long) (filp->f_pos)); + printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n", + dev, STp->nbr_waits, STp->nbr_finished); + } +#endif - /* Change the eof state if no data from tape or buffer */ - if (total == 0) { - if (STps->eof == ST_FM_HIT) { - STps->eof = ST_FM; - STps->drv_block = 0; - if (STps->drv_file >= 0) - STps->drv_file++; - } - else if (STps->eof == ST_EOD_1) { - STps->eof = ST_EOD_2; - STps->drv_block = 0; - if (STps->drv_file >= 0) - STps->drv_file++; - } - else if (STps->eof == ST_EOD_2) - STps->eof = ST_EOD; - } - else if (STps->eof == ST_FM) - STps->eof = ST_NOEOF; + if (result == 0 || result == (-ENOSPC)) { - return total; + memset(cmd, 0, 10); + cmd[0] = WRITE_FILEMARKS; + cmd[4] = 1 + STp->two_fm; + + SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES, + TRUE); + if (!SCpnt) + goto out; + + if ((STp->buffer)->last_result_fatal != 0 && + ((SCpnt->sense_buffer[0] & 0x70) != 0x70 || + (SCpnt->sense_buffer[2] & 0x4f) != 0x40 || + ((SCpnt->sense_buffer[0] & 0x80) != 0 && + (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] | + SCpnt->sense_buffer[5] | + SCpnt->sense_buffer[6]) == 0))) { + /* Filter out successful write at EOM */ + scsi_release_command(SCpnt); + SCpnt = NULL; + printk(KERN_ERR "st%d: Error on write filemark.\n", dev); + if (result == 0) + result = (-EIO); + } else { + scsi_release_command(SCpnt); + SCpnt = NULL; + if (STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + if (STp->two_fm) + cross_eof(STp, FALSE); + STps->eof = ST_FM; + } + } +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n", + dev, cmd[4]); +#endif + } else if (!STp->rew_at_close) { + STps = &(STp->ps[STp->partition]); + if (!STm->sysv || STps->rw != ST_READING) { + if (STp->can_bsr) + result = flush_buffer(inode, filp, 0); + else if (STps->eof == ST_FM_HIT) { + result = cross_eof(STp, FALSE); + if (result) { + if (STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + STps->eof = ST_FM; + } else + STps->eof = ST_NOEOF; + } + } else if ((STps->eof == ST_NOEOF && + !(result = cross_eof(STp, TRUE))) || + STps->eof == ST_FM_HIT) { + if (STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + STps->eof = ST_FM; + } + } + out: + if (STp->rew_at_close) { + result2 = st_int_ioctl(inode, MTREW, 1); + if (result == 0) + result = result2; + } + return result; } - -/* Set the driver options */ - static void -st_log_options(Scsi_Tape *STp, ST_mode *STm, int dev) +/* Close the device and release it */ +static int scsi_tape_close(struct inode *inode, struct file *filp) { - printk(KERN_INFO -"st%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", - dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, - STm->do_read_ahead); - printk(KERN_INFO -"st%d: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", - dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); - printk(KERN_INFO -"st%d: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", - dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, - STp->scsi2_logical); - printk(KERN_INFO -"st%d: sysv: %d\n", dev, STm->sysv); -#if DEBUG - printk(KERN_INFO - "st%d: debugging: %d\n", - dev, debugging); -#endif -} - - - static int -st_set_options(struct inode * inode, long options) -{ - int value; - long code; - Scsi_Tape *STp; - ST_mode *STm; - int dev = TAPE_NR(inode->i_rdev); - - STp = &(scsi_tapes[dev]); - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - memcpy(STm, &(STp->modes[0]), sizeof(ST_mode)); - modes_defined = TRUE; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Initialized mode %d definition from mode 0\n", - dev, STp->current_mode); -#endif - } - - code = options & MT_ST_OPTIONS; - if (code == MT_ST_BOOLEANS) { - STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; - STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; - STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; - STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; - STp->two_fm = (options & MT_ST_TWO_FM) != 0; - STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; - STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; - STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; - STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; - if ((STp->device)->scsi_level >= SCSI_2) - STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; - STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; - STm->sysv = (options & MT_ST_SYSV) != 0; -#if DEBUG - debugging = (options & MT_ST_DEBUGGING) != 0; -#endif - st_log_options(STp, STm, dev); - } - else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { - value = (code == MT_ST_SETBOOLEANS); - if ((options & MT_ST_BUFFER_WRITES) != 0) - STm->do_buffer_writes = value; - if ((options & MT_ST_ASYNC_WRITES) != 0) - STm->do_async_writes = value; - if ((options & MT_ST_DEF_WRITES) != 0) - STm->defaults_for_writes = value; - if ((options & MT_ST_READ_AHEAD) != 0) - STm->do_read_ahead = value; - if ((options & MT_ST_TWO_FM) != 0) - STp->two_fm = value; - if ((options & MT_ST_FAST_MTEOM) != 0) - STp->fast_mteom = value; - if ((options & MT_ST_AUTO_LOCK) != 0) - STp->do_auto_lock = value; - if ((options & MT_ST_CAN_BSR) != 0) - STp->can_bsr = value; - if ((options & MT_ST_NO_BLKLIMS) != 0) - STp->omit_blklims = value; - if ((STp->device)->scsi_level >= SCSI_2 && - (options & MT_ST_CAN_PARTITIONS) != 0) - STp->can_partitions = value; - if ((options & MT_ST_SCSI2LOGICAL) != 0) - STp->scsi2_logical = value; - if ((options & MT_ST_SYSV) != 0) - STm->sysv = value; -#if DEBUG - if ((options & MT_ST_DEBUGGING) != 0) - debugging = value; -#endif - st_log_options(STp, STm, dev); - } - else if (code == MT_ST_WRITE_THRESHOLD) { - value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; - if (value < 1 || value > st_buffer_size) { - printk(KERN_WARNING "st%d: Write threshold %d too small or too large.\n", - dev, value); - return (-EIO); - } - STp->write_threshold = value; - printk(KERN_INFO "st%d: Write threshold set to %d bytes.\n", - dev, value); - } - else if (code == MT_ST_DEF_BLKSIZE) { - value = (options & ~MT_ST_OPTIONS); - if (value == ~MT_ST_OPTIONS) { - STm->default_blksize = (-1); - printk(KERN_INFO "st%d: Default block size disabled.\n", dev); - } - else { - STm->default_blksize = value; - printk(KERN_INFO "st%d: Default block size set to %d bytes.\n", - dev, STm->default_blksize); - } - } - else if (code == MT_ST_TIMEOUTS) { - value = (options & ~MT_ST_OPTIONS); - if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { - STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; - printk(KERN_INFO "st%d: Long timeout set to %d seconds.\n", dev, - (value & ~MT_ST_SET_LONG_TIMEOUT)); - } - else { - STp->timeout = value * HZ; - printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", dev, - value); - } - } - else if (code == MT_ST_DEF_OPTIONS) { - code = (options & ~MT_ST_CLEAR_DEFAULT); - value = (options & MT_ST_CLEAR_DEFAULT); - if (code == MT_ST_DEF_DENSITY) { - if (value == MT_ST_CLEAR_DEFAULT) { - STm->default_density = (-1); - printk(KERN_INFO "st%d: Density default disabled.\n", dev); - } - else { - STm->default_density = value & 0xff; - printk(KERN_INFO "st%d: Density default set to %x\n", - dev, STm->default_density); - } - } - else if (code == MT_ST_DEF_DRVBUFFER) { - if (value == MT_ST_CLEAR_DEFAULT) { - STp->default_drvbuffer = 0xff; - printk(KERN_INFO "st%d: Drive buffer default disabled.\n", dev); - } - else { - STp->default_drvbuffer = value & 7; - printk(KERN_INFO "st%d: Drive buffer default set to %x\n", - dev, STp->default_drvbuffer); - } - } - else if (code == MT_ST_DEF_COMPRESSION) { - if (value == MT_ST_CLEAR_DEFAULT) { - STm->default_compression = ST_DONT_TOUCH; - printk(KERN_INFO "st%d: Compression default disabled.\n", dev); - } - else { - STm->default_compression = (value & 1 ? ST_YES : ST_NO); - printk(KERN_INFO "st%d: Compression default set to %x\n", - dev, (value & 1)); - } - } - } - else - return (-EIO); + int result = 0; + Scsi_Tape *STp; - return 0; -} + kdev_t devt = inode->i_rdev; + int dev; - -#define COMPRESSION_PAGE 0x0f -#define COMPRESSION_PAGE_LENGTH 16 + dev = TAPE_NR(devt); + STp = &(scsi_tapes[dev]); -#define MODE_HEADER_LENGTH 4 + if (STp->door_locked == ST_LOCKED_AUTO) + st_int_ioctl(inode, MTUNLOCK, 0); -#define DCE_MASK 0x80 -#define DCC_MASK 0x40 -#define RED_MASK 0x60 + if (STp->buffer != NULL) { + normalize_buffer(STp->buffer); + (STp->buffer)->in_use = 0; + } + STp->in_use = 0; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if (st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); + return result; +} + -/* Control the compression with mode page 15. Algorithm not changed if zero. */ - static int -st_compression(Scsi_Tape * STp, int state) +/* Write command */ +static ssize_t + st_write(struct file *filp, const char *buf, size_t count, loff_t * ppos) { - int dev; - unsigned char cmd[10]; - Scsi_Cmnd * SCpnt = NULL; - - if (STp->ready != ST_READY) - return (-EIO); - - /* Read the current page contents */ - memset(cmd, 0, 10); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = COMPRESSION_PAGE; - cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); - if (SCpnt == NULL) - return (-EBUSY); - dev = TAPE_NR(SCpnt->request.rq_dev); + struct inode *inode = filp->f_dentry->d_inode; + ssize_t total; + ssize_t i, do_count, blks, retval, transfer; + int write_threshold; + int doing_write = 0; + static unsigned char cmd[10]; + const char *b_point; + Scsi_Cmnd *SCpnt = NULL; + Scsi_Tape *STp; + ST_mode *STm; + ST_partstat *STps; + int dev = TAPE_NR(inode->i_rdev); + + STp = &(scsi_tapes[dev]); + + /* + * If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. + */ + if (!scsi_block_when_processing_errors(STp->device)) { + return -ENXIO; + } + if (ppos != &filp->f_pos) { + /* "A request was outside the capabilities of the device." */ + return -ENXIO; + } + if (STp->ready != ST_READY) { + if (STp->ready == ST_NO_TAPE) + return (-ENOMEDIUM); + else + return (-EIO); + } + STm = &(STp->modes[STp->current_mode]); + if (!STm->defined) + return (-ENXIO); + if (count == 0) + return 0; + + /* + * If there was a bus reset, block further access + * to this device. + */ + if (STp->device->was_reset) + return (-EIO); + +#if DEBUG + if (!STp->in_use) { + printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); + return (-EIO); + } +#endif + + /* 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); + } + if (STp->can_partitions && + (retval = update_partition(inode)) < 0) + return retval; + STps = &(STp->ps[STp->partition]); - if ((STp->buffer)->last_result_fatal != 0) { + if (STp->write_prot) + return (-EACCES); + + if (STp->block_size == 0 && + count > (STp->buffer)->buffer_size && + !enlarge_buffer(STp->buffer, count, STp->restr_dma)) + return (-EOVERFLOW); + + if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && + !st_int_ioctl(inode, MTLOCK, 0)) + STp->door_locked = ST_LOCKED_AUTO; + + if (STps->rw == ST_READING) { + retval = flush_buffer(inode, filp, 0); + if (retval) + return retval; + STps->rw = ST_WRITING; + } else if (STps->rw != ST_WRITING && + STps->drv_file == 0 && STps->drv_block == 0) { + if ((retval = set_mode_densblk(inode, STp, STm)) < 0) + return retval; + 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 ((STp->buffer)->writing) { + write_behind_check(STp); + if ((STp->buffer)->last_result_fatal) { #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev); + if (debugging) + printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", dev, + (STp->buffer)->last_result); #endif - scsi_release_command(SCpnt); - SCpnt = NULL; - return (-EIO); - } + if ((STp->buffer)->last_result == INT_MAX) + STps->eof = ST_EOM_OK; + else + STps->eof = ST_EOM_ERROR; + } + } + if (STps->eof == ST_EOM_OK) + return (-ENOSPC); + else if (STps->eof == ST_EOM_ERROR) + return (-EIO); + + /* 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); + + 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 */ +#endif + write_threshold = 1; + } else + write_threshold = (STp->buffer)->buffer_blocks * STp->block_size; + if (!STm->do_async_writes) + write_threshold--; + + total = count; + + memset(cmd, 0, 10); + cmd[0] = WRITE_6; + cmd[1] = (STp->block_size != 0); + + STps->rw = ST_WRITING; + + b_point = buf; + while ((STp->block_size == 0 && !STm->do_async_writes && count > 0) || + (STp->block_size != 0 && + (STp->buffer)->buffer_bytes + count > write_threshold)) { + doing_write = 1; + if (STp->block_size == 0) + do_count = count; + else { + do_count = (STp->buffer)->buffer_blocks * STp->block_size - + (STp->buffer)->buffer_bytes; + if (do_count > count) + do_count = count; + } + + i = append_to_buffer(b_point, STp->buffer, do_count); + if (i) { + if (SCpnt != NULL) { + scsi_release_command(SCpnt); + SCpnt = NULL; + } + return i; + } + if (STp->block_size == 0) + blks = transfer = do_count; + else { + blks = (STp->buffer)->buffer_bytes / + STp->block_size; + transfer = blks * STp->block_size; + } + cmd[2] = blks >> 16; + cmd[3] = blks >> 8; + cmd[4] = blks; + + SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout, + MAX_WRITE_RETRIES, TRUE); + if (!SCpnt) + return (-EBUSY); + + if ((STp->buffer)->last_result_fatal != 0) { #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev, - ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0)); + if (debugging) + printk(ST_DEB_MSG "st%d: Error on write:\n", dev); +#endif + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x40)) { + if (STp->block_size != 0 && (SCpnt->sense_buffer[0] & 0x80) != 0) + transfer = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + else if (STp->block_size == 0 && + (SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW) + transfer = do_count; + else + transfer = 0; + if (STp->block_size != 0) + transfer *= STp->block_size; + if (transfer <= do_count) { + filp->f_pos += do_count - transfer; + count -= do_count - transfer; + if (STps->drv_block >= 0) { + if (STp->block_size == 0 && transfer < do_count) + STps->drv_block++; + else if (STp->block_size != 0) + STps->drv_block += (do_count - transfer) / STp->block_size; + } + STps->eof = ST_EOM_OK; + retval = (-ENOSPC); /* EOM within current request */ +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: EOM with %d bytes unwritten.\n", + dev, transfer); +#endif + } else { + STps->eof = ST_EOM_ERROR; + STps->drv_block = (-1); /* Too cautious? */ + retval = (-EIO); /* EOM for old data */ +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: EOM with lost data.\n", dev); +#endif + } + } else { + STps->drv_block = (-1); /* Too cautious? */ + retval = (-EIO); + } + + scsi_release_command(SCpnt); + SCpnt = NULL; + (STp->buffer)->buffer_bytes = 0; + STp->dirty = 0; + if (count < total) + return total - count; + else + return retval; + } + filp->f_pos += do_count; + b_point += do_count; + count -= do_count; + if (STps->drv_block >= 0) { + if (STp->block_size == 0) + STps->drv_block++; + else + STps->drv_block += blks; + } + (STp->buffer)->buffer_bytes = 0; + STp->dirty = 0; + } + if (count != 0) { + STp->dirty = 1; + i = append_to_buffer(b_point, STp->buffer, count); + if (i) { + if (SCpnt != NULL) { + scsi_release_command(SCpnt); + SCpnt = NULL; + } + return i; + } + filp->f_pos += count; + count = 0; + } + if (doing_write && (STp->buffer)->last_result_fatal != 0) { + scsi_release_command(SCpnt); + SCpnt = NULL; + return (STp->buffer)->last_result_fatal; + } + if (STm->do_async_writes && + (((STp->buffer)->buffer_bytes >= STp->write_threshold && + (STp->buffer)->buffer_bytes >= STp->block_size) || + STp->block_size == 0)) { + /* Schedule an asynchronous write */ + if (STp->block_size == 0) + (STp->buffer)->writing = (STp->buffer)->buffer_bytes; + else + (STp->buffer)->writing = ((STp->buffer)->buffer_bytes / + STp->block_size) * STp->block_size; + STp->dirty = !((STp->buffer)->writing == + (STp->buffer)->buffer_bytes); + + if (STp->block_size == 0) + blks = (STp->buffer)->writing; + else + blks = (STp->buffer)->writing / STp->block_size; + cmd[2] = blks >> 16; + cmd[3] = blks >> 8; + cmd[4] = blks; +#if DEBUG + STp->write_pending = 1; #endif - /* Check if compression can be changed */ - if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) { + SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout, + MAX_WRITE_RETRIES, FALSE); + if (SCpnt == NULL) + return (-EIO); + } else if (SCpnt != NULL) { + scsi_release_command(SCpnt); + SCpnt = NULL; + } + STps->at_sm &= (total == 0); + if (total > 0) + STps->eof = ST_NOEOF; + + return (total); +} + +/* Read data from the tape. Returns zero in the normal case, one if the + eof status has changed, and the negative error code in case of a + fatal error. Otherwise updates the buffer and the eof state. */ +static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt) +{ + int transfer, blks, bytes; + static unsigned char cmd[10]; + Scsi_Cmnd *SCpnt; + Scsi_Tape *STp; + ST_mode *STm; + ST_partstat *STps; + int dev = TAPE_NR(inode->i_rdev); + int retval = 0; + + if (count == 0) + return 0; + + STp = &(scsi_tapes[dev]); + STm = &(STp->modes[STp->current_mode]); + STps = &(STp->ps[STp->partition]); + if (STps->eof == ST_FM_HIT) + return 1; + + memset(cmd, 0, 10); + cmd[0] = READ_6; + cmd[1] = (STp->block_size != 0); + if (STp->block_size == 0) + blks = bytes = count; + else { + if (STm->do_read_ahead) { + blks = (STp->buffer)->buffer_blocks; + bytes = blks * STp->block_size; + } else { + bytes = count; + if (bytes > (STp->buffer)->buffer_size) + bytes = (STp->buffer)->buffer_size; + blks = bytes / STp->block_size; + bytes = blks * STp->block_size; + } + } + cmd[2] = blks >> 16; + cmd[3] = blks >> 8; + cmd[4] = blks; + + SCpnt = *aSCpnt; + SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES, TRUE); + *aSCpnt = SCpnt; + if (!SCpnt) + return (-EBUSY); + + (STp->buffer)->read_pointer = 0; + STps->at_sm = 0; + + /* Something to check */ + if ((STp->buffer)->last_result_fatal) { + retval = 1; #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev); + if (debugging) + printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", + dev, + SCpnt->sense_buffer[0], SCpnt->sense_buffer[1], + SCpnt->sense_buffer[2], SCpnt->sense_buffer[3], + SCpnt->sense_buffer[4], SCpnt->sense_buffer[5], + SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]); +#endif + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */ + + if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) + SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */ + + if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ + /* Compute the residual count */ + if ((SCpnt->sense_buffer[0] & 0x80) != 0) + transfer = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + else + transfer = 0; + if (STp->block_size == 0 && + (SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR) + transfer = bytes; + + if (SCpnt->sense_buffer[2] & 0x20) { /* ILI */ + if (STp->block_size == 0) { + if (transfer <= 0) + transfer = 0; + (STp->buffer)->buffer_bytes = bytes - transfer; + } else { + scsi_release_command(SCpnt); + SCpnt = *aSCpnt = NULL; + if (transfer == blks) { /* We did not get anything, error */ + printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev); + if (STps->drv_block >= 0) + STps->drv_block += blks - transfer + 1; + st_int_ioctl(inode, MTBSR, 1); + return (-EIO); + } + /* We have some data, deliver it */ + (STp->buffer)->buffer_bytes = (blks - transfer) * + STp->block_size; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG + "st%d: ILI but enough data received %ld %d.\n", + dev, count, (STp->buffer)->buffer_bytes); +#endif + if (STps->drv_block >= 0) + STps->drv_block += 1; + if (st_int_ioctl(inode, MTBSR, 1)) + return (-EIO); + } + } else if (SCpnt->sense_buffer[2] & 0x80) { /* FM overrides EOM */ + if (STps->eof != ST_FM_HIT) + STps->eof = ST_FM_HIT; + else + STps->eof = ST_EOD_2; + if (STp->block_size == 0) + (STp->buffer)->buffer_bytes = 0; + else + (STp->buffer)->buffer_bytes = + bytes - transfer * STp->block_size; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG + "st%d: EOF detected (%d bytes read).\n", + dev, (STp->buffer)->buffer_bytes); +#endif + } else if (SCpnt->sense_buffer[2] & 0x40) { + if (STps->eof == ST_FM) + STps->eof = ST_EOD_1; + else + STps->eof = ST_EOM_OK; + if (STp->block_size == 0) + (STp->buffer)->buffer_bytes = bytes - transfer; + else + (STp->buffer)->buffer_bytes = + bytes - transfer * STp->block_size; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", + dev, (STp->buffer)->buffer_bytes); #endif - scsi_release_command(SCpnt); - SCpnt = NULL; - return (-EIO); - } + } + } + /* end of EOF, EOM, ILI test */ + else { /* nonzero sense key */ +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Tape error while reading.\n", dev); +#endif + STps->drv_block = (-1); + if (STps->eof == ST_FM && + (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) { +#if DEBUG + if (debugging) + printk(ST_DEB_MSG + "st%d: Zero returned for first BLANK CHECK after EOF.\n", + dev); +#endif + STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */ + } else /* Some other extended sense code */ + retval = (-EIO); + } + } + /* End of extended sense test */ + else { /* Non-extended sense */ + retval = (STp->buffer)->last_result_fatal; + } - /* Do the change */ - if (state) - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] |= DCE_MASK; - else - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] &= ~DCE_MASK; + } + /* End of error handling */ + else /* Read successful */ + (STp->buffer)->buffer_bytes = bytes; + + if (STps->drv_block >= 0) { + if (STp->block_size == 0) + STps->drv_block++; + else + STps->drv_block += (STp->buffer)->buffer_bytes / STp->block_size; + } + return retval; +} + - memset(cmd, 0, 10); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH; +/* Read command */ +static ssize_t + st_read(struct file *filp, char *buf, size_t count, loff_t * ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + ssize_t total; + ssize_t i, transfer; + int special; + Scsi_Cmnd *SCpnt = NULL; + Scsi_Tape *STp; + ST_mode *STm; + ST_partstat *STps; + int dev = TAPE_NR(inode->i_rdev); + + STp = &(scsi_tapes[dev]); + + /* + * If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. + */ + if (!scsi_block_when_processing_errors(STp->device)) { + return -ENXIO; + } + if (ppos != &filp->f_pos) { + /* "A request was outside the capabilities of the device." */ + return -ENXIO; + } + if (STp->ready != ST_READY) { + if (STp->ready == ST_NO_TAPE) + return (-ENOMEDIUM); + else + return (-EIO); + } + STm = &(STp->modes[STp->current_mode]); + if (!STm->defined) + return (-ENXIO); +#if DEBUG + if (!STp->in_use) { + printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); + return (-EIO); + } +#endif - (STp->buffer)->b_data[0] = 0; /* Reserved data length */ - (STp->buffer)->b_data[1] = 0; /* Reserved media type byte */ - (STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f; - SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + if (STp->can_partitions && + (total = update_partition(inode)) < 0) + return total; + + if (STp->block_size == 0 && + count > (STp->buffer)->buffer_size && + !enlarge_buffer(STp->buffer, count, STp->restr_dma)) + return (-EOVERFLOW); + + if (!(STm->do_read_ahead) && STp->block_size != 0 && + (count % STp->block_size) != 0) + return (-EIO); /* Read must be integral number of blocks */ + + if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && + !st_int_ioctl(inode, MTLOCK, 0)) + STp->door_locked = ST_LOCKED_AUTO; - if ((STp->buffer)->last_result_fatal != 0) { + STps = &(STp->ps[STp->partition]); + if (STps->rw == ST_WRITING) { + transfer = flush_buffer(inode, filp, 0); + if (transfer) + return transfer; + STps->rw = ST_READING; + } #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev); + if (debugging && STps->eof != ST_NOEOF) + printk(ST_DEB_MSG "st%d: EOF/EOM flag up (%d). Bytes %d\n", dev, + STps->eof, (STp->buffer)->buffer_bytes); +#endif + if ((STp->buffer)->buffer_bytes == 0 && + STps->eof >= ST_EOD_1) { + if (STps->eof < ST_EOD) { + STps->eof += 1; + return 0; + } + return (-EIO); /* EOM or Blank Check */ + } + /* Check the buffer writability before any tape movement. Don't alter + buffer data. */ + 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); + + STps->rw = ST_READING; + + + /* Loop until enough data in buffer or a special condition found */ + for (total = 0, special = 0; total < count && !special;) { + + /* Get new data if the buffer is empty */ + if ((STp->buffer)->buffer_bytes == 0) { + special = read_tape(inode, count - total, &SCpnt); + if (special < 0) { /* No need to continue read */ + if (SCpnt != NULL) { + scsi_release_command(SCpnt); + } + return special; + } + } + /* Move the data from driver buffer to user buffer */ + if ((STp->buffer)->buffer_bytes > 0) { +#if DEBUG + if (debugging && STps->eof != ST_NOEOF) + printk(ST_DEB_MSG "st%d: EOF up (%d). Left %d, needed %d.\n", dev, + STps->eof, (STp->buffer)->buffer_bytes, count - total); +#endif + transfer = (STp->buffer)->buffer_bytes < count - total ? + (STp->buffer)->buffer_bytes : count - total; + i = from_buffer(STp->buffer, buf, transfer); + if (i) { + if (SCpnt != NULL) { + scsi_release_command(SCpnt); + SCpnt = NULL; + } + return i; + } + filp->f_pos += transfer; + buf += transfer; + total += transfer; + } + if (STp->block_size == 0) + break; /* Read only one variable length block */ + + } /* for (total = 0, special = 0; total < count && !special; ) */ + + if (SCpnt != NULL) { + scsi_release_command(SCpnt); + SCpnt = NULL; + } + /* Change the eof state if no data from tape or buffer */ + if (total == 0) { + if (STps->eof == ST_FM_HIT) { + STps->eof = ST_FM; + STps->drv_block = 0; + if (STps->drv_file >= 0) + STps->drv_file++; + } else if (STps->eof == ST_EOD_1) { + STps->eof = ST_EOD_2; + STps->drv_block = 0; + if (STps->drv_file >= 0) + STps->drv_file++; + } else if (STps->eof == ST_EOD_2) + STps->eof = ST_EOD; + } else if (STps->eof == ST_FM) + STps->eof = ST_NOEOF; + + return total; +} + + + +/* Set the driver options */ +static void st_log_options(Scsi_Tape * STp, ST_mode * STm, int dev) +{ + printk(KERN_INFO + "st%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", + dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, + STm->do_read_ahead); + printk(KERN_INFO + "st%d: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", + dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); + printk(KERN_INFO + "st%d: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", + dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, + STp->scsi2_logical); + printk(KERN_INFO + "st%d: sysv: %d\n", dev, STm->sysv); +#if DEBUG + printk(KERN_INFO + "st%d: debugging: %d\n", + dev, debugging); #endif - scsi_release_command(SCpnt); - SCpnt = NULL; - return (-EIO); - } +} + +static int st_set_options(struct inode *inode, long options) +{ + int value; + long code; + Scsi_Tape *STp; + ST_mode *STm; + int dev = TAPE_NR(inode->i_rdev); + + STp = &(scsi_tapes[dev]); + STm = &(STp->modes[STp->current_mode]); + if (!STm->defined) { + memcpy(STm, &(STp->modes[0]), sizeof(ST_mode)); + modes_defined = TRUE; #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n", - dev, state); + if (debugging) + printk(ST_DEB_MSG "st%d: Initialized mode %d definition from mode 0\n", + dev, STp->current_mode); #endif + } + code = options & MT_ST_OPTIONS; + if (code == MT_ST_BOOLEANS) { + STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; + STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; + STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; + STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; + STp->two_fm = (options & MT_ST_TWO_FM) != 0; + STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; + STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; + STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; + STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; + if ((STp->device)->scsi_level >= SCSI_2) + STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; + STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; + STm->sysv = (options & MT_ST_SYSV) != 0; +#if DEBUG + debugging = (options & MT_ST_DEBUGGING) != 0; +#endif + st_log_options(STp, STm, dev); + } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { + value = (code == MT_ST_SETBOOLEANS); + if ((options & MT_ST_BUFFER_WRITES) != 0) + STm->do_buffer_writes = value; + if ((options & MT_ST_ASYNC_WRITES) != 0) + STm->do_async_writes = value; + if ((options & MT_ST_DEF_WRITES) != 0) + STm->defaults_for_writes = value; + if ((options & MT_ST_READ_AHEAD) != 0) + STm->do_read_ahead = value; + if ((options & MT_ST_TWO_FM) != 0) + STp->two_fm = value; + if ((options & MT_ST_FAST_MTEOM) != 0) + STp->fast_mteom = value; + if ((options & MT_ST_AUTO_LOCK) != 0) + STp->do_auto_lock = value; + if ((options & MT_ST_CAN_BSR) != 0) + STp->can_bsr = value; + if ((options & MT_ST_NO_BLKLIMS) != 0) + STp->omit_blklims = value; + if ((STp->device)->scsi_level >= SCSI_2 && + (options & MT_ST_CAN_PARTITIONS) != 0) + STp->can_partitions = value; + if ((options & MT_ST_SCSI2LOGICAL) != 0) + STp->scsi2_logical = value; + if ((options & MT_ST_SYSV) != 0) + STm->sysv = value; +#if DEBUG + if ((options & MT_ST_DEBUGGING) != 0) + debugging = value; +#endif + st_log_options(STp, STm, dev); + } else if (code == MT_ST_WRITE_THRESHOLD) { + value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; + if (value < 1 || value > st_buffer_size) { + printk(KERN_WARNING "st%d: Write threshold %d too small or too large.\n", + dev, value); + return (-EIO); + } + STp->write_threshold = value; + printk(KERN_INFO "st%d: Write threshold set to %d bytes.\n", + dev, value); + } else if (code == MT_ST_DEF_BLKSIZE) { + value = (options & ~MT_ST_OPTIONS); + if (value == ~MT_ST_OPTIONS) { + STm->default_blksize = (-1); + printk(KERN_INFO "st%d: Default block size disabled.\n", dev); + } else { + STm->default_blksize = value; + printk(KERN_INFO "st%d: Default block size set to %d bytes.\n", + dev, STm->default_blksize); + } + } else if (code == MT_ST_TIMEOUTS) { + value = (options & ~MT_ST_OPTIONS); + if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { + STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; + printk(KERN_INFO "st%d: Long timeout set to %d seconds.\n", dev, + (value & ~MT_ST_SET_LONG_TIMEOUT)); + } else { + STp->timeout = value * HZ; + printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", dev, + value); + } + } else if (code == MT_ST_DEF_OPTIONS) { + code = (options & ~MT_ST_CLEAR_DEFAULT); + value = (options & MT_ST_CLEAR_DEFAULT); + if (code == MT_ST_DEF_DENSITY) { + if (value == MT_ST_CLEAR_DEFAULT) { + STm->default_density = (-1); + printk(KERN_INFO "st%d: Density default disabled.\n", dev); + } else { + STm->default_density = value & 0xff; + printk(KERN_INFO "st%d: Density default set to %x\n", + dev, STm->default_density); + } + } else if (code == MT_ST_DEF_DRVBUFFER) { + if (value == MT_ST_CLEAR_DEFAULT) { + STp->default_drvbuffer = 0xff; + printk(KERN_INFO "st%d: Drive buffer default disabled.\n", dev); + } else { + STp->default_drvbuffer = value & 7; + printk(KERN_INFO "st%d: Drive buffer default set to %x\n", + dev, STp->default_drvbuffer); + } + } else if (code == MT_ST_DEF_COMPRESSION) { + if (value == MT_ST_CLEAR_DEFAULT) { + STm->default_compression = ST_DONT_TOUCH; + printk(KERN_INFO "st%d: Compression default disabled.\n", dev); + } else { + STm->default_compression = (value & 1 ? ST_YES : ST_NO); + printk(KERN_INFO "st%d: Compression default set to %x\n", + dev, (value & 1)); + } + } + } else + return (-EIO); - scsi_release_command(SCpnt); - SCpnt = NULL; - STp->compression_changed = TRUE; - return 0; + return 0; } + +#define COMPRESSION_PAGE 0x0f +#define COMPRESSION_PAGE_LENGTH 16 + +#define MODE_HEADER_LENGTH 4 + +#define DCE_MASK 0x80 +#define DCC_MASK 0x40 +#define RED_MASK 0x60 + + +/* Control the compression with mode page 15. Algorithm not changed if zero. */ +static int st_compression(Scsi_Tape * STp, int state) +{ + int dev; + unsigned char cmd[10]; + Scsi_Cmnd *SCpnt = NULL; + + if (STp->ready != ST_READY) + return (-EIO); + + /* Read the current page contents */ + memset(cmd, 0, 10); + cmd[0] = MODE_SENSE; + cmd[1] = 8; + cmd[2] = COMPRESSION_PAGE; + cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH; + + SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + if (SCpnt == NULL) + return (-EBUSY); + dev = TAPE_NR(SCpnt->request.rq_dev); + + if ((STp->buffer)->last_result_fatal != 0) { +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev); +#endif + scsi_release_command(SCpnt); + SCpnt = NULL; + return (-EIO); + } +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev, + ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0)); +#endif + + /* Check if compression can be changed */ + if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) { +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev); +#endif + scsi_release_command(SCpnt); + SCpnt = NULL; + return (-EIO); + } + /* Do the change */ + if (state) + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] |= DCE_MASK; + else + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] &= ~DCE_MASK; + + memset(cmd, 0, 10); + cmd[0] = MODE_SELECT; + cmd[1] = 0x10; + cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH; + + (STp->buffer)->b_data[0] = 0; /* Reserved data length */ + (STp->buffer)->b_data[1] = 0; /* Reserved media type byte */ + (STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f; + SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + + if ((STp->buffer)->last_result_fatal != 0) { +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev); +#endif + scsi_release_command(SCpnt); + SCpnt = NULL; + return (-EIO); + } +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n", + dev, state); +#endif + + scsi_release_command(SCpnt); + SCpnt = NULL; + STp->compression_changed = TRUE; + return 0; +} + /* Internal ioctl function */ - static int -st_int_ioctl(struct inode * inode, - unsigned int cmd_in, unsigned long arg) -{ - int timeout; - long ltmp; - int i, ioctl_result; - int chg_eof = TRUE; - unsigned char cmd[10]; - Scsi_Cmnd * SCpnt; - Scsi_Tape * STp; - ST_partstat * STps; - int fileno, blkno, at_sm, undone, datalen; - int dev = TAPE_NR(inode->i_rdev); - - STp = &(scsi_tapes[dev]); - if (STp->ready != ST_READY && cmd_in != MTLOAD) { - if (STp->ready == ST_NO_TAPE) - return (-ENOMEDIUM); - else - return (-EIO); - } - timeout = STp->long_timeout; - STps = &(STp->ps[STp->partition]); - fileno = STps->drv_file; - blkno = STps->drv_block; - at_sm = STps->at_sm; - - memset(cmd, 0, 10); - datalen = 0; - switch (cmd_in) { - case MTFSFM: - chg_eof = FALSE; /* Changed from the FSF after this */ - case MTFSF: - cmd[0] = SPACE; - cmd[1] = 0x01; /* Space FileMarks */ - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n", - dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif - if (fileno >= 0) - fileno += arg; - blkno = 0; - at_sm &= (arg == 0); - break; - case MTBSFM: - chg_eof = FALSE; /* Changed from the FSF after this */ - case MTBSF: - cmd[0] = SPACE; - cmd[1] = 0x01; /* Space FileMarks */ - ltmp = (-arg); - cmd[2] = (ltmp >> 16); - cmd[3] = (ltmp >> 8); - cmd[4] = ltmp; -#if DEBUG - if (debugging) { - if (cmd[2] & 0x80) - ltmp = 0xff000000; - ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(ST_DEB_MSG "st%d: Spacing tape backward over %ld filemarks.\n", - dev, (-ltmp)); - } -#endif - if (fileno >= 0) - fileno -= arg; - blkno = (-1); /* We can't know the block number */ - at_sm &= (arg == 0); - break; - case MTFSR: - cmd[0] = SPACE; - cmd[1] = 0x00; /* Space Blocks */ - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif - if (blkno >= 0) - blkno += arg; - at_sm &= (arg == 0); - break; - case MTBSR: - cmd[0] = SPACE; - cmd[1] = 0x00; /* Space Blocks */ - ltmp = (-arg); - cmd[2] = (ltmp >> 16); - cmd[3] = (ltmp >> 8); - cmd[4] = ltmp; -#if DEBUG - if (debugging) { - if (cmd[2] & 0x80) - ltmp = 0xff000000; - ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(ST_DEB_MSG "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp)); - } -#endif - if (blkno >= 0) - blkno -= arg; - at_sm &= (arg == 0); - break; - case MTFSS: - cmd[0] = SPACE; - cmd[1] = 0x04; /* Space Setmarks */ - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif - if (arg != 0) { - blkno = fileno = (-1); - at_sm = 1; - } - break; - case MTBSS: - cmd[0] = SPACE; - cmd[1] = 0x04; /* Space Setmarks */ - ltmp = (-arg); - cmd[2] = (ltmp >> 16); - cmd[3] = (ltmp >> 8); - cmd[4] = ltmp; -#if DEBUG - if (debugging) { - if (cmd[2] & 0x80) - ltmp = 0xff000000; - ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n", - dev, (-ltmp)); - } -#endif - if (arg != 0) { - blkno = fileno = (-1); - at_sm = 1; - } - break; - case MTWEOF: - case MTWSM: - if (STp->write_prot) - return (-EACCES); - cmd[0] = WRITE_FILEMARKS; - if (cmd_in == MTWSM) - cmd[1] = 2; - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; - timeout = STp->timeout; -#if DEBUG - if (debugging) { - if (cmd_in == MTWEOF) - printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - else - printk(ST_DEB_MSG "st%d: Writing %d setmarks.\n", dev, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - } -#endif - if (fileno >= 0) - fileno += arg; - blkno = 0; - at_sm = (cmd_in == MTWSM); - break; - case MTREW: - cmd[0] = REZERO_UNIT; +static int st_int_ioctl(struct inode *inode, + unsigned int cmd_in, unsigned long arg) +{ + int timeout; + long ltmp; + int i, ioctl_result; + int chg_eof = TRUE; + unsigned char cmd[10]; + Scsi_Cmnd *SCpnt; + Scsi_Tape *STp; + ST_partstat *STps; + int fileno, blkno, at_sm, undone, datalen; + int dev = TAPE_NR(inode->i_rdev); + + STp = &(scsi_tapes[dev]); + if (STp->ready != ST_READY && cmd_in != MTLOAD) { + if (STp->ready == ST_NO_TAPE) + return (-ENOMEDIUM); + else + return (-EIO); + } + timeout = STp->long_timeout; + STps = &(STp->ps[STp->partition]); + fileno = STps->drv_file; + blkno = STps->drv_block; + at_sm = STps->at_sm; + + memset(cmd, 0, 10); + datalen = 0; + switch (cmd_in) { + case MTFSFM: + chg_eof = FALSE; /* Changed from the FSF after this */ + case MTFSF: + cmd[0] = SPACE; + cmd[1] = 0x01; /* Space FileMarks */ + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n", + dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); +#endif + if (fileno >= 0) + fileno += arg; + blkno = 0; + at_sm &= (arg == 0); + break; + case MTBSFM: + chg_eof = FALSE; /* Changed from the FSF after this */ + case MTBSF: + cmd[0] = SPACE; + cmd[1] = 0x01; /* Space FileMarks */ + ltmp = (-arg); + cmd[2] = (ltmp >> 16); + cmd[3] = (ltmp >> 8); + cmd[4] = ltmp; +#if DEBUG + if (debugging) { + if (cmd[2] & 0x80) + ltmp = 0xff000000; + ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; + printk(ST_DEB_MSG "st%d: Spacing tape backward over %ld filemarks.\n", + dev, (-ltmp)); + } +#endif + if (fileno >= 0) + fileno -= arg; + blkno = (-1); /* We can't know the block number */ + at_sm &= (arg == 0); + break; + case MTFSR: + cmd[0] = SPACE; + cmd[1] = 0x00; /* Space Blocks */ + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); +#endif + if (blkno >= 0) + blkno += arg; + at_sm &= (arg == 0); + break; + case MTBSR: + cmd[0] = SPACE; + cmd[1] = 0x00; /* Space Blocks */ + ltmp = (-arg); + cmd[2] = (ltmp >> 16); + cmd[3] = (ltmp >> 8); + cmd[4] = ltmp; +#if DEBUG + if (debugging) { + if (cmd[2] & 0x80) + ltmp = 0xff000000; + ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; + printk(ST_DEB_MSG "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp)); + } +#endif + if (blkno >= 0) + blkno -= arg; + at_sm &= (arg == 0); + break; + case MTFSS: + cmd[0] = SPACE; + cmd[1] = 0x04; /* Space Setmarks */ + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); +#endif + if (arg != 0) { + blkno = fileno = (-1); + at_sm = 1; + } + break; + case MTBSS: + cmd[0] = SPACE; + cmd[1] = 0x04; /* Space Setmarks */ + ltmp = (-arg); + cmd[2] = (ltmp >> 16); + cmd[3] = (ltmp >> 8); + cmd[4] = ltmp; +#if DEBUG + if (debugging) { + if (cmd[2] & 0x80) + ltmp = 0xff000000; + ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; + printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n", + dev, (-ltmp)); + } +#endif + if (arg != 0) { + blkno = fileno = (-1); + at_sm = 1; + } + break; + case MTWEOF: + case MTWSM: + if (STp->write_prot) + return (-EACCES); + cmd[0] = WRITE_FILEMARKS; + if (cmd_in == MTWSM) + cmd[1] = 2; + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; + timeout = STp->timeout; +#if DEBUG + if (debugging) { + if (cmd_in == MTWEOF) + printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); + else + printk(ST_DEB_MSG "st%d: Writing %d setmarks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); + } +#endif + if (fileno >= 0) + fileno += arg; + blkno = 0; + at_sm = (cmd_in == MTWSM); + break; + case MTREW: + cmd[0] = REZERO_UNIT; #if ST_NOWAIT - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->timeout; + cmd[1] = 1; /* Don't wait for completion */ + timeout = STp->timeout; #endif #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev); + if (debugging) + printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev); #endif - fileno = blkno = at_sm = 0 ; - break; - case MTOFFL: - case MTLOAD: - case MTUNLOAD: - cmd[0] = START_STOP; - if (cmd_in == MTLOAD) - cmd[4] |= 1; - /* - * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A - */ - if (cmd_in != MTOFFL && - arg >= 1 + MT_ST_HPLOADER_OFFSET - && arg <= 6 + MT_ST_HPLOADER_OFFSET) { -#if DEBUG - if (debugging) { - printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", - dev, (cmd[4]) ? "" : "un", - arg - MT_ST_HPLOADER_OFFSET); - } + fileno = blkno = at_sm = 0; + break; + case MTOFFL: + case MTLOAD: + case MTUNLOAD: + cmd[0] = START_STOP; + if (cmd_in == MTLOAD) + cmd[4] |= 1; + /* + * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A + */ + if (cmd_in != MTOFFL && + arg >= 1 + MT_ST_HPLOADER_OFFSET + && arg <= 6 + MT_ST_HPLOADER_OFFSET) { +#if DEBUG + if (debugging) { + printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", + dev, (cmd[4]) ? "" : "un", + arg - MT_ST_HPLOADER_OFFSET); + } #endif - cmd[3] = arg - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ - } + cmd[3] = arg - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ + } #if ST_NOWAIT - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->timeout; + cmd[1] = 1; /* Don't wait for completion */ + timeout = STp->timeout; #else - timeout = STp->long_timeout; + timeout = STp->long_timeout; #endif #if DEBUG - if (debugging) { - if (cmd_in != MTLOAD) - printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev); - else - printk(ST_DEB_MSG "st%d: Loading tape.\n", dev); - } -#endif - fileno = blkno = at_sm = 0 ; - break; - case MTNOP: -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: No op on tape.\n", dev); -#endif - return 0; /* Should do something ? */ - break; - case MTRETEN: - cmd[0] = START_STOP; + if (debugging) { + if (cmd_in != MTLOAD) + printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev); + else + printk(ST_DEB_MSG "st%d: Loading tape.\n", dev); + } +#endif + fileno = blkno = at_sm = 0; + break; + case MTNOP: +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: No op on tape.\n", dev); +#endif + return 0; /* Should do something ? */ + break; + case MTRETEN: + cmd[0] = START_STOP; #if ST_NOWAIT - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->timeout; + cmd[1] = 1; /* Don't wait for completion */ + timeout = STp->timeout; #endif - cmd[4] = 3; + cmd[4] = 3; #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev); + if (debugging) + printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev); #endif - fileno = blkno = at_sm = 0; - break; - case MTEOM: - if (!STp->fast_mteom) { - /* space to the end of tape */ - ioctl_result = st_int_ioctl(inode, MTFSF, 0x3fff); - fileno = STps->drv_file; - if (STps->eof >= ST_EOD_1) - return 0; - /* The next lines would hide the number of spaced FileMarks - That's why I inserted the previous lines. I had no luck - with detecting EOM with FSF, so we go now to EOM. - Joerg Weule */ - } - else - fileno = (-1); - cmd[0] = SPACE; - cmd[1] = 3; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n", dev); -#endif - blkno = 0; - at_sm = 0; - break; - case MTERASE: - if (STp->write_prot) - return (-EACCES); - cmd[0] = ERASE; - cmd[1] = 1; /* To the end of tape */ + fileno = blkno = at_sm = 0; + break; + case MTEOM: + if (!STp->fast_mteom) { + /* space to the end of tape */ + ioctl_result = st_int_ioctl(inode, MTFSF, 0x3fff); + fileno = STps->drv_file; + if (STps->eof >= ST_EOD_1) + return 0; + /* The next lines would hide the number of spaced FileMarks + That's why I inserted the previous lines. I had no luck + with detecting EOM with FSF, so we go now to EOM. + Joerg Weule */ + } else + fileno = (-1); + cmd[0] = SPACE; + cmd[1] = 3; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n", dev); +#endif + blkno = 0; + at_sm = 0; + break; + case MTERASE: + if (STp->write_prot) + return (-EACCES); + cmd[0] = ERASE; + cmd[1] = 1; /* To the end of tape */ #if ST_NOWAIT - cmd[1] |= 2; /* Don't wait for completion */ - timeout = STp->timeout; + cmd[1] |= 2; /* Don't wait for completion */ + timeout = STp->timeout; #else - timeout = STp->long_timeout * 8; + timeout = STp->long_timeout * 8; #endif #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev); + if (debugging) + printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev); #endif - fileno = blkno = at_sm = 0 ; - break; - case MTLOCK: - chg_eof = FALSE; - cmd[0] = ALLOW_MEDIUM_REMOVAL; - cmd[4] = SCSI_REMOVAL_PREVENT; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev); -#endif; - break; - case MTUNLOCK: - chg_eof = FALSE; - cmd[0] = ALLOW_MEDIUM_REMOVAL; - cmd[4] = SCSI_REMOVAL_ALLOW; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev); -#endif; - break; - case MTSETBLK: /* Set block length */ - case MTSETDENSITY: /* Set tape density */ - case MTSETDRVBUFFER: /* Set drive buffering */ - case SET_DENS_AND_BLK: /* Set density and block size */ - chg_eof = FALSE; - if (STp->dirty || (STp->buffer)->buffer_bytes != 0) - return (-EIO); /* Not allowed if data in buffer */ - if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && - (arg & MT_ST_BLKSIZE_MASK) != 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)) { - printk(KERN_WARNING "st%d: Illegal block size.\n", dev); - return (-EINVAL); - } - cmd[0] = MODE_SELECT; - cmd[4] = datalen = 12; - - memset((STp->buffer)->b_data, 0, 12); - if (cmd_in == MTSETDRVBUFFER) - (STp->buffer)->b_data[2] = (arg & 7) << 4; - else - (STp->buffer)->b_data[2] = - STp->drv_buffer << 4; - (STp->buffer)->b_data[3] = 8; /* block descriptor length */ - if (cmd_in == MTSETDENSITY) { - (STp->buffer)->b_data[4] = arg; - STp->density_changed = TRUE; /* At least we tried ;-) */ - } - else if (cmd_in == SET_DENS_AND_BLK) - (STp->buffer)->b_data[4] = arg >> 24; - else - (STp->buffer)->b_data[4] = STp->density; - if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { - ltmp = arg & MT_ST_BLKSIZE_MASK; - if (cmd_in == MTSETBLK) - STp->blksize_changed = TRUE; /* At least we tried ;-) */ - } - else - ltmp = STp->block_size; - (STp->buffer)->b_data[9] = (ltmp >> 16); - (STp->buffer)->b_data[10] = (ltmp >> 8); - (STp->buffer)->b_data[11] = ltmp; - timeout = STp->timeout; -#if DEBUG - if (debugging) { - if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) - printk(ST_DEB_MSG "st%d: Setting block size to %d bytes.\n", dev, - (STp->buffer)->b_data[9] * 65536 + - (STp->buffer)->b_data[10] * 256 + - (STp->buffer)->b_data[11]); - if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK) - printk(ST_DEB_MSG "st%d: Setting density code to %x.\n", dev, - (STp->buffer)->b_data[4]); - if (cmd_in == MTSETDRVBUFFER) - printk(ST_DEB_MSG "st%d: Setting drive buffer code to %d.\n", dev, - ((STp->buffer)->b_data[2] >> 4) & 7); - } -#endif - break; - default: - return (-ENOSYS); - } - - SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE); - if (!SCpnt) - return (-EBUSY); - - ioctl_result = (STp->buffer)->last_result_fatal; - - if (!ioctl_result) { /* SCSI command successful */ - scsi_release_command(SCpnt); - SCpnt = NULL; - STps->drv_block = blkno; - STps->drv_file = fileno; - STps->at_sm = at_sm; - - if (cmd_in == MTLOCK) - STp->door_locked = ST_LOCKED_EXPLICIT; - else if (cmd_in == MTUNLOCK) - STp->door_locked = ST_UNLOCKED; - - if (cmd_in == MTBSFM) - ioctl_result = st_int_ioctl(inode, MTFSF, 1); - else if (cmd_in == MTFSFM) - ioctl_result = st_int_ioctl(inode, MTBSF, 1); - - if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { - STp->block_size = arg & MT_ST_BLKSIZE_MASK; - if (STp->block_size != 0) - (STp->buffer)->buffer_blocks = - (STp->buffer)->buffer_size / STp->block_size; - (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; - if (cmd_in == SET_DENS_AND_BLK) - STp->density = arg >> MT_ST_DENSITY_SHIFT; - } - else if (cmd_in == MTSETDRVBUFFER) - STp->drv_buffer = (arg & 7); - else if (cmd_in == MTSETDENSITY) - STp->density = arg; - - if (cmd_in == MTEOM) - STps->eof = ST_EOD; - else if (cmd_in == MTFSF) - STps->eof = ST_FM; - else if (chg_eof) - STps->eof = ST_NOEOF; - - - if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) - STp->rew_at_close = 0; - else if (cmd_in == MTLOAD) { - STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0; - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].last_block_valid = FALSE; - } - STp->partition = 0; - } - - } else { /* SCSI command was not completely successful. Don't return - from this block without releasing the SCSI command block! */ - - if (SCpnt->sense_buffer[2] & 0x40) { - if (cmd_in != MTBSF && cmd_in != MTBSFM && - cmd_in != MTBSR && cmd_in != MTBSS) - STps->eof = ST_EOM_OK; - STps->drv_block = 0; - } - - undone = ( - (SCpnt->sense_buffer[3] << 24) + - (SCpnt->sense_buffer[4] << 16) + - (SCpnt->sense_buffer[5] << 8) + - SCpnt->sense_buffer[6] ); - if (cmd_in == MTWEOF && - (SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x4f) == 0x40 && - ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) { - ioctl_result = 0; /* EOF written succesfully at EOM */ - if (fileno >= 0) - fileno++; - STps->drv_file = fileno; - STps->eof = ST_NOEOF; - } - else if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) { - if (fileno >= 0) - STps->drv_file = fileno - undone ; - else - STps->drv_file = fileno; - STps->drv_block = 0; - STps->eof = ST_NOEOF; - } - else if ( (cmd_in == MTBSF) || (cmd_in == MTBSFM) ) { - if (fileno >= 0) - STps->drv_file = fileno + undone ; - else - STps->drv_file = fileno; - STps->drv_block = 0; - STps->eof = ST_NOEOF; - } - else if (cmd_in == MTFSR) { - if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */ - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } - else { - if (blkno >= undone) - STps->drv_block = blkno - undone; - else - STps->drv_block = (-1); - STps->eof = ST_NOEOF; - } - } - else if (cmd_in == MTBSR) { - if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */ - STps->drv_file--; - STps->drv_block = (-1); - } - else { - if (blkno >= 0) - STps->drv_block = blkno + undone; - else - STps->drv_block = (-1); - } - STps->eof = ST_NOEOF; - } - else if (cmd_in == MTEOM) { - STps->drv_file = (-1); - STps->drv_block = (-1); - STps->eof = ST_EOD; - } - else if (chg_eof) - STps->eof = ST_NOEOF; - - if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) - STps->eof = ST_EOD; - - if (cmd_in == MTLOCK) - STp->door_locked = ST_LOCK_FAILS; - - scsi_release_command(SCpnt); - SCpnt = NULL; - } - - return ioctl_result; -} - - - /* Get the tape position. If bt == 2, arg points into a kernel space mt_loc - structure. */ - - static int -get_location(struct inode * inode, unsigned int *block, int *partition, - int logical) -{ - Scsi_Tape *STp; - int dev = TAPE_NR(inode->i_rdev); - int result; - unsigned char scmd[10]; - Scsi_Cmnd *SCpnt; - - STp = &(scsi_tapes[dev]); - if (STp->ready != ST_READY) - return (-EIO); - - memset (scmd, 0, 10); - if ((STp->device)->scsi_level < SCSI_2) { - scmd[0] = QFA_REQUEST_BLOCK; - scmd[4] = 3; - } - else { - scmd[0] = READ_POSITION; - if (!logical && !STp->scsi2_logical) - scmd[1] = 1; - } - SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE); - if (!SCpnt) - return (-EBUSY); - - if ((STp->buffer)->last_result_fatal != 0 || - (STp->device->scsi_level >= SCSI_2 && - ((STp->buffer)->b_data[0] & 4) != 0)) { - *block = *partition = 0; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev); -#endif - result = (-EIO); - } - else { - result = 0; - if ((STp->device)->scsi_level < SCSI_2) { - *block = ((STp->buffer)->b_data[0] << 16) - + ((STp->buffer)->b_data[1] << 8) - + (STp->buffer)->b_data[2]; - *partition = 0; - } - else { - *block = ((STp->buffer)->b_data[4] << 24) - + ((STp->buffer)->b_data[5] << 16) - + ((STp->buffer)->b_data[6] << 8) - + (STp->buffer)->b_data[7]; - *partition = (STp->buffer)->b_data[1]; - if (((STp->buffer)->b_data[0] & 0x80) && - (STp->buffer)->b_data[1] == 0) /* BOP of partition 0 */ - STp->ps[0].drv_block = STp->ps[0].drv_file = 0; - } -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev, - *block, *partition); -#endif - - } - scsi_release_command(SCpnt); - SCpnt = NULL; + fileno = blkno = at_sm = 0; + break; + case MTLOCK: + chg_eof = FALSE; + cmd[0] = ALLOW_MEDIUM_REMOVAL; + cmd[4] = SCSI_REMOVAL_PREVENT; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev); +#endif /* ; */ + break; + case MTUNLOCK: + chg_eof = FALSE; + cmd[0] = ALLOW_MEDIUM_REMOVAL; + cmd[4] = SCSI_REMOVAL_ALLOW; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev); +#endif /* ; */ + break; + case MTSETBLK: /* Set block length */ + case MTSETDENSITY: /* Set tape density */ + case MTSETDRVBUFFER: /* Set drive buffering */ + case SET_DENS_AND_BLK: /* Set density and block size */ + chg_eof = FALSE; + if (STp->dirty || (STp->buffer)->buffer_bytes != 0) + return (-EIO); /* Not allowed if data in buffer */ + if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && + (arg & MT_ST_BLKSIZE_MASK) != 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)) { + printk(KERN_WARNING "st%d: Illegal block size.\n", dev); + return (-EINVAL); + } + cmd[0] = MODE_SELECT; + cmd[4] = datalen = 12; + + memset((STp->buffer)->b_data, 0, 12); + if (cmd_in == MTSETDRVBUFFER) + (STp->buffer)->b_data[2] = (arg & 7) << 4; + else + (STp->buffer)->b_data[2] = + STp->drv_buffer << 4; + (STp->buffer)->b_data[3] = 8; /* block descriptor length */ + if (cmd_in == MTSETDENSITY) { + (STp->buffer)->b_data[4] = arg; + STp->density_changed = TRUE; /* At least we tried ;-) */ + } else if (cmd_in == SET_DENS_AND_BLK) + (STp->buffer)->b_data[4] = arg >> 24; + else + (STp->buffer)->b_data[4] = STp->density; + if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { + ltmp = arg & MT_ST_BLKSIZE_MASK; + if (cmd_in == MTSETBLK) + STp->blksize_changed = TRUE; /* At least we tried ;-) */ + } else + ltmp = STp->block_size; + (STp->buffer)->b_data[9] = (ltmp >> 16); + (STp->buffer)->b_data[10] = (ltmp >> 8); + (STp->buffer)->b_data[11] = ltmp; + timeout = STp->timeout; +#if DEBUG + if (debugging) { + if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) + printk(ST_DEB_MSG "st%d: Setting block size to %d bytes.\n", dev, + (STp->buffer)->b_data[9] * 65536 + + (STp->buffer)->b_data[10] * 256 + + (STp->buffer)->b_data[11]); + if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK) + printk(ST_DEB_MSG "st%d: Setting density code to %x.\n", dev, + (STp->buffer)->b_data[4]); + if (cmd_in == MTSETDRVBUFFER) + printk(ST_DEB_MSG "st%d: Setting drive buffer code to %d.\n", dev, + ((STp->buffer)->b_data[2] >> 4) & 7); + } +#endif + break; + default: + return (-ENOSYS); + } + + SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE); + if (!SCpnt) + return (-EBUSY); + + ioctl_result = (STp->buffer)->last_result_fatal; + + if (!ioctl_result) { /* SCSI command successful */ + scsi_release_command(SCpnt); + SCpnt = NULL; + STps->drv_block = blkno; + STps->drv_file = fileno; + STps->at_sm = at_sm; + + if (cmd_in == MTLOCK) + STp->door_locked = ST_LOCKED_EXPLICIT; + else if (cmd_in == MTUNLOCK) + STp->door_locked = ST_UNLOCKED; + + if (cmd_in == MTBSFM) + ioctl_result = st_int_ioctl(inode, MTFSF, 1); + else if (cmd_in == MTFSFM) + ioctl_result = st_int_ioctl(inode, MTBSF, 1); + + if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { + STp->block_size = arg & MT_ST_BLKSIZE_MASK; + if (STp->block_size != 0) + (STp->buffer)->buffer_blocks = + (STp->buffer)->buffer_size / STp->block_size; + (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; + if (cmd_in == SET_DENS_AND_BLK) + STp->density = arg >> MT_ST_DENSITY_SHIFT; + } else if (cmd_in == MTSETDRVBUFFER) + STp->drv_buffer = (arg & 7); + else if (cmd_in == MTSETDENSITY) + STp->density = arg; + + if (cmd_in == MTEOM) + STps->eof = ST_EOD; + else if (cmd_in == MTFSF) + STps->eof = ST_FM; + else if (chg_eof) + STps->eof = ST_NOEOF; + + + if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) + STp->rew_at_close = 0; + else if (cmd_in == MTLOAD) { + STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0; + for (i = 0; i < ST_NBR_PARTITIONS; i++) { + STp->ps[i].rw = ST_IDLE; + STp->ps[i].last_block_valid = FALSE; + } + STp->partition = 0; + } + } else { /* SCSI command was not completely successful. Don't return + from this block without releasing the SCSI command block! */ - return result; + if (SCpnt->sense_buffer[2] & 0x40) { + if (cmd_in != MTBSF && cmd_in != MTBSFM && + cmd_in != MTBSR && cmd_in != MTBSS) + STps->eof = ST_EOM_OK; + STps->drv_block = 0; + } + undone = ( + (SCpnt->sense_buffer[3] << 24) + + (SCpnt->sense_buffer[4] << 16) + + (SCpnt->sense_buffer[5] << 8) + + SCpnt->sense_buffer[6]); + if (cmd_in == MTWEOF && + (SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x4f) == 0x40 && + ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) { + ioctl_result = 0; /* EOF written succesfully at EOM */ + if (fileno >= 0) + fileno++; + STps->drv_file = fileno; + STps->eof = ST_NOEOF; + } else if ((cmd_in == MTFSF) || (cmd_in == MTFSFM)) { + if (fileno >= 0) + STps->drv_file = fileno - undone; + else + STps->drv_file = fileno; + STps->drv_block = 0; + STps->eof = ST_NOEOF; + } else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) { + if (fileno >= 0) + STps->drv_file = fileno + undone; + else + STps->drv_file = fileno; + STps->drv_block = 0; + STps->eof = ST_NOEOF; + } else if (cmd_in == MTFSR) { + if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */ + if (STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + STps->eof = ST_FM; + } else { + if (blkno >= undone) + STps->drv_block = blkno - undone; + else + STps->drv_block = (-1); + STps->eof = ST_NOEOF; + } + } else if (cmd_in == MTBSR) { + if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */ + STps->drv_file--; + STps->drv_block = (-1); + } else { + if (blkno >= 0) + STps->drv_block = blkno + undone; + else + STps->drv_block = (-1); + } + STps->eof = ST_NOEOF; + } else if (cmd_in == MTEOM) { + STps->drv_file = (-1); + STps->drv_block = (-1); + STps->eof = ST_EOD; + } else if (chg_eof) + STps->eof = ST_NOEOF; + + if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) + STps->eof = ST_EOD; + + if (cmd_in == MTLOCK) + STp->door_locked = ST_LOCK_FAILS; + + scsi_release_command(SCpnt); + SCpnt = NULL; + } + + return ioctl_result; +} + + +/* Get the tape position. If bt == 2, arg points into a kernel space mt_loc + structure. */ + +static int get_location(struct inode *inode, unsigned int *block, int *partition, + int logical) +{ + Scsi_Tape *STp; + int dev = TAPE_NR(inode->i_rdev); + int result; + unsigned char scmd[10]; + Scsi_Cmnd *SCpnt; + + STp = &(scsi_tapes[dev]); + if (STp->ready != ST_READY) + return (-EIO); + + memset(scmd, 0, 10); + if ((STp->device)->scsi_level < SCSI_2) { + scmd[0] = QFA_REQUEST_BLOCK; + scmd[4] = 3; + } else { + scmd[0] = READ_POSITION; + if (!logical && !STp->scsi2_logical) + scmd[1] = 1; + } + SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE); + if (!SCpnt) + return (-EBUSY); + + if ((STp->buffer)->last_result_fatal != 0 || + (STp->device->scsi_level >= SCSI_2 && + ((STp->buffer)->b_data[0] & 4) != 0)) { + *block = *partition = 0; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev); +#endif + result = (-EIO); + } else { + result = 0; + if ((STp->device)->scsi_level < SCSI_2) { + *block = ((STp->buffer)->b_data[0] << 16) + + ((STp->buffer)->b_data[1] << 8) + + (STp->buffer)->b_data[2]; + *partition = 0; + } else { + *block = ((STp->buffer)->b_data[4] << 24) + + ((STp->buffer)->b_data[5] << 16) + + ((STp->buffer)->b_data[6] << 8) + + (STp->buffer)->b_data[7]; + *partition = (STp->buffer)->b_data[1]; + if (((STp->buffer)->b_data[0] & 0x80) && + (STp->buffer)->b_data[1] == 0) /* BOP of partition 0 */ + STp->ps[0].drv_block = STp->ps[0].drv_file = 0; + } +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev, + *block, *partition); +#endif + + } + scsi_release_command(SCpnt); + SCpnt = NULL; + + return result; } /* Set the tape block and partition. Negative partition means that only the block should be set in vendor specific way. */ - static int -set_location(struct inode * inode, unsigned int block, int partition, - int logical) -{ - Scsi_Tape *STp; - ST_partstat *STps; - int dev = TAPE_NR(inode->i_rdev); - int result, p; - unsigned int blk; - int timeout; - unsigned char scmd[10]; - Scsi_Cmnd *SCpnt; - - STp = &(scsi_tapes[dev]); - if (STp->ready != ST_READY) - return (-EIO); - timeout = STp->long_timeout; - STps = &(STp->ps[STp->partition]); - -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Setting block to %d and partition to %d.\n", - dev, block, partition); - if (partition < 0) - return (-EIO); -#endif - - /* Update the location at the partition we are leaving */ - if ((!STp->can_partitions && partition != 0) || - partition >= ST_NBR_PARTITIONS) - return (-EINVAL); - if (partition != STp->partition) { - if (get_location(inode, &blk, &p, 1)) - STps->last_block_valid = FALSE; - else { - STps->last_block_valid = TRUE; - STps->last_block_visited = blk; +static int set_location(struct inode *inode, unsigned int block, int partition, + int logical) +{ + Scsi_Tape *STp; + ST_partstat *STps; + int dev = TAPE_NR(inode->i_rdev); + int result, p; + unsigned int blk; + int timeout; + unsigned char scmd[10]; + Scsi_Cmnd *SCpnt; + + STp = &(scsi_tapes[dev]); + if (STp->ready != ST_READY) + return (-EIO); + timeout = STp->long_timeout; + STps = &(STp->ps[STp->partition]); + #if DEBUG if (debugging) - printk(ST_DEB_MSG "st%d: Visited block %d for partition %d saved.\n", - dev, blk, STp->partition); + printk(ST_DEB_MSG "st%d: Setting block to %d and partition to %d.\n", + dev, block, partition); + if (partition < 0) + return (-EIO); +#endif + + /* Update the location at the partition we are leaving */ + if ((!STp->can_partitions && partition != 0) || + partition >= ST_NBR_PARTITIONS) + return (-EINVAL); + if (partition != STp->partition) { + if (get_location(inode, &blk, &p, 1)) + STps->last_block_valid = FALSE; + else { + STps->last_block_valid = TRUE; + STps->last_block_visited = blk; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Visited block %d for partition %d saved.\n", + dev, blk, STp->partition); #endif - } - } - - memset (scmd, 0, 10); - if ((STp->device)->scsi_level < SCSI_2) { - scmd[0] = QFA_SEEK_BLOCK; - scmd[2] = (block >> 16); - scmd[3] = (block >> 8); - scmd[4] = block; - scmd[5] = 0; - } - else { - scmd[0] = SEEK_10; - scmd[3] = (block >> 24); - scmd[4] = (block >> 16); - scmd[5] = (block >> 8); - scmd[6] = block; - if (!logical && !STp->scsi2_logical) - scmd[1] = 4; - if (STp->partition != partition) { - scmd[1] |= 2; - scmd[8] = partition; + } + } + memset(scmd, 0, 10); + if ((STp->device)->scsi_level < SCSI_2) { + scmd[0] = QFA_SEEK_BLOCK; + scmd[2] = (block >> 16); + scmd[3] = (block >> 8); + scmd[4] = block; + scmd[5] = 0; + } else { + scmd[0] = SEEK_10; + scmd[3] = (block >> 24); + scmd[4] = (block >> 16); + scmd[5] = (block >> 8); + scmd[6] = block; + if (!logical && !STp->scsi2_logical) + scmd[1] = 4; + if (STp->partition != partition) { + scmd[1] |= 2; + scmd[8] = partition; #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Trying to change partition from %d to %d\n", - dev, STp->partition, partition); + if (debugging) + printk(ST_DEB_MSG "st%d: Trying to change partition from %d to %d\n", + dev, STp->partition, partition); #endif - } - } + } + } #if ST_NOWAIT - scmd[1] |= 1; /* Don't wait for completion */ - timeout = STp->timeout; + scmd[1] |= 1; /* Don't wait for completion */ + timeout = STp->timeout; #endif - SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE); - if (!SCpnt) - return (-EBUSY); - - STps->drv_block = STps->drv_file = (-1); - STps->eof = ST_NOEOF; - if ((STp->buffer)->last_result_fatal != 0) { - result = (-EIO); - if (STp->can_partitions && - (STp->device)->scsi_level >= SCSI_2 && - (p = find_partition(inode)) >= 0) - STp->partition = p; - } - else { - if (STp->can_partitions) { - STp->partition = partition; - STps = &(STp->ps[partition]); - if (!STps->last_block_valid || - STps->last_block_visited != block) { - STps->at_sm = 0; - STps->rw = ST_IDLE; + SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE); + if (!SCpnt) + return (-EBUSY); + + STps->drv_block = STps->drv_file = (-1); + STps->eof = ST_NOEOF; + if ((STp->buffer)->last_result_fatal != 0) { + result = (-EIO); + if (STp->can_partitions && + (STp->device)->scsi_level >= SCSI_2 && + (p = find_partition(inode)) >= 0) + STp->partition = p; + } else { + if (STp->can_partitions) { + STp->partition = partition; + STps = &(STp->ps[partition]); + if (!STps->last_block_valid || + STps->last_block_visited != block) { + STps->at_sm = 0; + STps->rw = ST_IDLE; + } + } else + STps->at_sm = 0; + if (block == 0) + STps->drv_block = STps->drv_file = 0; + result = 0; } - } - else - STps->at_sm = 0; - if (block == 0) - STps->drv_block = STps->drv_file = 0; - result = 0; - } - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_command(SCpnt); + SCpnt = NULL; - return result; + return result; } /* Find the current partition number for the drive status. Called from open and returns either partition number of negative error code. */ - static int -find_partition(struct inode *inode) +static int find_partition(struct inode *inode) { - int i, partition; - unsigned int block; + int i, partition; + unsigned int block; - if ((i = get_location(inode, &block, &partition, 1)) < 0) - return i; - if (partition >= ST_NBR_PARTITIONS) - return (-EIO); - return partition; + if ((i = get_location(inode, &block, &partition, 1)) < 0) + return i; + if (partition >= ST_NBR_PARTITIONS) + return (-EIO); + return partition; } /* Change the partition if necessary */ - static int -update_partition(struct inode * inode) +static int update_partition(struct inode *inode) { - int dev = TAPE_NR(inode->i_rdev); - Scsi_Tape *STp; - ST_partstat *STps; - - STp = &(scsi_tapes[dev]); - if (STp->partition == STp->new_partition) - return 0; - STps = &(STp->ps[STp->new_partition]); - if (!STps->last_block_valid) - STps->last_block_visited = 0; - return set_location(inode, STps->last_block_visited, STp->new_partition, 1); + int dev = TAPE_NR(inode->i_rdev); + Scsi_Tape *STp; + ST_partstat *STps; + + STp = &(scsi_tapes[dev]); + if (STp->partition == STp->new_partition) + return 0; + STps = &(STp->ps[STp->new_partition]); + if (!STps->last_block_valid) + STps->last_block_visited = 0; + return set_location(inode, STps->last_block_visited, STp->new_partition, 1); } - - /* Functions for reading and writing the medium partition mode page. These + +/* Functions for reading and writing the medium partition mode page. These seem to work with Wangtek 6200HS and HP C1533A. */ #define PART_PAGE 0x11 @@ -2736,656 +2631,635 @@ /* Get the number of partitions on the tape. As a side effect reads the mode page into the tape buffer. */ - static int -nbr_partitions(struct inode * inode) +static int nbr_partitions(struct inode *inode) { - int dev = TAPE_NR(inode->i_rdev), result; - Scsi_Tape *STp; - Scsi_Cmnd * SCpnt = NULL; - unsigned char cmd[10]; - - STp = &(scsi_tapes[dev]); - if (STp->ready != ST_READY) - return (-EIO); - - memset ((void *) &cmd[0], 0, 10); - cmd[0] = MODE_SENSE; - cmd[1] = 8; /* Page format */ - cmd[2] = PART_PAGE; - cmd[4] = 200; - - SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES, TRUE); - if (SCpnt == NULL) - return (-EBUSY); - scsi_release_command(SCpnt); - SCpnt = NULL; - - if ((STp->buffer)->last_result_fatal != 0) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n", dev); -#endif - result = (-EIO); - } - else { - result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] + 1; + int dev = TAPE_NR(inode->i_rdev), result; + Scsi_Tape *STp; + Scsi_Cmnd *SCpnt = NULL; + unsigned char cmd[10]; + + STp = &(scsi_tapes[dev]); + if (STp->ready != ST_READY) + return (-EIO); + + memset((void *) &cmd[0], 0, 10); + cmd[0] = MODE_SENSE; + cmd[1] = 8; /* Page format */ + cmd[2] = PART_PAGE; + cmd[4] = 200; + + SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES, TRUE); + if (SCpnt == NULL) + return (-EBUSY); + scsi_release_command(SCpnt); + SCpnt = NULL; + + if ((STp->buffer)->last_result_fatal != 0) { +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n", dev); +#endif + result = (-EIO); + } else { + result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] + 1; #if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result); + if (debugging) + printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result); #endif - } + } - return result; + return result; } /* Partition the tape into two partitions if size > 0 or one partition if size == 0 */ - static int -partition_tape(struct inode * inode, int size) +static int partition_tape(struct inode *inode, int size) { - int dev = TAPE_NR(inode->i_rdev), result; - int length; - Scsi_Tape *STp; - Scsi_Cmnd * SCpnt = NULL; - unsigned char cmd[10], *bp; - - if ((result = nbr_partitions(inode)) < 0) - return result; - STp = &(scsi_tapes[dev]); - - /* The mode page is in the buffer. Let's modify it and write it. */ - bp = &((STp->buffer)->b_data[0]); - if (size <= 0) { - length = 8; - bp[MODE_HEADER_LENGTH + 3] = 0; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n", dev); -#endif - } - else { - length = 10; - bp[MODE_HEADER_LENGTH + 3] = 1; - bp[MODE_HEADER_LENGTH + 8] = (size >> 8) & 0xff; - bp[MODE_HEADER_LENGTH + 9] = size & 0xff; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Formatting tape with two partition (1 = %d MB).\n", - dev, size); -#endif - } - bp[MODE_HEADER_LENGTH + 6] = 0; - bp[MODE_HEADER_LENGTH + 7] = 0; - bp[MODE_HEADER_LENGTH + 4] = 0x30; /* IDP | PSUM = MB */ - - bp[0] = 0; - bp[1] = 0; - bp[MODE_HEADER_LENGTH] &= 0x3f; - bp[MODE_HEADER_LENGTH + 1] = length - 2; - - memset(cmd, 0, 10); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = length + MODE_HEADER_LENGTH; - - SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout, - MAX_READY_RETRIES, TRUE); - if (SCpnt == NULL) - return (-EBUSY); - scsi_release_command(SCpnt); - SCpnt = NULL; - - if ((STp->buffer)->last_result_fatal != 0) { - printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev); - result = (-EIO); - } - else - result = 0; + int dev = TAPE_NR(inode->i_rdev), result; + int length; + Scsi_Tape *STp; + Scsi_Cmnd *SCpnt = NULL; + unsigned char cmd[10], *bp; + + if ((result = nbr_partitions(inode)) < 0) + return result; + STp = &(scsi_tapes[dev]); + + /* The mode page is in the buffer. Let's modify it and write it. */ + bp = &((STp->buffer)->b_data[0]); + if (size <= 0) { + length = 8; + bp[MODE_HEADER_LENGTH + 3] = 0; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n", dev); +#endif + } else { + length = 10; + bp[MODE_HEADER_LENGTH + 3] = 1; + bp[MODE_HEADER_LENGTH + 8] = (size >> 8) & 0xff; + bp[MODE_HEADER_LENGTH + 9] = size & 0xff; +#if DEBUG + if (debugging) + printk(ST_DEB_MSG "st%d: Formatting tape with two partition (1 = %d MB).\n", + dev, size); +#endif + } + bp[MODE_HEADER_LENGTH + 6] = 0; + bp[MODE_HEADER_LENGTH + 7] = 0; + bp[MODE_HEADER_LENGTH + 4] = 0x30; /* IDP | PSUM = MB */ + + bp[0] = 0; + bp[1] = 0; + bp[MODE_HEADER_LENGTH] &= 0x3f; + bp[MODE_HEADER_LENGTH + 1] = length - 2; - return result; -} + memset(cmd, 0, 10); + cmd[0] = MODE_SELECT; + cmd[1] = 0x10; + cmd[4] = length + MODE_HEADER_LENGTH; + + SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout, + MAX_READY_RETRIES, TRUE); + if (SCpnt == NULL) + return (-EBUSY); + scsi_release_command(SCpnt); + SCpnt = NULL; + if ((STp->buffer)->last_result_fatal != 0) { + printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev); + result = (-EIO); + } else + result = 0; + return result; +} + + /* The ioctl command */ - static int -st_ioctl(struct inode * inode,struct file * file, - unsigned int cmd_in, unsigned long arg) -{ - int i, cmd_nr, cmd_type, bt; - unsigned int blk; - struct mtop mtc; - struct mtpos mt_pos; - Scsi_Tape *STp; - ST_mode *STm; - ST_partstat *STps; - int dev = TAPE_NR(inode->i_rdev); - - STp = &(scsi_tapes[dev]); -#if DEBUG - if (debugging && !STp->in_use) { - printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); - return (-EIO); - } -#endif - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(STp->device) ) { - return -ENXIO; - } - - cmd_type = _IOC_TYPE(cmd_in); - cmd_nr = _IOC_NR(cmd_in); - - if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { - if (_IOC_SIZE(cmd_in) != sizeof(mtc)) - return (-EINVAL); - - i = copy_from_user((char *) &mtc, (char *)arg, sizeof(struct mtop)); - if (i) - return (-EFAULT); - - if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { - printk(KERN_WARNING "st%d: MTSETDRVBUFFER only allowed for root.\n", dev); - return (-EPERM); - } - if (!STm->defined && - (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) - return (-ENXIO); - - if (!(STp->device)->was_reset) { - - if (STps->eof == ST_FM_HIT) { - if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) { - mtc.mt_count -= 1; - if (STps->drv_file >= 0) - STps->drv_file += 1; - } - else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) { - mtc.mt_count += 1; - if (STps->drv_file >= 0) - STps->drv_file += 1; - } - } - - if (mtc.mt_op == MTSEEK) { - /* Old position must be restored if partition will be changed */ - i = !STp->can_partitions || - (STp->new_partition != STp->partition); - } - else { - i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || - mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || - mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || - mtc.mt_op == MTCOMPRESSION; - } - i = flush_buffer(inode, file, i); - if (i < 0) - return i; - } - else { - /* - * If there was a bus reset, block further access - * to this device. If the user wants to rewind the tape, - * then reset the flag and allow access again. - */ - if(mtc.mt_op != MTREW && - mtc.mt_op != MTOFFL && - mtc.mt_op != MTRETEN && - mtc.mt_op != MTERASE && - mtc.mt_op != MTSEEK && - mtc.mt_op != MTEOM) - return (-EIO); - STp->device->was_reset = 0; - if (STp->door_locked != ST_UNLOCKED && - STp->door_locked != ST_LOCK_FAILS) { - if (st_int_ioctl(inode, MTLOCK, 0)) { - printk(KERN_NOTICE "st%d: Could not relock door after bus reset.\n", - dev); - STp->door_locked = ST_UNLOCKED; - } - } - } - - if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && - mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM && - mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART) - STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ - - if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) - st_int_ioctl(inode, MTUNLOCK, 0); /* Ignore result! */ - - if (mtc.mt_op == MTSETDRVBUFFER && - (mtc.mt_count & MT_ST_OPTIONS) != 0) - return st_set_options(inode, mtc.mt_count); - if (mtc.mt_op == MTSETPART) { - if (!STp->can_partitions || - mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) - return (-EINVAL); - if (mtc.mt_count >= STp->nbr_partitions && - (STp->nbr_partitions = nbr_partitions(inode)) < 0) - return (-EIO); - if (mtc.mt_count >= STp->nbr_partitions) - return (-EINVAL); - STp->new_partition = mtc.mt_count; - return 0; - } - if (mtc.mt_op == MTMKPART) { - if (!STp->can_partitions) - return (-EINVAL); - if ((i = st_int_ioctl(inode, MTREW, 0)) < 0 || - (i = partition_tape(inode, mtc.mt_count)) < 0) - return i; - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].at_sm = 0; - STp->ps[i].last_block_valid = FALSE; - } - STp->partition = STp->new_partition = 0; - STp->nbr_partitions = 1; /* Bad guess ?-) */ - STps->drv_block = STps->drv_file = 0; - return 0; - } - if (mtc.mt_op == MTSEEK) { - i = set_location(inode, mtc.mt_count, STp->new_partition, 0); - if (!STp->can_partitions) - STp->ps[0].rw = ST_IDLE; - return i; - } - if (STp->can_partitions && STp->ready == ST_READY && - (i = update_partition(inode)) < 0) - return i; - if (mtc.mt_op == MTCOMPRESSION) - return st_compression(STp, (mtc.mt_count & 1)); - else - return st_int_ioctl(inode, mtc.mt_op, mtc.mt_count); - } - - if (!STm->defined) - return (-ENXIO); - - if ((i = flush_buffer(inode, file, FALSE)) < 0) - return i; - if (STp->can_partitions && - (i = update_partition(inode)) < 0) - return i; - - if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { - - if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) - return (-EINVAL); - - (STp->mt_status)->mt_dsreg = - ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) | - ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); - (STp->mt_status)->mt_blkno = STps->drv_block; - (STp->mt_status)->mt_fileno = STps->drv_file; - if (STp->block_size != 0) { - if (STps->rw == ST_WRITING) - (STp->mt_status)->mt_blkno += - (STp->buffer)->buffer_bytes / STp->block_size; - else if (STps->rw == ST_READING) - (STp->mt_status)->mt_blkno -= ((STp->buffer)->buffer_bytes + - STp->block_size - 1) / STp->block_size; - } - - (STp->mt_status)->mt_gstat = 0; - if (STp->drv_write_prot) - (STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff); - if ((STp->mt_status)->mt_blkno == 0) { - if ((STp->mt_status)->mt_fileno == 0) - (STp->mt_status)->mt_gstat |= GMT_BOT(0xffffffff); - else - (STp->mt_status)->mt_gstat |= GMT_EOF(0xffffffff); - } - (STp->mt_status)->mt_resid = STp->partition; - if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR) - (STp->mt_status)->mt_gstat |= GMT_EOT(0xffffffff); - else if (STps->eof >= ST_EOM_OK) - (STp->mt_status)->mt_gstat |= GMT_EOD(0xffffffff); - if (STp->density == 1) - (STp->mt_status)->mt_gstat |= GMT_D_800(0xffffffff); - else if (STp->density == 2) - (STp->mt_status)->mt_gstat |= GMT_D_1600(0xffffffff); - else if (STp->density == 3) - (STp->mt_status)->mt_gstat |= GMT_D_6250(0xffffffff); - if (STp->ready == ST_READY) - (STp->mt_status)->mt_gstat |= GMT_ONLINE(0xffffffff); - if (STp->ready == ST_NO_TAPE) - (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff); - if (STps->at_sm) - (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff); - if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) || - STp->drv_buffer != 0) - (STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff); - - i = copy_to_user((char *)arg, (char *)(STp->mt_status), - sizeof(struct mtget)); - if (i) - return (-EFAULT); - - (STp->mt_status)->mt_erreg = 0; /* Clear after read */ - return 0; - } /* End of MTIOCGET */ - - if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { - if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) - return (-EINVAL); - if ((i = get_location(inode, &blk, &bt, 0)) < 0) - return i; - mt_pos.mt_blkno = blk; - i = copy_to_user((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos)); - if (i) - return (-EFAULT); - return 0; - } +static int st_ioctl(struct inode *inode, struct file *file, + unsigned int cmd_in, unsigned long arg) +{ + int i, cmd_nr, cmd_type, bt; + unsigned int blk; + struct mtop mtc; + struct mtpos mt_pos; + Scsi_Tape *STp; + ST_mode *STm; + ST_partstat *STps; + int dev = TAPE_NR(inode->i_rdev); + + STp = &(scsi_tapes[dev]); +#if DEBUG + if (debugging && !STp->in_use) { + printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); + return (-EIO); + } +#endif + STm = &(STp->modes[STp->current_mode]); + STps = &(STp->ps[STp->partition]); - return scsi_ioctl(STp->device, cmd_in, (void *) arg); -} + /* + * If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. + */ + if (!scsi_block_when_processing_errors(STp->device)) { + return -ENXIO; + } + cmd_type = _IOC_TYPE(cmd_in); + cmd_nr = _IOC_NR(cmd_in); + if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { + if (_IOC_SIZE(cmd_in) != sizeof(mtc)) + return (-EINVAL); + + i = copy_from_user((char *) &mtc, (char *) arg, sizeof(struct mtop)); + if (i) + return (-EFAULT); + + if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { + printk(KERN_WARNING "st%d: MTSETDRVBUFFER only allowed for root.\n", dev); + return (-EPERM); + } + if (!STm->defined && + (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) + return (-ENXIO); + + if (!(STp->device)->was_reset) { + + if (STps->eof == ST_FM_HIT) { + if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || mtc.mt_op == MTEOM) { + mtc.mt_count -= 1; + if (STps->drv_file >= 0) + STps->drv_file += 1; + } else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) { + mtc.mt_count += 1; + if (STps->drv_file >= 0) + STps->drv_file += 1; + } + } + if (mtc.mt_op == MTSEEK) { + /* Old position must be restored if partition will be changed */ + i = !STp->can_partitions || + (STp->new_partition != STp->partition); + } else { + i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || + mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || + mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || + mtc.mt_op == MTCOMPRESSION; + } + i = flush_buffer(inode, file, i); + if (i < 0) + return i; + } else { + /* + * If there was a bus reset, block further access + * to this device. If the user wants to rewind the tape, + * then reset the flag and allow access again. + */ + if (mtc.mt_op != MTREW && + mtc.mt_op != MTOFFL && + mtc.mt_op != MTRETEN && + mtc.mt_op != MTERASE && + mtc.mt_op != MTSEEK && + mtc.mt_op != MTEOM) + return (-EIO); + STp->device->was_reset = 0; + if (STp->door_locked != ST_UNLOCKED && + STp->door_locked != ST_LOCK_FAILS) { + if (st_int_ioctl(inode, MTLOCK, 0)) { + printk(KERN_NOTICE "st%d: Could not relock door after bus reset.\n", + dev); + STp->door_locked = ST_UNLOCKED; + } + } + } + + if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && + mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM && + mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART) + STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ + + if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) + st_int_ioctl(inode, MTUNLOCK, 0); /* Ignore result! */ + + if (mtc.mt_op == MTSETDRVBUFFER && + (mtc.mt_count & MT_ST_OPTIONS) != 0) + return st_set_options(inode, mtc.mt_count); + if (mtc.mt_op == MTSETPART) { + if (!STp->can_partitions || + mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) + return (-EINVAL); + if (mtc.mt_count >= STp->nbr_partitions && + (STp->nbr_partitions = nbr_partitions(inode)) < 0) + return (-EIO); + if (mtc.mt_count >= STp->nbr_partitions) + return (-EINVAL); + STp->new_partition = mtc.mt_count; + return 0; + } + if (mtc.mt_op == MTMKPART) { + if (!STp->can_partitions) + return (-EINVAL); + if ((i = st_int_ioctl(inode, MTREW, 0)) < 0 || + (i = partition_tape(inode, mtc.mt_count)) < 0) + return i; + for (i = 0; i < ST_NBR_PARTITIONS; i++) { + STp->ps[i].rw = ST_IDLE; + STp->ps[i].at_sm = 0; + STp->ps[i].last_block_valid = FALSE; + } + STp->partition = STp->new_partition = 0; + STp->nbr_partitions = 1; /* Bad guess ?-) */ + STps->drv_block = STps->drv_file = 0; + return 0; + } + if (mtc.mt_op == MTSEEK) { + i = set_location(inode, mtc.mt_count, STp->new_partition, 0); + if (!STp->can_partitions) + STp->ps[0].rw = ST_IDLE; + return i; + } + if (STp->can_partitions && STp->ready == ST_READY && + (i = update_partition(inode)) < 0) + return i; + if (mtc.mt_op == MTCOMPRESSION) + return st_compression(STp, (mtc.mt_count & 1)); + else + return st_int_ioctl(inode, mtc.mt_op, mtc.mt_count); + } + if (!STm->defined) + return (-ENXIO); + + if ((i = flush_buffer(inode, file, FALSE)) < 0) + return i; + if (STp->can_partitions && + (i = update_partition(inode)) < 0) + return i; + + if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { + + if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) + return (-EINVAL); + + (STp->mt_status)->mt_dsreg = + ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) | + ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); + (STp->mt_status)->mt_blkno = STps->drv_block; + (STp->mt_status)->mt_fileno = STps->drv_file; + if (STp->block_size != 0) { + if (STps->rw == ST_WRITING) + (STp->mt_status)->mt_blkno += + (STp->buffer)->buffer_bytes / STp->block_size; + else if (STps->rw == ST_READING) + (STp->mt_status)->mt_blkno -= ((STp->buffer)->buffer_bytes + + STp->block_size - 1) / STp->block_size; + } + (STp->mt_status)->mt_gstat = 0; + if (STp->drv_write_prot) + (STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff); + if ((STp->mt_status)->mt_blkno == 0) { + if ((STp->mt_status)->mt_fileno == 0) + (STp->mt_status)->mt_gstat |= GMT_BOT(0xffffffff); + else + (STp->mt_status)->mt_gstat |= GMT_EOF(0xffffffff); + } + (STp->mt_status)->mt_resid = STp->partition; + if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR) + (STp->mt_status)->mt_gstat |= GMT_EOT(0xffffffff); + else if (STps->eof >= ST_EOM_OK) + (STp->mt_status)->mt_gstat |= GMT_EOD(0xffffffff); + if (STp->density == 1) + (STp->mt_status)->mt_gstat |= GMT_D_800(0xffffffff); + else if (STp->density == 2) + (STp->mt_status)->mt_gstat |= GMT_D_1600(0xffffffff); + else if (STp->density == 3) + (STp->mt_status)->mt_gstat |= GMT_D_6250(0xffffffff); + if (STp->ready == ST_READY) + (STp->mt_status)->mt_gstat |= GMT_ONLINE(0xffffffff); + if (STp->ready == ST_NO_TAPE) + (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff); + if (STps->at_sm) + (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff); + if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) || + STp->drv_buffer != 0) + (STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff); + + i = copy_to_user((char *) arg, (char *) (STp->mt_status), + sizeof(struct mtget)); + if (i) + return (-EFAULT); + + (STp->mt_status)->mt_erreg = 0; /* Clear after read */ + return 0; + } /* End of MTIOCGET */ + if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { + if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) + return (-EINVAL); + if ((i = get_location(inode, &blk, &bt, 0)) < 0) + return i; + mt_pos.mt_blkno = blk; + i = copy_to_user((char *) arg, (char *) (&mt_pos), sizeof(struct mtpos)); + if (i) + return (-EFAULT); + return 0; + } + return scsi_ioctl(STp->device, cmd_in, (void *) arg); +} + /* Try to allocate a new tape buffer */ - static ST_buffer * -new_tape_buffer( int from_initialization, int need_dma ) +static ST_buffer * + new_tape_buffer(int from_initialization, int need_dma) { - int i, priority, b_size, got = 0, segs = 0; - ST_buffer *tb; + int i, priority, b_size, got = 0, segs = 0; + ST_buffer *tb; - if (st_nbr_buffers >= st_template.dev_max) - return NULL; /* Should never happen */ + if (st_nbr_buffers >= st_template.dev_max) + return NULL; /* Should never happen */ - if (from_initialization) - priority = GFP_ATOMIC; - else - priority = GFP_KERNEL; - - i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist); - tb = (ST_buffer *)scsi_init_malloc(i, priority); - if (tb) { - tb->this_size = i; - if (need_dma) - priority |= GFP_DMA; - - /* Try to allocate the first segment up to ST_FIRST_ORDER and the - others big enough to reach the goal */ - for (b_size = PAGE_SIZE << ST_FIRST_ORDER; - b_size / 2 >= st_buffer_size && b_size > PAGE_SIZE; ) - b_size /= 2; - for ( ; b_size >= PAGE_SIZE; b_size /= 2) { - tb->sg[0].address = - (unsigned char *)scsi_init_malloc(b_size, priority); - if (tb->sg[0].address != NULL) { - tb->sg[0].alt_address = NULL; - tb->sg[0].length = b_size; - break; - } - } - if (tb->sg[segs].address == NULL) { - scsi_init_free((char *)tb, tb->this_size); - tb = NULL; - } - else { /* Got something, continue */ - - for (b_size = PAGE_SIZE; - st_buffer_size > tb->sg[0].length + (ST_FIRST_SG - 1) * b_size; ) - b_size *= 2; - - for (segs=1, got=tb->sg[0].length; - got < st_buffer_size && segs < ST_FIRST_SG; ) { - tb->sg[segs].address = - (unsigned char *)scsi_init_malloc(b_size, priority); - if (tb->sg[segs].address == NULL) { - if (st_buffer_size - got <= - (ST_FIRST_SG - segs) * b_size / 2) { - b_size /= 2; /* Large enough for the rest of the buffers */ - continue; - } - for (i=0; i < segs - 1; i++) - scsi_init_free(tb->sg[i].address, tb->sg[i].length); - scsi_init_free((char *)tb, tb->this_size); - tb = NULL; - break; - } - tb->sg[segs].alt_address = NULL; - tb->sg[segs].length = b_size; - got += b_size; - segs++; - } - } - } - if (!tb) { - printk(KERN_NOTICE "st: Can't allocate new tape buffer (nbr %d).\n", - st_nbr_buffers); - return NULL; - } - tb->sg_segs = tb->orig_sg_segs = segs; - tb->b_data = tb->sg[0].address; - -#if DEBUG - if (debugging) { - printk(ST_DEB_MSG - "st: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n", - st_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data); - printk(ST_DEB_MSG - "st: segment sizes: first %d, last %d bytes.\n", - tb->sg[0].length, tb->sg[segs-1].length); - } -#endif - tb->in_use = 0; - tb->dma = need_dma; - tb->buffer_size = got; - tb->writing = 0; - st_buffers[st_nbr_buffers++] = tb; + if (from_initialization) + priority = GFP_ATOMIC; + else + priority = GFP_KERNEL; + + i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist); + tb = (ST_buffer *) scsi_init_malloc(i, priority); + if (tb) { + tb->this_size = i; + if (need_dma) + priority |= GFP_DMA; + + /* Try to allocate the first segment up to ST_FIRST_ORDER and the + others big enough to reach the goal */ + for (b_size = PAGE_SIZE << ST_FIRST_ORDER; + b_size / 2 >= st_buffer_size && b_size > PAGE_SIZE;) + b_size /= 2; + for (; b_size >= PAGE_SIZE; b_size /= 2) { + tb->sg[0].address = + (unsigned char *) scsi_init_malloc(b_size, priority); + if (tb->sg[0].address != NULL) { + tb->sg[0].alt_address = NULL; + tb->sg[0].length = b_size; + break; + } + } + if (tb->sg[segs].address == NULL) { + scsi_init_free((char *) tb, tb->this_size); + tb = NULL; + } else { /* Got something, continue */ + + for (b_size = PAGE_SIZE; + st_buffer_size > tb->sg[0].length + (ST_FIRST_SG - 1) * b_size;) + b_size *= 2; + + for (segs = 1, got = tb->sg[0].length; + got < st_buffer_size && segs < ST_FIRST_SG;) { + tb->sg[segs].address = + (unsigned char *) scsi_init_malloc(b_size, priority); + if (tb->sg[segs].address == NULL) { + if (st_buffer_size - got <= + (ST_FIRST_SG - segs) * b_size / 2) { + b_size /= 2; /* Large enough for the rest of the buffers */ + continue; + } + for (i = 0; i < segs - 1; i++) + scsi_init_free(tb->sg[i].address, tb->sg[i].length); + scsi_init_free((char *) tb, tb->this_size); + tb = NULL; + break; + } + tb->sg[segs].alt_address = NULL; + tb->sg[segs].length = b_size; + got += b_size; + segs++; + } + } + } + if (!tb) { + printk(KERN_NOTICE "st: Can't allocate new tape buffer (nbr %d).\n", + st_nbr_buffers); + return NULL; + } + tb->sg_segs = tb->orig_sg_segs = segs; + tb->b_data = tb->sg[0].address; + +#if DEBUG + if (debugging) { + printk(ST_DEB_MSG + "st: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n", + st_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data); + printk(ST_DEB_MSG + "st: segment sizes: first %d, last %d bytes.\n", + tb->sg[0].length, tb->sg[segs - 1].length); + } +#endif + tb->in_use = 0; + tb->dma = need_dma; + tb->buffer_size = got; + tb->writing = 0; + st_buffers[st_nbr_buffers++] = tb; - return tb; + return tb; } /* Try to allocate a temporary enlarged tape buffer */ - static int -enlarge_buffer(ST_buffer *STbuffer, int new_size, int need_dma) +static int enlarge_buffer(ST_buffer * STbuffer, int new_size, int need_dma) { - int segs, nbr, max_segs, b_size, priority, got; + int segs, nbr, max_segs, b_size, priority, got; - normalize_buffer(STbuffer); + normalize_buffer(STbuffer); - max_segs = STbuffer->use_sg; - if (max_segs > st_max_sg_segs) - max_segs = st_max_sg_segs; - nbr = max_segs - STbuffer->sg_segs; - if (nbr <= 0) - return FALSE; - - priority = GFP_KERNEL; - if (need_dma) - priority |= GFP_DMA; - for (b_size = PAGE_SIZE; b_size * nbr < new_size - STbuffer->buffer_size; ) - b_size *= 2; - - for (segs=STbuffer->sg_segs, got=STbuffer->buffer_size; - segs < max_segs && got < new_size; ) { - STbuffer->sg[segs].address = - (unsigned char *)scsi_init_malloc(b_size, priority); - if (STbuffer->sg[segs].address == NULL) { - if (new_size - got <= (max_segs - segs) * b_size / 2) { - b_size /= 2; /* Large enough for the rest of the buffers */ - continue; - } - printk(KERN_NOTICE "st: failed to enlarge buffer to %d bytes.\n", - new_size); - normalize_buffer(STbuffer); - return FALSE; - } - STbuffer->sg[segs].alt_address = NULL; - STbuffer->sg[segs].length = b_size; - STbuffer->sg_segs += 1; - got += b_size; - STbuffer->buffer_size = got; - segs++; - } -#if DEBUG - if (debugging) - printk(ST_DEB_MSG - "st: Succeeded to enlarge buffer to %d bytes (segs %d->%d, %d).\n", - got, STbuffer->orig_sg_segs, STbuffer->sg_segs, b_size); + max_segs = STbuffer->use_sg; + if (max_segs > st_max_sg_segs) + max_segs = st_max_sg_segs; + nbr = max_segs - STbuffer->sg_segs; + if (nbr <= 0) + return FALSE; + + priority = GFP_KERNEL; + if (need_dma) + priority |= GFP_DMA; + for (b_size = PAGE_SIZE; b_size * nbr < new_size - STbuffer->buffer_size;) + b_size *= 2; + + for (segs = STbuffer->sg_segs, got = STbuffer->buffer_size; + segs < max_segs && got < new_size;) { + STbuffer->sg[segs].address = + (unsigned char *) scsi_init_malloc(b_size, priority); + if (STbuffer->sg[segs].address == NULL) { + if (new_size - got <= (max_segs - segs) * b_size / 2) { + b_size /= 2; /* Large enough for the rest of the buffers */ + continue; + } + printk(KERN_NOTICE "st: failed to enlarge buffer to %d bytes.\n", + new_size); + normalize_buffer(STbuffer); + return FALSE; + } + STbuffer->sg[segs].alt_address = NULL; + STbuffer->sg[segs].length = b_size; + STbuffer->sg_segs += 1; + got += b_size; + STbuffer->buffer_size = got; + segs++; + } +#if DEBUG + if (debugging) + printk(ST_DEB_MSG + "st: Succeeded to enlarge buffer to %d bytes (segs %d->%d, %d).\n", + got, STbuffer->orig_sg_segs, STbuffer->sg_segs, b_size); #endif - return TRUE; + return TRUE; } /* Release the extra buffer */ - static void -normalize_buffer(ST_buffer *STbuffer) +static void normalize_buffer(ST_buffer * STbuffer) { - int i; + int i; - for (i=STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) { - scsi_init_free(STbuffer->sg[i].address, STbuffer->sg[i].length); - STbuffer->buffer_size -= STbuffer->sg[i].length; - } + for (i = STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) { + scsi_init_free(STbuffer->sg[i].address, STbuffer->sg[i].length); + STbuffer->buffer_size -= STbuffer->sg[i].length; + } #if DEBUG - if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs) - printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes (segs %d).\n", - STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs); + if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs) + printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes (segs %d).\n", + STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs); #endif - STbuffer->sg_segs = STbuffer->orig_sg_segs; + STbuffer->sg_segs = STbuffer->orig_sg_segs; } /* Move data from the user buffer to the tape buffer. Returns zero (success) or negative error code. */ - static int -append_to_buffer(const char *ubp, ST_buffer *st_bp, int do_count) +static int append_to_buffer(const char *ubp, ST_buffer * st_bp, int do_count) { - int i, cnt, res, offset; + int i, cnt, res, offset; - for (i=0, offset=st_bp->buffer_bytes; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "st: append_to_buffer offset overflow.\n"); - return (-EIO); - } - for ( ; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count; - res = copy_from_user(st_bp->sg[i].address + offset, ubp, cnt); - if (res) - return (-EFAULT); - do_count -= cnt; - st_bp->buffer_bytes += cnt; - ubp += cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "st: append_to_buffer overflow (left %d).\n", - do_count); - return (-EIO); - } - return 0; + for (i = 0, offset = st_bp->buffer_bytes; + i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) + offset -= st_bp->sg[i].length; + if (i == st_bp->sg_segs) { /* Should never happen */ + printk(KERN_WARNING "st: append_to_buffer offset overflow.\n"); + return (-EIO); + } + for (; i < st_bp->sg_segs && do_count > 0; i++) { + cnt = st_bp->sg[i].length - offset < do_count ? + st_bp->sg[i].length - offset : do_count; + res = copy_from_user(st_bp->sg[i].address + offset, ubp, cnt); + if (res) + return (-EFAULT); + do_count -= cnt; + st_bp->buffer_bytes += cnt; + ubp += cnt; + offset = 0; + } + if (do_count) { /* Should never happen */ + printk(KERN_WARNING "st: append_to_buffer overflow (left %d).\n", + do_count); + return (-EIO); + } + return 0; } /* Move data from the tape buffer to the user buffer. Returns zero (success) or negative error code. */ - static int -from_buffer(ST_buffer *st_bp, char *ubp, int do_count) +static int from_buffer(ST_buffer * st_bp, char *ubp, int do_count) { - int i, cnt, res, offset; + int i, cnt, res, offset; - for (i=0, offset=st_bp->read_pointer; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "st: from_buffer offset overflow.\n"); - return (-EIO); - } - for ( ; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count; - res = copy_to_user(ubp, st_bp->sg[i].address + offset, cnt); - if (res) - return (-EFAULT); - do_count -= cnt; - st_bp->buffer_bytes -= cnt; - st_bp->read_pointer += cnt; - ubp += cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "st: from_buffer overflow (left %d).\n", - do_count); - return (-EIO); - } - return 0; + for (i = 0, offset = st_bp->read_pointer; + i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) + offset -= st_bp->sg[i].length; + if (i == st_bp->sg_segs) { /* Should never happen */ + printk(KERN_WARNING "st: from_buffer offset overflow.\n"); + return (-EIO); + } + for (; i < st_bp->sg_segs && do_count > 0; i++) { + cnt = st_bp->sg[i].length - offset < do_count ? + st_bp->sg[i].length - offset : do_count; + res = copy_to_user(ubp, st_bp->sg[i].address + offset, cnt); + if (res) + return (-EFAULT); + do_count -= cnt; + st_bp->buffer_bytes -= cnt; + st_bp->read_pointer += cnt; + ubp += cnt; + offset = 0; + } + if (do_count) { /* Should never happen */ + printk(KERN_WARNING "st: from_buffer overflow (left %d).\n", + do_count); + return (-EIO); + } + return 0; } /* Validate the options from command line or module parameters */ static void validate_options(void) { - if (buffer_kbs > 0) - st_buffer_size = buffer_kbs * ST_KILOBYTE; - if (write_threshold_kbs > 0) - st_write_threshold = write_threshold_kbs * ST_KILOBYTE; - else if (buffer_kbs > 0) - st_write_threshold = st_buffer_size - 2048; - if (st_write_threshold > st_buffer_size) { - st_write_threshold = st_buffer_size; - printk(KERN_WARNING "st: write_threshold limited to %d bytes.\n", - st_write_threshold); - } - if (max_buffers >= 0) - st_max_buffers = max_buffers; - if (max_sg_segs >= ST_FIRST_SG) - st_max_sg_segs = max_sg_segs; + if (buffer_kbs > 0) + st_buffer_size = buffer_kbs * ST_KILOBYTE; + if (write_threshold_kbs > 0) + st_write_threshold = write_threshold_kbs * ST_KILOBYTE; + else if (buffer_kbs > 0) + st_write_threshold = st_buffer_size - 2048; + if (st_write_threshold > st_buffer_size) { + st_write_threshold = st_buffer_size; + printk(KERN_WARNING "st: write_threshold limited to %d bytes.\n", + st_write_threshold); + } + if (max_buffers >= 0) + st_max_buffers = max_buffers; + if (max_sg_segs >= ST_FIRST_SG) + st_max_sg_segs = max_sg_segs; } #ifndef MODULE /* Set the boot options. Syntax is defined in README.st. -*/ + */ static int __init st_setup(char *str) { - int i, len, ints[5]; - char *stp; + int i, len, ints[5]; + char *stp; - stp = get_options(str, ARRAY_SIZE(ints), ints); + stp = get_options(str, ARRAY_SIZE(ints), ints); - if (ints[0] > 0) { - for (i=0; i < ints[0] && i < ARRAY_SIZE(parms) ; i++) - *parms[i].val = ints[i + 1]; - } - else { - while (stp != NULL) { - for (i=0; i < ARRAY_SIZE(parms); i++) { - len = strlen(parms[i].name); - if (!strncmp(stp, parms[i].name, len) && - (*(stp + len) == ':' || *(stp + len) == '=')) { - *parms[i].val = simple_strtoul(stp + len + 1, NULL, 0); - break; - } - } - if (i >= sizeof(parms) / sizeof(struct st_dev_parm)) - printk(KERN_WARNING "st: illegal parameter in '%s'\n", - stp); - stp = strchr(stp, ','); - if (stp) - stp++; + if (ints[0] > 0) { + for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++) + *parms[i].val = ints[i + 1]; + } else { + while (stp != NULL) { + for (i = 0; i < ARRAY_SIZE(parms); i++) { + len = strlen(parms[i].name); + if (!strncmp(stp, parms[i].name, len) && + (*(stp + len) == ':' || *(stp + len) == '=')) { + *parms[i].val = simple_strtoul(stp + len + 1, NULL, 0); + break; + } + } + if (i >= sizeof(parms) / sizeof(struct st_dev_parm)) + printk(KERN_WARNING "st: illegal parameter in '%s'\n", + stp); + stp = strchr(stp, ','); + if (stp) + stp++; + } } - } - validate_options(); + validate_options(); - return 1; + return 1; } __setup("st=", st_setup); @@ -3393,108 +3267,112 @@ #endif -static struct file_operations st_fops = { - NULL, /* lseek - default */ - st_read, /* read - general block-dev read */ - st_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - st_ioctl, /* ioctl */ - NULL, /* mmap */ - scsi_tape_open, /* open */ - scsi_tape_flush, /* flush */ - scsi_tape_close, /* release */ - NULL /* fsync */ +static struct file_operations st_fops = +{ + NULL, /* lseek - default */ + st_read, /* read - general block-dev read */ + st_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + st_ioctl, /* ioctl */ + NULL, /* mmap */ + scsi_tape_open, /* open */ + scsi_tape_flush, /* flush */ + scsi_tape_close, /* release */ + NULL /* fsync */ }; -static int st_attach(Scsi_Device * SDp){ - Scsi_Tape * tpnt; - ST_mode * STm; - ST_partstat * STps; - int i; - - if (SDp->type != TYPE_TAPE) - return 1; - - if (st_template.nr_dev >= st_template.dev_max) { - SDp->attached--; - return 1; - } - - for(tpnt = scsi_tapes, i=0; idevice) break; - - if(i >= st_template.dev_max) panic ("scsi_devices corrupt (st)"); - - scsi_tapes[i].device = SDp; - if (SDp->scsi_level <= 2) - scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1; - else - scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2; - - tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i); - tpnt->dirty = 0; - tpnt->in_use = 0; - tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ - tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; - tpnt->density = 0; - tpnt->do_auto_lock = ST_AUTO_LOCK; - tpnt->can_bsr = ST_IN_FILE_POS; - tpnt->can_partitions = 0; - tpnt->two_fm = ST_TWO_FM; - tpnt->fast_mteom = ST_FAST_MTEOM; - tpnt->scsi2_logical = ST_SCSI2LOGICAL; - tpnt->write_threshold = st_write_threshold; - tpnt->default_drvbuffer = 0xff; /* No forced buffering */ - tpnt->partition = 0; - tpnt->new_partition = 0; - tpnt->nbr_partitions = 0; - tpnt->timeout = ST_TIMEOUT; - tpnt->long_timeout = ST_LONG_TIMEOUT; - - for (i=0; i < ST_NBR_MODES; i++) { - STm = &(tpnt->modes[i]); - STm->defined = FALSE; - STm->sysv = ST_SYSV; - STm->defaults_for_writes = 0; - STm->do_async_writes = ST_ASYNC_WRITES; - STm->do_buffer_writes = ST_BUFFER_WRITES; - STm->do_read_ahead = ST_READ_AHEAD; - STm->default_compression = ST_DONT_TOUCH; - STm->default_blksize = (-1); /* No forced size */ - STm->default_density = (-1); /* No forced density */ - } - - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(tpnt->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = FALSE; - STps->drv_block = (-1); - STps->drv_file = (-1); - } +static int st_attach(Scsi_Device * SDp) +{ + Scsi_Tape *tpnt; + ST_mode *STm; + ST_partstat *STps; + int i; + + if (SDp->type != TYPE_TAPE) + return 1; + + if (st_template.nr_dev >= st_template.dev_max) { + SDp->attached--; + return 1; + } + for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++) + if (!tpnt->device) + break; + + if (i >= st_template.dev_max) + panic("scsi_devices corrupt (st)"); + + scsi_tapes[i].device = SDp; + if (SDp->scsi_level <= 2) + scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1; + else + scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2; + + tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i); + tpnt->dirty = 0; + tpnt->in_use = 0; + tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ + tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; + tpnt->density = 0; + tpnt->do_auto_lock = ST_AUTO_LOCK; + tpnt->can_bsr = ST_IN_FILE_POS; + tpnt->can_partitions = 0; + tpnt->two_fm = ST_TWO_FM; + tpnt->fast_mteom = ST_FAST_MTEOM; + tpnt->scsi2_logical = ST_SCSI2LOGICAL; + tpnt->write_threshold = st_write_threshold; + tpnt->default_drvbuffer = 0xff; /* No forced buffering */ + tpnt->partition = 0; + tpnt->new_partition = 0; + tpnt->nbr_partitions = 0; + tpnt->timeout = ST_TIMEOUT; + tpnt->long_timeout = ST_LONG_TIMEOUT; + + for (i = 0; i < ST_NBR_MODES; i++) { + STm = &(tpnt->modes[i]); + STm->defined = FALSE; + STm->sysv = ST_SYSV; + STm->defaults_for_writes = 0; + STm->do_async_writes = ST_ASYNC_WRITES; + STm->do_buffer_writes = ST_BUFFER_WRITES; + STm->do_read_ahead = ST_READ_AHEAD; + STm->default_compression = ST_DONT_TOUCH; + STm->default_blksize = (-1); /* No forced size */ + STm->default_density = (-1); /* No forced density */ + } - tpnt->current_mode = 0; - tpnt->modes[0].defined = TRUE; + for (i = 0; i < ST_NBR_PARTITIONS; i++) { + STps = &(tpnt->ps[i]); + STps->rw = ST_IDLE; + STps->eof = ST_NOEOF; + STps->at_sm = 0; + STps->last_block_valid = FALSE; + STps->drv_block = (-1); + STps->drv_file = (-1); + } - tpnt->density_changed = tpnt->compression_changed = - tpnt->blksize_changed = FALSE; + tpnt->current_mode = 0; + tpnt->modes[0].defined = TRUE; - st_template.nr_dev++; - return 0; + tpnt->density_changed = tpnt->compression_changed = + tpnt->blksize_changed = FALSE; + + st_template.nr_dev++; + return 0; }; static int st_detect(Scsi_Device * SDp) { - if(SDp->type != TYPE_TAPE) return 0; + if (SDp->type != TYPE_TAPE) + return 0; - printk(KERN_WARNING - "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", - st_template.dev_noticed++, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + printk(KERN_WARNING + "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", + st_template.dev_noticed++, + SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - return 1; + return 1; } static int st_registered = 0; @@ -3502,142 +3380,142 @@ /* Driver initialization (not __init because may be called later) */ static int st_init() { - int i; - Scsi_Tape * STp; - int target_nbr; - - if (st_template.dev_noticed == 0) return 0; - - printk(KERN_INFO "st: bufsize %d, wrt %d, max init. buffers %d, s/g segs %d.\n", - st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs); - - if(!st_registered) { - if (register_chrdev(SCSI_TAPE_MAJOR,"st",&st_fops)) { - printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",MAJOR_NR); - return 1; - } - st_registered++; - } - - if (scsi_tapes) return 0; - st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS; - if (st_template.dev_max < ST_MAX_TAPES) - st_template.dev_max = ST_MAX_TAPES; - if (st_template.dev_max > 128 / ST_NBR_MODES) - printk(KERN_INFO "st: Only %d tapes accessible.\n", 128 / ST_NBR_MODES); - scsi_tapes = - (Scsi_Tape *) scsi_init_malloc(st_template.dev_max * sizeof(Scsi_Tape), - GFP_ATOMIC); - if (scsi_tapes == NULL) { - printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n"); - unregister_chrdev(SCSI_TAPE_MAJOR, "st"); - return 1; - } - -#if DEBUG - printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n", - st_buffer_size, st_write_threshold); -#endif - - memset(scsi_tapes, 0, st_template.dev_max * sizeof(Scsi_Tape)); - for (i=0; i < st_template.dev_max; ++i) { - STp = &(scsi_tapes[i]); - STp->capacity = 0xfffff; - STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget), - GFP_ATOMIC); - /* Initialize status */ - memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget)); - } - - /* Allocate the buffers */ - st_buffers = - (ST_buffer **) scsi_init_malloc(st_template.dev_max * sizeof(ST_buffer *), - GFP_ATOMIC); - if (st_buffers == NULL) { - printk(KERN_ERR "Unable to allocate tape buffer pointers.\n"); - unregister_chrdev(SCSI_TAPE_MAJOR, "st"); - scsi_init_free((char *) scsi_tapes, - st_template.dev_max * sizeof(Scsi_Tape)); - return 1; - } - - target_nbr = st_template.dev_noticed; - if (target_nbr < ST_EXTRA_DEVS) - target_nbr = ST_EXTRA_DEVS; - if (target_nbr > st_max_buffers) - target_nbr = st_max_buffers; - - for (i=st_nbr_buffers=0; i < target_nbr; i++) { - if (!new_tape_buffer(TRUE, TRUE)) { - if (i == 0) { - printk(KERN_INFO "No tape buffers allocated at initialization.\n"); - break; - } - printk(KERN_INFO "Number of tape buffers adjusted.\n"); - break; - } - } + int i; + Scsi_Tape *STp; + int target_nbr; + + if (st_template.dev_noticed == 0) + return 0; + + printk(KERN_INFO "st: bufsize %d, wrt %d, max init. buffers %d, s/g segs %d.\n", + st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs); + + if (!st_registered) { + if (register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) { + printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR); + return 1; + } + st_registered++; + } + if (scsi_tapes) + return 0; + st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS; + if (st_template.dev_max < ST_MAX_TAPES) + st_template.dev_max = ST_MAX_TAPES; + if (st_template.dev_max > 128 / ST_NBR_MODES) + printk(KERN_INFO "st: Only %d tapes accessible.\n", 128 / ST_NBR_MODES); + scsi_tapes = + (Scsi_Tape *) scsi_init_malloc(st_template.dev_max * sizeof(Scsi_Tape), + GFP_ATOMIC); + if (scsi_tapes == NULL) { + printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n"); + unregister_chrdev(SCSI_TAPE_MAJOR, "st"); + return 1; + } +#if DEBUG + printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n", + st_buffer_size, st_write_threshold); +#endif + + memset(scsi_tapes, 0, st_template.dev_max * sizeof(Scsi_Tape)); + for (i = 0; i < st_template.dev_max; ++i) { + STp = &(scsi_tapes[i]); + STp->capacity = 0xfffff; + STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget), + GFP_ATOMIC); + /* Initialize status */ + memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget)); + } - return 0; + /* Allocate the buffers */ + st_buffers = + (ST_buffer **) scsi_init_malloc(st_template.dev_max * sizeof(ST_buffer *), + GFP_ATOMIC); + if (st_buffers == NULL) { + printk(KERN_ERR "Unable to allocate tape buffer pointers.\n"); + unregister_chrdev(SCSI_TAPE_MAJOR, "st"); + scsi_init_free((char *) scsi_tapes, + st_template.dev_max * sizeof(Scsi_Tape)); + return 1; + } + target_nbr = st_template.dev_noticed; + if (target_nbr < ST_EXTRA_DEVS) + target_nbr = ST_EXTRA_DEVS; + if (target_nbr > st_max_buffers) + target_nbr = st_max_buffers; + + for (i = st_nbr_buffers = 0; i < target_nbr; i++) { + if (!new_tape_buffer(TRUE, TRUE)) { + if (i == 0) { + printk(KERN_INFO "No tape buffers allocated at initialization.\n"); + break; + } + printk(KERN_INFO "Number of tape buffers adjusted.\n"); + break; + } + } + + return 0; } static void st_detach(Scsi_Device * SDp) { - Scsi_Tape * tpnt; - int i; + Scsi_Tape *tpnt; + int i; - for(tpnt = scsi_tapes, i=0; idevice == SDp) { - tpnt->device = NULL; - SDp->attached--; - st_template.nr_dev--; - st_template.dev_noticed--; - return; - } - return; + for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++) + if (tpnt->device == SDp) { + tpnt->device = NULL; + SDp->attached--; + st_template.nr_dev--; + st_template.dev_noticed--; + return; + } + return; } #ifdef MODULE -int __init init_module(void) { - int result; +int __init init_module(void) +{ + int result; - validate_options(); + validate_options(); - st_template.module = &__this_module; - result = scsi_register_module(MODULE_SCSI_DEV, &st_template); - if (result) - return result; + st_template.module = &__this_module; + result = scsi_register_module(MODULE_SCSI_DEV, &st_template); + if (result) + return result; - return 0; + return 0; } -void cleanup_module( void) +void cleanup_module(void) { - int i, j; + int i, j; - scsi_unregister_module(MODULE_SCSI_DEV, &st_template); - unregister_chrdev(SCSI_TAPE_MAJOR, "st"); - st_registered--; - if(scsi_tapes != NULL) { - scsi_init_free((char *) scsi_tapes, - st_template.dev_max * sizeof(Scsi_Tape)); - - if (st_buffers != NULL) { - for (i=0; i < st_nbr_buffers; i++) - if (st_buffers[i] != NULL) { - for (j=0; j < st_buffers[i]->sg_segs; j++) - scsi_init_free((char *) st_buffers[i]->sg[j].address, - st_buffers[i]->sg[j].length); - scsi_init_free((char *) st_buffers[i], st_buffers[i]->this_size); + scsi_unregister_module(MODULE_SCSI_DEV, &st_template); + unregister_chrdev(SCSI_TAPE_MAJOR, "st"); + st_registered--; + if (scsi_tapes != NULL) { + scsi_init_free((char *) scsi_tapes, + st_template.dev_max * sizeof(Scsi_Tape)); + + if (st_buffers != NULL) { + for (i = 0; i < st_nbr_buffers; i++) + { + if (st_buffers[i] != NULL) { + for (j = 0; j < st_buffers[i]->sg_segs; j++) + scsi_init_free((char *) st_buffers[i]->sg[j].address, + st_buffers[i]->sg[j].length); + scsi_init_free((char *) st_buffers[i], st_buffers[i]->this_size); + } + } + scsi_init_free((char *) st_buffers, st_template.dev_max * sizeof(ST_buffer *)); + } } - - scsi_init_free((char *) st_buffers, - st_template.dev_max * sizeof(ST_buffer *)); - } - } - st_template.dev_max = 0; - printk(KERN_INFO "st: Unloaded.\n"); + st_template.dev_max = 0; + printk(KERN_INFO "st: Unloaded.\n"); } -#endif /* MODULE */ +#endif /* MODULE */ diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v2.3.16/linux/drivers/scsi/st.h Sat May 22 14:50:07 1999 +++ linux/drivers/scsi/st.h Sat Sep 4 10:48:46 1999 @@ -1,9 +1,9 @@ #ifndef _ST_H - #define _ST_H +#define _ST_H /* - $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.h,v 1.1 1992/04/24 18:01:50 root Exp root $ -*/ + $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.h,v 1.1 1992/04/24 18:01:50 root Exp root $ + */ #ifndef _SCSI_H #include "scsi.h" @@ -11,36 +11,36 @@ /* The tape buffer descriptor. */ typedef struct { - unsigned char in_use; - unsigned char dma; /* DMA-able buffer */ - int this_size; /* allocated size of the structure */ - int buffer_size; - int buffer_blocks; - int buffer_bytes; - int read_pointer; - int writing; - int last_result; - int last_result_fatal; - Scsi_Cmnd *last_SCpnt; - unsigned char *b_data; - unsigned short use_sg; /* zero or number of segments for this adapter */ - unsigned short sg_segs; /* total number of allocated segments */ - unsigned short orig_sg_segs; /* number of segments allocated at first try */ - struct scatterlist sg[1]; /* MUST BE last item */ + unsigned char in_use; + unsigned char dma; /* DMA-able buffer */ + int this_size; /* allocated size of the structure */ + int buffer_size; + int buffer_blocks; + int buffer_bytes; + int read_pointer; + int writing; + int last_result; + int last_result_fatal; + Scsi_Cmnd *last_SCpnt; + unsigned char *b_data; + unsigned short use_sg; /* zero or number of segments for this adapter */ + unsigned short sg_segs; /* total number of allocated segments */ + unsigned short orig_sg_segs; /* number of segments allocated at first try */ + struct scatterlist sg[1]; /* MUST BE last item */ } ST_buffer; /* The tape mode definition */ typedef struct { - unsigned char defined; - unsigned char sysv; /* SYS V semantics? */ - unsigned char do_async_writes; - unsigned char do_buffer_writes; - unsigned char do_read_ahead; - unsigned char defaults_for_writes; - unsigned char default_compression; /* 0 = don't touch, etc */ - short default_density; /* Forced density, -1 = no value */ - int default_blksize; /* Forced blocksize, -1 = no value */ + unsigned char defined; + unsigned char sysv; /* SYS V semantics? */ + unsigned char do_async_writes; + unsigned char do_buffer_writes; + unsigned char do_read_ahead; + unsigned char defaults_for_writes; + unsigned char default_compression; /* 0 = don't touch, etc */ + short default_density; /* Forced density, -1 = no value */ + int default_blksize; /* Forced blocksize, -1 = no value */ } ST_mode; #define ST_NBR_MODE_BITS 2 @@ -50,76 +50,76 @@ /* The status related to each partition */ typedef struct { - unsigned char rw; - unsigned char eof; - unsigned char at_sm; - unsigned char last_block_valid; - u32 last_block_visited; - int drv_block; /* The block where the drive head is */ - int drv_file; + unsigned char rw; + unsigned char eof; + unsigned char at_sm; + unsigned char last_block_valid; + u32 last_block_visited; + int drv_block; /* The block where the drive head is */ + int drv_file; } ST_partstat; #define ST_NBR_PARTITIONS 4 /* The tape drive descriptor */ typedef struct { - kdev_t devt; - unsigned capacity; - Scsi_Device* device; - struct semaphore sem; - ST_buffer * buffer; - - /* Drive characteristics */ - unsigned char omit_blklims; - unsigned char do_auto_lock; - unsigned char can_bsr; - unsigned char can_partitions; - unsigned char two_fm; - unsigned char fast_mteom; - unsigned char restr_dma; - unsigned char scsi2_logical; - unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ - int write_threshold; - int timeout; /* timeout for normal commands */ - int long_timeout; /* timeout for commands known to take long time*/ - - /* Mode characteristics */ - ST_mode modes[ST_NBR_MODES]; - int current_mode; - - /* Status variables */ - int partition; - int new_partition; - int nbr_partitions; /* zero until partition support enabled */ - ST_partstat ps[ST_NBR_PARTITIONS]; - unsigned char dirty; - unsigned char ready; - unsigned char write_prot; - unsigned char drv_write_prot; - unsigned char in_use; - unsigned char blksize_changed; - unsigned char density_changed; - unsigned char compression_changed; - unsigned char drv_buffer; - unsigned char density; - unsigned char door_locked; - unsigned char rew_at_close; - int block_size; - int min_block; - int max_block; - int recover_count; - struct mtget * mt_status; + kdev_t devt; + unsigned capacity; + Scsi_Device *device; + struct semaphore sem; + ST_buffer *buffer; + + /* Drive characteristics */ + unsigned char omit_blklims; + unsigned char do_auto_lock; + unsigned char can_bsr; + unsigned char can_partitions; + unsigned char two_fm; + unsigned char fast_mteom; + unsigned char restr_dma; + unsigned char scsi2_logical; + unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ + int write_threshold; + int timeout; /* timeout for normal commands */ + int long_timeout; /* timeout for commands known to take long time */ + + /* Mode characteristics */ + ST_mode modes[ST_NBR_MODES]; + int current_mode; + + /* Status variables */ + int partition; + int new_partition; + int nbr_partitions; /* zero until partition support enabled */ + ST_partstat ps[ST_NBR_PARTITIONS]; + unsigned char dirty; + unsigned char ready; + unsigned char write_prot; + unsigned char drv_write_prot; + unsigned char in_use; + unsigned char blksize_changed; + unsigned char density_changed; + unsigned char compression_changed; + unsigned char drv_buffer; + unsigned char density; + unsigned char door_locked; + unsigned char rew_at_close; + int block_size; + int min_block; + int max_block; + int recover_count; + struct mtget *mt_status; #if DEBUG - unsigned char write_pending; - int nbr_finished; - int nbr_waits; - unsigned char last_cmnd[6]; - unsigned char last_sense[16]; + unsigned char write_pending; + int nbr_finished; + int nbr_waits; + unsigned char last_cmnd[6]; + unsigned char last_sense[16]; #endif } Scsi_Tape; -extern Scsi_Tape * scsi_tapes; +extern Scsi_Tape *scsi_tapes; /* Values of eof */ #define ST_NOEOF 0 @@ -159,4 +159,3 @@ #define ST_YES 2 #endif - diff -u --recursive --new-file v2.3.16/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.3.16/linux/drivers/sound/Config.in Tue Aug 31 17:29:14 1999 +++ linux/drivers/sound/Config.in Tue Sep 7 10:22:12 1999 @@ -10,9 +10,16 @@ # Prompt user for primary drivers. dep_tristate 'C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND +if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then + bool 'Enable legacy FM' CONFIG_SOUND_CMPCI_FM + bool 'Enable legacy MPU-401' CONFIG_SOUND_CMPCI_MIDI +fi 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 +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND +fi dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND if [ "$CONFIG_VISWS" = "y" ]; then dep_tristate 'SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND @@ -171,6 +178,8 @@ fi fi + dep_tristate 'VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX $CONFIG_SOUND_OSS + dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_MAD16" = "y" -o "$CONFIG_SOUND_MAD16" = "m" ]; then bool 'Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD diff -u --recursive --new-file v2.3.16/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.3.16/linux/drivers/sound/Makefile Tue Aug 31 17:29:14 1999 +++ linux/drivers/sound/Makefile Tue Sep 7 10:22:12 1999 @@ -53,6 +53,7 @@ obj-$(CONFIG_SOUND_CS4232) += uart401.o obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o +obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx.o sb.o uart401.o obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o obj-$(CONFIG_SOUND_MPU401) += mpu401.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o diff -u --recursive --new-file v2.3.16/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c --- v2.3.16/linux/drivers/sound/cmpci.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/sound/cmpci.c Tue Sep 7 10:22:12 1999 @@ -2311,7 +2311,9 @@ index++; continue; + err_dev4: unregister_sound_midi(s->dev_midi); + err_dev3: unregister_sound_mixer(s->dev_mixer); err_dev2: unregister_sound_dsp(s->dev_audio); @@ -2326,6 +2328,7 @@ #ifdef CONFIG_SOUND_CMPCI_MIDI release_region(s->iomidi, CM_EXTENT_MIDI); #endif + err_region4: release_region(s->iobase, CM_EXTENT_CODEC); err_region5: kfree_s(s, sizeof(struct cm_state)); diff -u --recursive --new-file v2.3.16/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c --- v2.3.16/linux/drivers/sound/dmasound.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/sound/dmasound.c Sat Sep 4 13:09:36 1999 @@ -5646,7 +5646,9 @@ sound.mach.irqcleanup(); } +#ifdef CONFIG_PPC sq_release_read_buffers(); +#endif sq_release_buffers(); if (mixer_unit >= 0) diff -u --recursive --new-file v2.3.16/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.3.16/linux/drivers/sound/es1370.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/sound/es1370.c Tue Sep 7 10:19:45 1999 @@ -108,6 +108,11 @@ * removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge * 12.08.99 0.27 module_init/__setup fixes * 19.08.99 0.28 SOUND_MIXER_IMIX fixes, reported by Gianluca + * 31.08.99 0.29 add spin_lock_init + * __initlocaldata to fix gcc 2.7.x problems + * replaced current->state = x with set_current_state(x) + * 03.09.99 0.30 change read semantics for MIDI to match + * OSS more closely; remove possible wakeup race * * some important things missing in Ensoniq documentation: * @@ -1059,7 +1064,7 @@ if (s->dma_dac1.mapped || !s->dma_dac1.ready) return 0; - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac1.wait, &wait); for (;;) { spin_lock_irqsave(&s->lock, flags); @@ -1071,7 +1076,7 @@ break; if (nonblock) { remove_wait_queue(&s->dma_dac1.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 @@ -1081,7 +1086,7 @@ DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");) } remove_wait_queue(&s->dma_dac1.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0; @@ -1095,7 +1100,7 @@ if (s->dma_dac2.mapped || !s->dma_dac2.ready) return 0; - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac2.wait, &wait); for (;;) { spin_lock_irqsave(&s->lock, flags); @@ -1107,7 +1112,7 @@ break; if (nonblock) { remove_wait_queue(&s->dma_dac2.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 @@ -1117,7 +1122,7 @@ DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");) } remove_wait_queue(&s->dma_dac2.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0; @@ -2071,6 +2076,7 @@ static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct es1370_state *s = (struct es1370_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned ptr; @@ -2081,7 +2087,10 @@ return -ESPIPE; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; + if (count == 0) + return 0; ret = 0; + add_wait_queue(&s->midi.iwait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); ptr = s->midi.ird; @@ -2092,15 +2101,25 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->midi.iwait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) - return ret ? ret : -EFAULT; + if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } ptr = (ptr + cnt) % MIDIINBUF; spin_lock_irqsave(&s->lock, flags); s->midi.ird = ptr; @@ -2109,13 +2128,17 @@ count -= cnt; buffer += cnt; ret += cnt; + break; } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&s->midi.iwait, &wait); return ret; } static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct es1370_state *s = (struct es1370_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned ptr; @@ -2126,7 +2149,10 @@ return -ESPIPE; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + if (count == 0) + return 0; ret = 0; + add_wait_queue(&s->midi.owait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); ptr = s->midi.owr; @@ -2139,15 +2165,25 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->midi.owait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) - return ret ? ret : -EFAULT; + if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } ptr = (ptr + cnt) % MIDIOUTBUF; spin_lock_irqsave(&s->lock, flags); s->midi.owr = ptr; @@ -2160,6 +2196,8 @@ es1370_handle_midi(s); spin_unlock_irqrestore(&s->lock, flags); } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&s->midi.owait, &wait); return ret; } @@ -2246,7 +2284,7 @@ VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->midi.owait, &wait); for (;;) { spin_lock_irqsave(&s->lock, flags); @@ -2258,7 +2296,7 @@ break; if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2266,7 +2304,7 @@ DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");) } remove_wait_queue(&s->midi.owait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); } down(&s->open_sem); s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE); @@ -2337,6 +2375,11 @@ { SOUND_MIXER_WRITE_OGAIN, 0x4040 } }; +#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ + ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) +#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) + + static int __init init_es1370(void) { struct es1370_state *s; @@ -2346,11 +2389,10 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.28 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.29 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { - if (pcidev->resource[0].flags == 0 || - (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + if (!RSRCISIOREGION(pcidev, 0)) continue; if (pcidev->irq == 0) continue; @@ -2366,8 +2408,9 @@ init_waitqueue_head(&s->midi.iwait); init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); s->magic = ES1370_MAGIC; - s->io = pcidev->resource[0].start; + s->io = RSRCADDRESS(pcidev, 0); s->irq = pcidev->irq; if (check_region(s->io, ES1370_EXTENT)) { printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1); @@ -2485,11 +2528,12 @@ static int __init es1370_setup(char *str) { - static unsigned __initdata nr_dev = 0; + static unsigned __initlocaldata nr_dev = 0; if (nr_dev >= NR_DEVICE) return 0; + (void) ( (get_option(&str,&joystick[nr_dev]) == 2) && (get_option(&str,&lineout [nr_dev]) == 2) && get_option(&str,&micbias [nr_dev]) diff -u --recursive --new-file v2.3.16/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.3.16/linux/drivers/sound/es1371.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/sound/es1371.c Tue Sep 7 10:19:45 1999 @@ -81,6 +81,11 @@ * added a /proc file system for dumping hardware state * updated SRC and CODEC w/r functions to accomodate bugs * in some versions of the ES137x chips. + * 31.08.99 0.17 add spin_lock_init + * __initlocaldata to fix gcc 2.7.x problems + * replaced current->state = x with set_current_state(x) + * 03.09.99 0.18 change read semantics for MIDI to match + * OSS more closely; remove possible wakeup race * */ @@ -1608,8 +1613,8 @@ if (s->dma_dac1.mapped || !s->dma_dac1.ready) return 0; + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac1.wait, &wait); - current->state = TASK_INTERRUPTIBLE; for (;;) { spin_lock_irqsave(&s->lock, flags); count = s->dma_dac1.count; @@ -1620,7 +1625,7 @@ break; if (nonblock) { remove_wait_queue(&s->dma_dac1.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate; @@ -1629,7 +1634,7 @@ printk(KERN_DEBUG "es1371: dac1 dma timed out??\n"); } remove_wait_queue(&s->dma_dac1.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0; @@ -1644,8 +1649,8 @@ if (s->dma_dac2.mapped || !s->dma_dac2.ready) return 0; + __set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&s->dma_dac2.wait, &wait); - current->state = TASK_UNINTERRUPTIBLE; for (;;) { spin_lock_irqsave(&s->lock, flags); count = s->dma_dac2.count; @@ -1656,7 +1661,7 @@ break; if (nonblock) { remove_wait_queue(&s->dma_dac2.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate; @@ -1665,7 +1670,7 @@ printk(KERN_DEBUG "es1371: dac2 dma timed out??\n"); } remove_wait_queue(&s->dma_dac2.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0; @@ -2607,6 +2612,7 @@ static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct es1371_state *s = (struct es1371_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned ptr; @@ -2617,7 +2623,10 @@ return -ESPIPE; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; + if (count == 0) + return 0; ret = 0; + add_wait_queue(&s->midi.iwait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); ptr = s->midi.ird; @@ -2628,15 +2637,25 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->midi.iwait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) - return ret ? ret : -EFAULT; + if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } ptr = (ptr + cnt) % MIDIINBUF; spin_lock_irqsave(&s->lock, flags); s->midi.ird = ptr; @@ -2645,13 +2664,17 @@ count -= cnt; buffer += cnt; ret += cnt; + break; } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&s->midi.iwait, &wait); return ret; } static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct es1371_state *s = (struct es1371_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned ptr; @@ -2662,7 +2685,10 @@ return -ESPIPE; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + if (count == 0) + return 0; ret = 0; + add_wait_queue(&s->midi.owait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); ptr = s->midi.owr; @@ -2675,15 +2701,25 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->midi.owait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) - return ret ? ret : -EFAULT; + if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } ptr = (ptr + cnt) % MIDIOUTBUF; spin_lock_irqsave(&s->lock, flags); s->midi.owr = ptr; @@ -2696,6 +2732,8 @@ es1371_handle_midi(s); spin_unlock_irqrestore(&s->lock, flags); } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&s->midi.owait, &wait); return ret; } @@ -2781,7 +2819,7 @@ VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->midi.owait, &wait); for (;;) { spin_lock_irqsave(&s->lock, flags); @@ -2793,7 +2831,7 @@ break; if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2801,7 +2839,7 @@ printk(KERN_DEBUG "es1371: midi timed out??\n"); } remove_wait_queue(&s->midi.owait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); } down(&s->open_sem); s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE); @@ -2910,6 +2948,11 @@ { SOUND_MIXER_WRITE_IGAIN, 0x4040 } }; +#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ + ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) +#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) + + static int __init init_es1371(void) { struct es1371_state *s; @@ -2920,11 +2963,10 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.15 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1371: version v0.17 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) { - if (pcidev->resource[0].flags == 0 || - (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + if (!RSRCISIOREGION(pcidev, 0)) continue; if (pcidev->irq == 0) continue; @@ -2940,8 +2982,9 @@ init_waitqueue_head(&s->midi.iwait); init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); s->magic = ES1371_MAGIC; - s->io = pcidev->resource[0].start; + s->io = RSRCADDRESS(pcidev, 0); s->irq = pcidev->irq; pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev); if (check_region(s->io, ES1371_EXTENT)) { @@ -3106,12 +3149,12 @@ static int __init es1371_setup(char *str) { - static unsigned __initdata nr_dev = 0; + static unsigned __initlocaldata nr_dev = 0; if (nr_dev >= NR_DEVICE) return 0; if (get_option(&str, &joystick[nr_dev]) == 2) - get_option(&str, &spdif[nr_dev]); + (void)get_option(&str, &spdif[nr_dev]); nr_dev++; return 1; } diff -u --recursive --new-file v2.3.16/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.3.16/linux/drivers/sound/esssolo1.c Thu Aug 12 12:21:48 1999 +++ linux/drivers/sound/esssolo1.c Tue Sep 7 10:19:45 1999 @@ -54,6 +54,10 @@ * The fun part is that the Windows Solo1 driver doesn't * seem to do these tricks. * Bugs remaining: plops and clicks when starting/stopping playback + * 31.08.99 0.7 add spin_lock_init + * replaced current->state = x with set_current_state(x) + * 03.09.99 0.8 change read semantics for MIDI to match + * OSS more closely; remove possible wakeup race * */ @@ -929,7 +933,7 @@ if (s->dma_dac.mapped) return 0; - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac.wait, &wait); for (;;) { spin_lock_irqsave(&s->lock, flags); @@ -941,7 +945,7 @@ break; if (nonblock) { remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate; @@ -953,7 +957,7 @@ printk(KERN_DEBUG "solo1: dma timed out??\n"); } remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0; @@ -1599,6 +1603,7 @@ static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct solo1_state *s = (struct solo1_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned ptr; @@ -1609,7 +1614,10 @@ return -ESPIPE; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; + if (count == 0) + return 0; ret = 0; + add_wait_queue(&s->midi.iwait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); ptr = s->midi.ird; @@ -1620,15 +1628,25 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->midi.iwait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) - return ret ? ret : -EFAULT; + if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } ptr = (ptr + cnt) % MIDIINBUF; spin_lock_irqsave(&s->lock, flags); s->midi.ird = ptr; @@ -1637,13 +1655,17 @@ count -= cnt; buffer += cnt; ret += cnt; + break; } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&s->midi.iwait, &wait); return ret; } static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct solo1_state *s = (struct solo1_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned ptr; @@ -1654,7 +1676,10 @@ return -ESPIPE; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + if (count == 0) + return 0; ret = 0; + add_wait_queue(&s->midi.owait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); ptr = s->midi.owr; @@ -1667,15 +1692,25 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->midi.owait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) - return ret ? ret : -EFAULT; + if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } ptr = (ptr + cnt) % MIDIOUTBUF; spin_lock_irqsave(&s->lock, flags); s->midi.owr = ptr; @@ -1688,6 +1723,8 @@ solo1_handle_midi(s); spin_unlock_irqrestore(&s->lock, flags); } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&s->midi.owait, &wait); return ret; } @@ -1779,7 +1816,7 @@ VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->midi.owait, &wait); for (;;) { spin_lock_irqsave(&s->lock, flags); @@ -1791,7 +1828,7 @@ break; if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -1799,7 +1836,7 @@ printk(KERN_DEBUG "solo1: midi timed out??\n"); } remove_wait_queue(&s->midi.owait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); } down(&s->open_sem); s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE); @@ -2030,6 +2067,11 @@ { SOUND_MIXER_WRITE_MIC, 0x4040 } }; +#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ + ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) +#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) + + static int __init init_solo1(void) { struct solo1_state *s; @@ -2039,17 +2081,13 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "solo1: version v0.6 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "solo1: version v0.7 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) { - if (pcidev->resource[0].start == 0 || - (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO || - pcidev->resource[1].start == 0 || - (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO || - pcidev->resource[2].start == 0 || - (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO || - pcidev->resource[3].start == 0 || - (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + if (!RSRCISIOREGION(pcidev, 0) || + !RSRCISIOREGION(pcidev, 1) || + !RSRCISIOREGION(pcidev, 2) || + !RSRCISIOREGION(pcidev, 3)) continue; if (pcidev->irq == 0) continue; @@ -2064,14 +2102,15 @@ init_waitqueue_head(&s->midi.iwait); init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); s->magic = SOLO1_MAGIC; s->pcidev = pcidev; - s->iobase = pcidev->resource[0].start; - s->sbbase = pcidev->resource[1].start; - s->vcbase = pcidev->resource[2].start; + s->iobase = RSRCADDRESS(pcidev, 0); + s->sbbase = RSRCADDRESS(pcidev, 1); + s->vcbase = RSRCADDRESS(pcidev, 2); s->ddmabase = s->vcbase + DDMABASE_OFFSET; - s->mpubase = pcidev->resource[3].start; - s->gpbase = pcidev->resource[4].start; + s->mpubase = RSRCADDRESS(pcidev, 3); + s->gpbase = RSRCADDRESS(pcidev, 4); s->irq = pcidev->irq; if (check_region(s->iobase, IOBASE_EXTENT) || check_region(s->sbbase, SBBASE_EXTENT) || diff -u --recursive --new-file v2.3.16/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c --- v2.3.16/linux/drivers/sound/maestro.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/sound/maestro.c Tue Sep 7 10:14:37 1999 @@ -69,15 +69,29 @@ * Once input is actually written, it will be worth pointing out * that only 44/16 input actually works. * + * History + * v0.04 - Sep 01 1999 - Zach Brown + * copied memory leak fix from sonicvibes driver + * different ac97 reset, play with 2.0 ac97, simplify ring bus setup + * bob freq code, region sanity, jitter sync fix; all from eric + * * TODO - * Leaks memory? * recording is horribly broken - * apus or dmas get out sync - * bob can be started twice + * codec timeouts (we're way under the example source's 20ms(!?)) + * some people get indir reg timeouts? + * mixer interface broken? * anyone have a pt101 codec? * ess's ac97 codec (es1921) doesn't work - * generally test across codecs.. * mmap(), but beware stereo encoding nastiness. + * actually post pci writes + * check for bogon bios set irq/io windows + * compare our pci setup to the dos one, explains register timeouts? + * look really hard at the apu/bob/dma buffer code paths. + * + * the entire issue of smp safety needs to be looked at. cli() needs + * to be replaced with spinlock_irqsave, being very careful of call + * paths avoiding deadlock. if lock hold times are quick just + * use one big ass per device spinlock.. */ /*****************************************************************************/ @@ -124,7 +138,7 @@ /* --------------------------------------------------------------------- */ -#define DRIVER_VERSION "0.03" +#define DRIVER_VERSION "0.04" #ifndef PCI_VENDOR_ESS #define PCI_VENDOR_ESS 0x125D @@ -293,22 +307,21 @@ for(i=0;i<10000;i++) { - if(!(inb(io+ESS_AC97_INDEX)&1)) + if(!(inb(io+ESS_AC97_INDEX)&1)) break; } /* * Write the bus */ outw(val, io+ESS_AC97_DATA); - udelay(1); - /* should actually be delaying 10 milliseconds? */ + mdelay(1); outb(cmd, io+ESS_AC97_INDEX); - udelay(1); + mdelay(1); } static u16 maestro_ac97_get(int io, u8 cmd) { - int sanity=100000; + int sanity=10000; u16 data; int i; @@ -323,7 +336,7 @@ } outb(cmd|0x80, io+ESS_AC97_INDEX); - udelay(1); + mdelay(1); while(inb(io+ESS_AC97_INDEX)&1) { @@ -335,7 +348,7 @@ } } data=inw(io+ESS_AC97_DATA); - udelay(1); + mdelay(1); return data; } @@ -349,28 +362,36 @@ static u16 maestro_ac97_init(int iobase) { - int val, seid, caps; u16 vend1, vend2; -#if 0 /* an experiment for another time */ - /* aim at the second codec */ - outw(0x21, iobase+0x38); - outw(0x5555, iobase+0x3a); - outw(0x5555, iobase+0x3c); - udelay(1); - vend1 = maestro_ac97_get(iobase, 0x7c); - vend2 = maestro_ac97_get(iobase, 0x7e); - if(vend1 != 0xffff || vend2 != 0xffff) { - printk("maestro: It seems you have a second codec: %x %x, please report this.\n", - vend1,vend2); - } - /* back to the first */ +#if 0 /* this needs to be thought about harder */ + /* aim at the second codec */ + outw(0x21, iobase+0x38); + outw(0x5555, iobase+0x3a); + outw(0x5555, iobase+0x3c); + udelay(1); + vend1 = maestro_ac97_get(iobase, 0x7c); + vend2 = maestro_ac97_get(iobase, 0x7e); + if(vend1 != 0xffff || vend2 != 0xffff) { + printk("maestro: second codec 0x%4x%4x found, enabling both. please report this.\n", + vend1,vend2); + /* enable them both */ + outw(0x00, iobase+0x38); + outw(0xFFFC, iobase+0x3a); + outw(0x000C, iobase+0x3c); + } else { + /* back to the first only */ outw(0x0, iobase+0x38); outw(0x0, iobase+0x3a); outw(0x0, iobase+0x3c); + } + udelay(1); #endif + /* perform codec reset */ + maestro_ac97_set(iobase, 0x00, 0x0000); + /* should make sure we're ac97 2.1? */ vend1 = maestro_ac97_get(iobase, 0x7c); vend2 = maestro_ac97_get(iobase, 0x7e); @@ -382,9 +403,15 @@ printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x 3d: 0x%x caps: 0x%x\n", vend1,vend2,seid, caps); + /* XXX endianness, dork head. */ + /* magic vendor specifc init code, _no_ idea what these do */ switch ((long)(vend1 << 16) | vend2) { - /* magic vendor specifc init code, _no_ idea what these do */ -#if 0 + case 0x545200ff: /* TriTech */ + + maestro_ac97_set(iobase,0x2a,0x0001); + maestro_ac97_set(iobase,0x2c,0x0000); + maestro_ac97_set(iobase,0x2c,0xffff); + break; case 0x83847609: /* ESS 1921 */ maestro_ac97_set(iobase,0x76,0xABBA); /* o/~ Take a chance on me o/~ */ udelay(20); @@ -393,7 +420,6 @@ maestro_ac97_set(iobase,0x78,0x3802); udelay(20); break; -#endif default: break; } @@ -424,6 +450,15 @@ /* power up various units? */ maestro_ac97_set(iobase, 0x26, 0x000F); + /* lets see if they actually default to the spec :) */ + if(maestro_ac97_get(iobase,0x36) ==0x8080) { + int reg; + printk("maestro: your ac97 might be 2.0, see if this makes sense:\n"); + for(reg = 0x28; reg <= 0x58 ; reg += 2) { + printk(" 0x%2x: %4x\n",reg,maestro_ac97_get(iobase,reg)); + } + } + return 0; } @@ -450,10 +485,43 @@ static void maestro_ac97_reset(int ioaddr) { +/* outw(0x2000, ioaddr+0x36); + inb(ioaddr); + mdelay(1); + outw(0x0000, ioaddr+0x36); + inb(ioaddr); + mdelay(1);*/ + + /* well this seems to work a little + better on the 2e */ + /* this screws around with the gpio + mask/input/direction.. */ + outw(0x0000, ioaddr+0x36); + udelay(20); + outw(0xFFFE, ioaddr+0x64); + outw(0x1, ioaddr+0x68); + outw(0x0, ioaddr+0x60); + udelay(20); + outw(0x1, ioaddr+0x60); + udelay(20); /* other source says 500ms.. INSANE */ outw(0x2000, ioaddr+0x36); udelay(20); - outw(0x0000, ioaddr+0x36); + outw(0x3000, ioaddr+0x36); udelay(200); + outw(0x0001, ioaddr+0x68); + outw(0xFFFF, ioaddr+0x64); + + /* strange strange reset tickling the ring bus */ + outw(0x0, ioaddr+0x36); + udelay(20); + outw(0x200, ioaddr+0x36); /* first codec only */ + udelay(20); + outw(0x0, ioaddr+0x36); + udelay(20); + outw(0x2000, ioaddr+0x36); + udelay(20); + outw(0x3000, ioaddr+0x36); + udelay(20); } /* @@ -621,9 +689,9 @@ static void sound_reset(int ioaddr) { outw(0x2000, 0x18+ioaddr); - udelay(10); + udelay(1); outw(0x0000, 0x18+ioaddr); - udelay(10); + udelay(1); } static void set_apu_fmt(struct ess_state *s, int apu, int mode) @@ -790,9 +858,9 @@ /* apu_set_register(ess, channel, 2, (rate&0xFF)<<8|0x10); apu_set_register(ess, channel, 3, rate>>8);*/ +/* XXX think about endianess when writing these registers */ /* Load the buffer into the wave engine */ apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8); - /* XXX reg is little endian.. */ apu_set_register(ess, channel, 5, pa&0xFFFF); apu_set_register(ess, channel, 6, (pa+size)&0xFFFF); /* setting loop == sample len */ @@ -949,7 +1017,7 @@ #else -/* nice HW BOB implementation. cheers, eric. */ +/* nice HW BOB implementation. */ static void stop_bob(struct ess_state *s) { @@ -961,17 +1029,51 @@ /* eventually we could be clever and limit bob ints to the frequency at which our smallest duration chunks may expire */ +#define ESS_SYSCLK 50000000 static void start_bob(struct ess_state *s) { - stop_bob(s); // make sure bob's not already running + int prescale; + int divide; + + int freq = 200; /* requested frequency - calculate what we want here. */ + + stop_bob(s); /* make sure bob's not already running */ - maestro_write(s, 6, 0x8000 |(1<<12) | (5<<5) | 11); // (50MHz/2^14)/12 = 254 Hz = 40 mS + /* compute ideal interrupt frequency for buffer size & play rate */ + /* first, find best prescaler value to match freq */ + for(prescale=5;prescale<12;prescale++) + if(freq > (ESS_SYSCLK>>(prescale+9))) + break; + + /* next, back off prescaler whilst getting divider into optimum range */ + divide=1; + while((prescale > 5) && (divide<32)) + { + prescale--; + divide <<=1; + } + divide>>=1; + + /* now fine-tune the divider for best match */ + for(;divide<31;divide++) + if(freq >= ((ESS_SYSCLK>>(prescale+9))/(divide+1))) + break; + + /* divide = 0 is illegal, but don't let prescale = 4! */ + if(divide == 0) + { + divide++; + if(prescale>5) + prescale--; + } + + maestro_write(s, 6, 0x9000 | (prescale<<5) | divide); /* set reg */ /* Now set IDR 11/17 */ maestro_write(s, 0x11, maestro_read(s, 0x11)|1); maestro_write(s, 0x17, maestro_read(s, 0x17)|1); } -#endif // ESS_HW_TIMER +#endif /* ESS_HW_TIMER */ /* --------------------------------------------------------------------- */ static int adc_active = 0; @@ -986,8 +1088,8 @@ apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F); apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F); adc_active&=~1; -// if(!adc_active) -// stop_bob(s); +/* if(!adc_active) + stop_bob(s); */ spin_unlock_irqrestore(&s->lock, flags); } @@ -1000,8 +1102,8 @@ apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F); apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F); adc_active&=~2; -// if(!adc_active) -// stop_bob(s); +/* if(!adc_active) + stop_bob(s); */ spin_unlock_irqrestore(&s->lock, flags); } @@ -1020,8 +1122,8 @@ apu_set_register(s, 1, 0, (apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]); } -// if(!adc_active) -// start_bob(s); +/* if(!adc_active) + start_bob(s);*/ adc_active|=2; spin_unlock_irqrestore(&s->lock, flags); } @@ -1039,8 +1141,8 @@ apu_set_register(s, 3, 0, (apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]); } -// if(!adc_active) -// start_bob(s); +/* if(!adc_active) + start_bob(s); */ adc_active|=1; spin_unlock_irqrestore(&s->lock, flags); } @@ -1094,8 +1196,9 @@ db->ready = db->mapped = 0; /* alloc as big a chunk as we can */ - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--) - db->rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order); + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) + if((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order))) + break; if (!db->rawbuf) return -ENOMEM; @@ -1144,10 +1247,10 @@ /* program enhanced mode registers */ /* FILL */ } else { - //set_dmaa(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + /* set_dmaa(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); */ /* program enhanced mode registers */ /* FILL */ - //set_dac_rate(s, s->ratedac); // redundant + /*set_dac_rate(s, s->ratedac); redundant */ ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->numfrag << db->fragshift); } @@ -1156,6 +1259,7 @@ return 0; } +/* XXX haha, way broken with our split stereo setup. giggle. */ extern __inline__ void clear_advance(struct ess_state *s) { unsigned char c = (s->fmt & (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT)) ? 0 : 0x80; @@ -1180,9 +1284,9 @@ unsigned hwptr; int diff; +/* ADC is way broken. compare to DAC.. */ /* update ADC pointer */ if (s->dma_adc.ready) { - M_printk("adc ready.. \n"); hwptr = (/*s->dma_adc.dmasize - */get_dmac(s)) % s->dma_adc.dmasize; diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; s->dma_adc.hwptr = hwptr; @@ -1193,16 +1297,17 @@ if (!s->dma_adc.mapped) { if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { s->enable &= ~ESS_ENABLE_RE; - /* FILL ME */ -// wrindir(s, SV_CIENABLE, s->enable); - stop_adc(s); + /* FILL ME + wrindir(s, SV_CIENABLE, s->enable); */ + stop_adc(s); s->dma_adc.error++; } } } /* update DAC pointer */ if (s->dma_dac.ready) { - hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize; + /* this is so gross. */ + hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize; diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; /* M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/ s->dma_dac.hwptr = hwptr; @@ -1213,12 +1318,17 @@ wake_up(&s->dma_dac.wait); } else { 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) { s->enable &= ~ESS_ENABLE_PE; -/* FILL ME */ -// wrindir(s, SV_CIENABLE, s->enable); - + /* 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.error++; } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { clear_advance(s); @@ -1708,8 +1818,8 @@ set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); /* program enhanced mode registers */ /* FILL ME */ -// wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); -// wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); +/* wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); + wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); */ s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; spin_unlock_irqrestore(&s->lock, flags); } @@ -1739,9 +1849,7 @@ { /* oh, bother. stereo decoding APU's don't work in 16bit so we use dual linear decoders. which means we have to hack up stereo - buffer's we're given. yuck. - - and we have to be able to work a byte at a time..*/ + buffer's we're given. yuck. */ unsigned char *so,*left,*right; int i; @@ -1780,6 +1888,8 @@ unsigned char *splitbuf = NULL; int cnt; +/* printk("maestro: ess_write: count %d\n", count);*/ + VALIDATE_STATE(s); if (ppos != &file->f_pos) return -ESPIPE; @@ -1789,7 +1899,7 @@ return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; - /* I wish we could be more clever than this */ + /* XXX be more clever than this.. */ if (!(splitbuf = kmalloc(count,GFP_KERNEL))) return -ENOMEM; ret = 0; @@ -1840,8 +1950,8 @@ spin_lock_irqsave(&s->lock, flags); set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); /* program enhanced mode registers */ -// wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); -// wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); +/* wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); + wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); */ /* FILL ME */ s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; spin_unlock_irqrestore(&s->lock, flags); @@ -1957,6 +2067,8 @@ int val, mapped, ret; unsigned char fmtm, fmtd; +/* printk("maestro: ess_ioctl: cmd %d\n", cmd);*/ + VALIDATE_STATE(s); mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); @@ -2248,7 +2360,6 @@ return -EINVAL; } -// return mixer_ioctl(s, cmd, arg); return -EINVAL; } @@ -2374,7 +2485,7 @@ static int maestro_install(struct pci_dev *pcidev, int card_type, int index) { u16 w; - u32 n; +/* u32 n;*/ int iobase; int i; struct ess_card *card; @@ -2384,6 +2495,12 @@ iobase = pcidev->resource[0].start; + if(check_region(iobase, 256)) + { + printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase); + return 0; + } + card = kmalloc(sizeof(struct ess_card), GFP_KERNEL); if(card == NULL) { @@ -2531,14 +2648,37 @@ pci_write_config_word(pcidev, 0x40, w); + /* stake our claim on the iospace */ + request_region(iobase, 256, card_names[card_type]); + sound_reset(iobase); +#if 0 + + /* reset the ring bus */ + + outw(inw(iobase + 0x36) & 0xdfff, iobase+0x36); /* disable */ + outw(0xC090, iobase+0x34); + udelay(20); + outw(inw(iobase + 0x36) |0x2000, iobase+0x36); /* enable */ +#endif + /* + * Ring Bus Setup + */ + + /* setup usual 0x34 stuff.. 0x36 may be chip specific */ + outw(0xC090, iobase+0x34); /* direct sound, stereo */ + udelay(20); + outw(0x3000, iobase+0x36); /* direct sound, stereo */ + udelay(20); + /* * Reset the CODEC */ maestro_ac97_reset(iobase); - + +#if 0 /* * Ring Bus Setup */ @@ -2546,6 +2686,7 @@ n=inl(iobase+0x34); n&=~0xF000; n|=12<<12; /* Direct Sound, Stereo */ + outl(n, iobase+0x34); n=inl(iobase+0x34); n&=~0x0F00; /* Modem off */ @@ -2605,11 +2746,15 @@ w=inw(iobase+0x18); w|=(1<<0); /* SB IRQ on */ outw(w, iobase+0x18); +#endif - outb(0, iobase+0xA4); - outb(3, iobase+0xA2); +#if 0 + /* asp crap */ + outb(0, iobase+0xA4); + outb(3, iobase+0xA2); outb(0, iobase+0xA6); +#endif for(apu=0;apu<16;apu++) { @@ -2698,10 +2843,18 @@ if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, card_names[card_type], card)) { printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq); + unregister_sound_mixer(card->dev_mixer); + for(i=0;i<8;i++) + { + struct ess_state *s = &card->channels[i]; + if(s->dev_audio != -1) + unregister_sound_dsp(s->dev_audio); + } + release_region(card->iobase, 256); + kfree(card); return 0; } -// ess_play_test(ess); printk("maestro: %d channels configured.\n", num); return 1; } @@ -2776,18 +2929,11 @@ while ((s = devs)) { int i; devs = devs->next; -// ess_play_test(&s->channels[0]); #ifndef ESS_HW_TIMER kill_bob(&s->channels[0]); #else stop_bob(&s->channels[0]); #endif -// outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ -// synchronize_irq(); -// inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ -// wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ - //outb(0, s->iodmaa + SV_DMA_RESET); - //outb(0, s->iodmac + SV_DMA_RESET); free_irq(s->irq, s); unregister_sound_mixer(s->dev_mixer); for(i=0;i<8;i++) @@ -2796,6 +2942,7 @@ if(ess->dev_audio != -1) unregister_sound_dsp(ess->dev_audio); } + release_region(s->iobase, 256); kfree(s); } M_printk("maestro: unloading\n"); @@ -2808,6 +2955,7 @@ * ex-code that we're not using anymore.. *============================================================================ */ + /* * The ASSP is fortunately not double indexed */ diff -u --recursive --new-file v2.3.16/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.3.16/linux/drivers/sound/sonicvibes.c Thu Aug 12 12:21:48 1999 +++ linux/drivers/sound/sonicvibes.c Tue Sep 7 10:19:45 1999 @@ -74,6 +74,13 @@ * 03.08.99 0.17 adapt to Linus' new __setup/__initcall * added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr" * 12.08.99 0.18 module_init/__setup fixes + * 24.08.99 0.19 get rid of the dmaio kludge, replace with allocate_resource + * 31.08.99 0.20 add spin_lock_init + * __initlocaldata to fix gcc 2.7.x problems + * use new resource allocation to allocate DDMA IO space + * replaced current->state = x with set_current_state(x) + * 03.09.99 0.21 change read semantics for MIDI to match + * OSS more closely; remove possible wakeup race * */ @@ -121,6 +128,12 @@ #define SV_EXTENT_GAME 0x8 #define SV_EXTENT_DMA 0x10 +#define RESOURCE_SB 0 +#define RESOURCE_ENH 1 +#define RESOURCE_SYNTH 2 +#define RESOURCE_MIDI 3 +#define RESOURCE_GAME 4 +#define RESOURCE_DDMA 7 #define SV_MIDI_DATA 0 #define SV_MIDI_COMMAND 1 @@ -1254,7 +1267,7 @@ if (s->dma_dac.mapped || !s->dma_dac.ready) return 0; - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac.wait, &wait); for (;;) { spin_lock_irqsave(&s->lock, flags); @@ -1266,7 +1279,7 @@ break; if (nonblock) { remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac; @@ -1275,7 +1288,7 @@ printk(KERN_DEBUG "sv: dma timed out??\n"); } remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0; @@ -1874,6 +1887,7 @@ static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct sv_state *s = (struct sv_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned ptr; @@ -1884,7 +1898,10 @@ return -ESPIPE; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; + if (count == 0) + return 0; ret = 0; + add_wait_queue(&s->midi.iwait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); ptr = s->midi.ird; @@ -1895,15 +1912,25 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->midi.iwait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) - return ret ? ret : -EFAULT; + if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } ptr = (ptr + cnt) % MIDIINBUF; spin_lock_irqsave(&s->lock, flags); s->midi.ird = ptr; @@ -1912,13 +1939,17 @@ count -= cnt; buffer += cnt; ret += cnt; + break; } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&s->midi.iwait, &wait); return ret; } static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct sv_state *s = (struct sv_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned ptr; @@ -1929,7 +1960,10 @@ return -ESPIPE; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + if (count == 0) + return 0; ret = 0; + add_wait_queue(&s->midi.owait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); ptr = s->midi.owr; @@ -1942,15 +1976,25 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->midi.owait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) - return ret ? ret : -EFAULT; + if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } ptr = (ptr + cnt) % MIDIOUTBUF; spin_lock_irqsave(&s->lock, flags); s->midi.owr = ptr; @@ -1963,6 +2007,8 @@ sv_handle_midi(s); spin_unlock_irqrestore(&s->lock, flags); } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&s->midi.owait, &wait); return ret; } @@ -2057,7 +2103,7 @@ VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->midi.owait, &wait); for (;;) { spin_lock_irqsave(&s->lock, flags); @@ -2069,7 +2115,7 @@ break; if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2077,7 +2123,7 @@ printk(KERN_DEBUG "sv: midi timed out??\n"); } remove_wait_queue(&s->midi.owait, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); } down(&s->open_sem); s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE); @@ -2296,8 +2342,6 @@ static int wavetable[NR_DEVICE] = { 0, }; #endif -static unsigned dmaio = 0xac00; - MODULE_PARM(reverb, "1-" __MODULE_STRING(NR_DEVICE) "i"); MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM"); #if 0 @@ -2305,9 +2349,6 @@ MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled"); #endif -MODULE_PARM(dmaio, "i"); -MODULE_PARM_DESC(dmaio, "if the motherboard BIOS did not allocate DDMA io, allocate them starting at this address"); - MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); MODULE_DESCRIPTION("S3 SonicVibes Driver"); @@ -2328,33 +2369,54 @@ { SOUND_MIXER_WRITE_PCM, 0x4040 } }; +#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ + ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) +#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) + static int __init init_sonicvibes(void) { - struct sv_state *s; + static const char __initlocaldata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller"; + struct sv_state *s; struct pci_dev *pcidev = NULL; mm_segment_t fs; int i, val, index = 0; + char *ddmaname; + unsigned ddmanamelen; if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.18 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.20 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); #endif while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, pcidev))) { - if (pcidev->resource[1].flags == 0 || - (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) - continue; - if (pcidev->resource[2].flags == 0 || - (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) - continue; - if (pcidev->resource[3].flags == 0 || - (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO) + if (!RSRCISIOREGION(pcidev, RESOURCE_SB) || + !RSRCISIOREGION(pcidev, RESOURCE_ENH) || + !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) || + !RSRCISIOREGION(pcidev, RESOURCE_MIDI) || + !RSRCISIOREGION(pcidev, RESOURCE_GAME)) continue; if (pcidev->irq == 0) continue; + /* try to allocate a DDMA resource if not already available */ + if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) { + /* take care of ISA aliases */ + ddmanamelen = strlen(sv_ddma_name)+1; + if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL))) + continue; + memcpy(ddmaname, sv_ddma_name, ddmanamelen); + pcidev->resource[RESOURCE_DDMA].name = ddmaname; + if (allocate_resource(&ioport_resource, pcidev->resource+RESOURCE_DDMA, + 2*SV_EXTENT_DMA, 0x1000, 0x10000-2*SV_EXTENT_DMA, 1024)) { + pcidev->resource[RESOURCE_DDMA].name = NULL; + kfree(ddmaname); + printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n"); + continue; + } + pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO; + } if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) { printk(KERN_WARNING "sv: out of memory\n"); continue; @@ -2366,35 +2428,19 @@ init_waitqueue_head(&s->midi.iwait); init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); s->magic = SV_MAGIC; - s->iosb = pcidev->resource[0].start; - s->ioenh = pcidev->resource[1].start; - s->iosynth = pcidev->resource[2].start; - s->iomidi = pcidev->resource[3].start; - s->iogame = pcidev->resource[4].start; - pci_read_config_dword(pcidev, 0x40, &s->iodmaa); - pci_read_config_dword(pcidev, 0x48, &s->iodmac); - dmaio &= ~(SV_EXTENT_DMA-1); - s->iodmaa &= ~(SV_EXTENT_DMA-1); - s->iodmac &= ~(SV_EXTENT_DMA-1); - if (!(s->iodmaa)) { - s->iodmaa = dmaio; - dmaio += SV_EXTENT_DMA; - printk(KERN_INFO "sv: BIOS did not allocate DDMA channel A io, allocated at %#x\n", - s->iodmaa); - } - if (!(s->iodmac)) { - s->iodmac = dmaio; - dmaio += SV_EXTENT_DMA; - printk(KERN_INFO "sv: BIOS did not allocate DDMA channel C io, allocated at %#x\n", - s->iodmac); - } + s->iosb = RSRCADDRESS(pcidev, RESOURCE_SB); + s->ioenh = RSRCADDRESS(pcidev, RESOURCE_ENH); + s->iosynth = RSRCADDRESS(pcidev, RESOURCE_SYNTH); + s->iomidi = RSRCADDRESS(pcidev, RESOURCE_MIDI); + s->iogame = RSRCADDRESS(pcidev, RESOURCE_GAME); + s->iodmaa = RSRCADDRESS(pcidev, RESOURCE_DDMA); + s->iodmac = RSRCADDRESS(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA; pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */ pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */ printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n", s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac); - if (s->ioenh == 0 || s->iodmaa == 0 || s->iodmac == 0) - continue; s->irq = pcidev->irq; /* hack */ @@ -2436,8 +2482,8 @@ wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */ wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */ outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK); - //outb(0xff, s->iodmaa + SV_DMA_RESET); - //outb(0xff, s->iodmac + SV_DMA_RESET); + /* outb(0xff, s->iodmaa + SV_DMA_RESET); */ + /* outb(0xff, s->iodmac + SV_DMA_RESET); */ inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */ wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */ @@ -2550,31 +2596,21 @@ static int __init sonicvibes_setup(char *str) { - static unsigned __initdata nr_dev = 0; + static unsigned __initlocaldata nr_dev = 0; if (nr_dev >= NR_DEVICE) return 0; #if 0 if (get_option(&str, &reverb[nr_dev]) == 2) - get_option(&str, &wavetable[nr_dev]); + (void)get_option(&str, &wavetable[nr_dev]); #else - get_option(&str, &reverb[nr_dev]); + (void)get_option(&str, &reverb[nr_dev]); #endif nr_dev++; return 1; } -static int __init sonicvibesdmaio_setup(char *str) -{ - int io; - - if (get_option(&str, &io)) - dmaio = io; - return 1; -} - __setup("sonicvibes=", sonicvibes_setup); -__setup("sonicvibesdmaio=", sonicvibesdmaio_setup); #endif /* MODULE */ diff -u --recursive --new-file v2.3.16/linux/drivers/sound/via82cxxx.c linux/drivers/sound/via82cxxx.c --- v2.3.16/linux/drivers/sound/via82cxxx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/via82cxxx.c Tue Sep 7 10:22:12 1999 @@ -0,0 +1,256 @@ +/* + * Support for VIA 82Cxxx Audio Codecs + * Copyright 1999 Jeff Garzik + * + * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2. + * See the "COPYING" file distributed with this software for more info. + * + ******************************************************************** + * + * TODO: + * + * - Integrate AC'97 support, when AC'97 interface released + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb.h" + +#ifndef SOUND_LOCK +#define SOUND_LOCK do {} while (0) +#define SOUND_LOCK_END do {} while (0) +#endif + +#define MAX_CARDS 2 + +#define PFX "via82cxxx: " + +#define VIA_VERSION "1.0.0" +#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION + +#define VIA_FUNC_ENABLE 0x42 +#define VIA_PNP_CONTROL 0x43 + +#define VIA_CR42_SB_ENABLE 0x01 +#define VIA_CR42_MIDI_ENABLE 0x02 +#define VIA_CR42_FM_ENABLE 0x04 + +#define via_probe_midi probe_uart401 +#define via_attach_midi attach_uart401 +#define via_unload_midi unload_uart401 + +static struct address_info sb_data[MAX_CARDS]; +static struct address_info opl3_data[MAX_CARDS]; +static unsigned cards = 0; + + +static void __init via_attach_sb(struct address_info *hw_config) +{ + if(!sb_dsp_init(hw_config)) + hw_config->slots[0] = -1; +} + + +static int __init via_probe_sb(struct address_info *hw_config) +{ + if (check_region(hw_config->io_base, 16)) + { + printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n", + hw_config->io_base); + return 0; + } + return sb_dsp_detect(hw_config, 0, 0); +} + + +static void __exit via_unload_sb(struct address_info *hw_config, int unload_mpu) +{ + if(hw_config->slots[0]!=-1) + sb_dsp_unload(hw_config, unload_mpu); +} + + +static int __init via82cxxx_install (struct pci_dev *pcidev) +{ + int sb_io_base = 0; + int sb_irq = 0; + int sb_dma = 0; + int midi_base = 0; + u8 tmp8; + + memset (&sb_data[cards], 0, sizeof (struct address_info)); + memset (&opl3_data[cards], 0, sizeof (struct address_info)); + + sb_data[cards].name = opl3_data[cards].name = VIA_CARD_NAME; + opl3_data[cards].irq = -1; + + /* turn on features, if not already */ + pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8); + tmp8 |= VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE | + VIA_CR42_FM_ENABLE; + pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8); + + /* read legacy PNP info byte */ + pci_read_config_byte (pcidev, VIA_PNP_CONTROL, &tmp8); + pci_write_config_byte (pcidev, VIA_PNP_CONTROL, tmp8); + + switch ((tmp8 >> 6) & 0x03) { + case 0: sb_irq = 5; break; + case 1: sb_irq = 7; break; + case 2: sb_irq = 9; break; + case 3: sb_irq = 10; break; + default: /* do nothing */ break; + } + switch ((tmp8 >> 4) & 0x03) { + case 0: sb_dma = 0; break; + case 1: sb_dma = 1; break; + case 2: sb_dma = 2; break; + case 3: sb_dma = 3; break; + default: /* do nothing */ break; + } + switch ((tmp8 >> 2) & 0x03) { + case 0: midi_base = 0x300; break; + case 1: midi_base = 0x310; break; + case 2: midi_base = 0x320; break; + case 3: midi_base = 0x330; break; + default: /* do nothing */ break; + } + switch (tmp8 & 0x03) { + case 0: sb_io_base = 0x220; break; + case 1: sb_io_base = 0x240; break; + case 2: sb_io_base = 0x260; break; + case 3: sb_io_base = 0x280; break; + default: /* do nothing */ break; + } + + udelay(100); + + printk(KERN_INFO PFX "legacy " + "MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA\n", + midi_base, sb_io_base, sb_irq, sb_dma); + + sb_data[cards].card_subtype = MDL_SBPRO; + sb_data[cards].io_base = sb_io_base; + sb_data[cards].irq = sb_irq; + sb_data[cards].dma = sb_dma; + + opl3_data[cards].io_base = midi_base; + + /* register legacy SoundBlaster Pro */ + if (!via_probe_sb (&sb_data[cards])) { + printk (KERN_ERR PFX + "SB probe @ 0x%X failed, aborting\n", + sb_io_base); + return -1; + } + via_attach_sb (&sb_data[cards]); + + /* register legacy MIDI */ + if (!via_probe_midi (&opl3_data[cards])) { + printk (KERN_ERR PFX + "MIDI probe @ 0x%X failed, aborting\n", + midi_base); + via_unload_sb (&sb_data[cards], 0); + return -1; + } + via_attach_midi (&opl3_data[cards]); + + cards++; + return 0; +} + + +/* + * This loop walks the PCI configuration database and finds where + * the sound cards are. + */ + +static int __init probe_via82cxxx (void) +{ + struct pci_dev *pcidev = NULL; + + while ((pcidev = pci_find_device (PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C686_5, + pcidev)) != NULL) { + + if (via82cxxx_install (pcidev) != 0) { + printk (KERN_ERR PFX "audio init failed\n"); + return -1; + } + + if (cards == MAX_CARDS) { + printk (KERN_DEBUG PFX "maximum number of cards reached\n"); + break; + } + } + + return 0; +} + + +/* + * This function is called when the user or kernel loads the + * module into memory. + */ + + +static int __init init_via82cxxx_module(void) +{ + if (!pci_present ()) { + printk (KERN_DEBUG PFX "PCI not present, exiting\n"); + return -ENODEV; + } + + if (probe_via82cxxx() != 0) { + printk(KERN_ERR PFX "probe failed, aborting\n"); + /* XXX unload cards registered so far, if any */ + return -ENODEV; + } + + if (cards == 0) { + printk(KERN_DEBUG PFX "No chips found, aborting\n"); + return -ENODEV; + } + + printk (KERN_INFO PFX VIA_CARD_NAME " loaded\n"); + + /* + * Binds us to the sound subsystem + */ + SOUND_LOCK; + return 0; +} + +/* + * This is called when it is removed. It will only be removed + * when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK + * macros hide the entire work for this. + */ + +static void __exit cleanup_via82cxxx_module(void) +{ + int i; + + for (i = 0; i < cards; i++) + via_unload_sb (&sb_data[i], 1); + + /* + * Final clean up with the sound layer + */ + SOUND_LOCK_END; +} + +module_init(init_via82cxxx_module); +module_exit(cleanup_via82cxxx_module); + diff -u --recursive --new-file v2.3.16/linux/drivers/usb/CREDITS linux/drivers/usb/CREDITS --- v2.3.16/linux/drivers/usb/CREDITS Mon Aug 2 14:29:08 1999 +++ linux/drivers/usb/CREDITS Wed Sep 1 15:31:47 1999 @@ -9,6 +9,7 @@ ham Bradley M Keryan Paul Mackerras + David E. Nelson Vojtech Pavlik Gregory P. Smith Linus Torvalds diff -u --recursive --new-file v2.3.16/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.3.16/linux/drivers/usb/Config.in Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/Config.in Wed Sep 1 15:31:47 1999 @@ -28,6 +28,7 @@ dep_tristate 'USB hub support' CONFIG_USB_HUB $CONFIG_USB dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB + dep_tristate 'USB HP scanner support' CONFIG_USB_HP_SCANNER $CONFIG_USB dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB dep_tristate 'USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB diff -u --recursive --new-file v2.3.16/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.3.16/linux/drivers/usb/Makefile Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/Makefile Wed Sep 1 15:31:47 1999 @@ -64,6 +64,14 @@ MIX_OBJS += mouse.o endif +ifeq ($(CONFIG_USB_HP_SCANNER),y) + L_OBJS += hp_scanner.o +endif +ifeq ($(CONFIG_USB_HP_SCANNER),m) + M_OBJS +=hp_scanner.o + MIX_OBJS +=hp_scanner.o +endif + ifeq ($(CONFIG_USB_HUB),y) L_OBJS += hub.o endif diff -u --recursive --new-file v2.3.16/linux/drivers/usb/README.hp_scanner linux/drivers/usb/README.hp_scanner --- v2.3.16/linux/drivers/usb/README.hp_scanner Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/README.hp_scanner Wed Sep 1 15:31:47 1999 @@ -0,0 +1,59 @@ +August 30, 1999 + + +Overview + +This README will address issues regarding how to configure the kernel +to access a USB HP Scanner. The scanner should support the Scanner +Control Language (SCL) so that applications such as SANE can access it +properly. Refer to the document README.hp_scanner_sane for guidance +on how to configure SANE to use the USB HP Scanner. + + +Requirements + +A host with a USB port. Ideally, either a UHCI (Intel) or OHCI +(Compaq and others) hardware port should work. However, I've only +been able to really use an OHCI controller. I did have access to a +system with a UHCI controller but some very limited testing did not +produce satisfactory results. + +A Linux kernel with USB support (preferably 2.3.15+). + +A Linux kernel with USB HP Scanner support. + + +Configuration + +Add both USB controller support and USB HP Scanner support using `make +menuconfig`. If you decide to use the ohci-hcd driver, don't forget +to add HUB support. Compile and install the modules. Testing was +performed only as modules, YMMV. + +Add a device for the USB scanner: `mknod /dev/usbscanner c 16 1` + +Set appropriate permissions for /dev/usbscanner. Both read and write +permissions are needed for proper operation. + +Load the appropriate modules: + + OHCI: + + modprobe usb-ohci + modprobe hp_scanner + + OHCI-HCD: + modprobe usb-ohci-hcd + modprobe hub + modprobe hp_scanner + +That's it. SANE should now be able to access the device. + +There is a small test program (hp_scan.c) that can be used to test the +scanner device. It's purpose is to test the driver(s) without having +to retrieve/configure SANE. Hp_scan.c will scan the entire bed and +put the output into a file called out.dat in the current directory. +The data in the file is raw data. + +David /\/elson +dnelson@jump.net diff -u --recursive --new-file v2.3.16/linux/drivers/usb/README.hp_scanner_sane linux/drivers/usb/README.hp_scanner_sane --- v2.3.16/linux/drivers/usb/README.hp_scanner_sane Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/README.hp_scanner_sane Wed Sep 1 15:31:47 1999 @@ -0,0 +1,67 @@ +August 30, 1999 + +NOTE: This is all VERY alpha. Use at your own risk. There is no +warranty expressed nor implied. + + +Introduction + +This document will hopefully provide enough info on how to get SANE +working with a Hewlett Packard USB capable scanner using the USB +interface. The majority of HP Scanners support the Scanner Control +Language (SCL) which is both published by HP and supported by SANE. +The only HP Scanner that I'm aware of that does not support SCL is the +4200C. All other HP scanners with USB interfaces should work (4100C, +5200C, 6200C). Of course as HP releases new scanners this information +may change. + + +Requirements + +In order to get this running you'll need USB support in your kernel in +addition to USB HP Scanner support. Please refer to README.hp_scanner +for issues pertaining to Linux USB and USB HP Scanner support. + +An installed version of SANE which is available from +http://www.mostang.com/sane/. Testing has been performed using +version SANE-1.0.1. For instructions on building and installing SANE, +refer to the various README files within the distribution. + + +Ok, so what do I do? + +NOTE: $INSTALL_DIR is the location where SANE was installed. It may +be /usr/local, /usr, /opt or somewhere else. If you don't know, ask +your system administrator. + +1) Make sure that you have the libsane-hp.* libraries under the +$INSTALL_DIR/lib/sane/ directory. + +2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following +files: dll.conf, hp.conf. + + dll.conf: Make sure that the 'hp' entry is present and uncommented. + + hp.conf: This should contain two lines: + + option connect-device + /dev/usbscanner + +3) You should now be able to use SANE (xscanimage or scanimage). + +Don't forget to read any relevant man pages regarding the usage of +SANE. If you have other entries uncommented in dll.conf, you my have +to specify the device to (x)scanimage. The xscanimage (1) man page +has info on how to get 'The Gimp' to work with xscanimage. Note that +Gimp support must be compiled into SANE for it work. If you are +dealing with a RedHat system, you'll also need to install the +gimp-devel rpm package. + +NOTE: Most of the time xscanimage will run without incident, then on +the next invocation it'll core dump at different locations. I don't +know why yet and I don't have a work around either other than to try +again. But once you get it started, it'll scan without any problems +(or at least it does for me). + +David /\/elson +dnelson@jump.net diff -u --recursive --new-file v2.3.16/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c --- v2.3.16/linux/drivers/usb/cpia.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/cpia.c Wed Sep 1 16:24:19 1999 @@ -597,9 +597,9 @@ /* First for desc. [0] */ id = cpia->sbuf [0].isodesc; id->start_type = START_ASAP; - id->callback_frames = 1; /* on every frame */ + id->callback_frames = 10; /* on every 10th frame */ id->callback_fn = cpia_isoc_irq; - id->data = cpia->sbuf [0].data; + id->data = cpia->sbuf[0].data; id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; for (fx = 0; fx < FRAMES_PER_DESC; fx++) id->frames [fx].frame_length = FRAME_SIZE_PER_DESC; @@ -607,15 +607,15 @@ /* and the desc. [1] */ id = cpia->sbuf [1].isodesc; id->start_type = 0; /* will follow the first desc. */ - id->callback_frames = 1; /* on every frame */ + id->callback_frames = 10; /* on every 10th frame */ id->callback_fn = cpia_isoc_irq; - id->data = cpia->sbuf [1].data; + id->data = cpia->sbuf[1].data; id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; for (fx = 0; fx < FRAMES_PER_DESC; fx++) id->frames [fx].frame_length = FRAME_SIZE_PER_DESC; - usb_run_isoc (cpia->sbuf [0].isodesc, NULL); - usb_run_isoc (cpia->sbuf [1].isodesc, cpia->sbuf [0].isodesc); + usb_run_isoc (cpia->sbuf[0].isodesc, NULL); + usb_run_isoc (cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc); #if 0 usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL); diff -u --recursive --new-file v2.3.16/linux/drivers/usb/cpia.h linux/drivers/usb/cpia.h --- v2.3.16/linux/drivers/usb/cpia.h Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/cpia.h Wed Sep 1 16:24:19 1999 @@ -82,7 +82,7 @@ #define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2) -#define FRAMES_PER_DESC 500 +#define FRAMES_PER_DESC 10 #define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */ enum { diff -u --recursive --new-file v2.3.16/linux/drivers/usb/ezusb.c linux/drivers/usb/ezusb.c --- v2.3.16/linux/drivers/usb/ezusb.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/ezusb.c Tue Sep 7 10:19:45 1999 @@ -26,18 +26,22 @@ * bulk reads. * Implemented EZUSB_SETINTERFACE, more sanity checks for EZUSB_BULK. * Preliminary ISO support + * 0.3 01.09.99 Async Bulk and ISO support + * 0.4 01.09.99 * */ /*****************************************************************************/ +#include #include #include -#include #include #include #include #include +#include +#include #include "usb.h" #include "ezusb.h" @@ -49,27 +53,190 @@ static struct ezusb { struct semaphore mutex; struct usb_device *usbdev; - struct list_head iso; + struct list_head async_pending; + struct list_head async_completed; + wait_queue_head_t wait; + spinlock_t lock; } ezusb[NREZUSB]; -struct isodesc { - struct list_head isolist; - spinlock_t lock; - struct usb_device *usbdev; - unsigned int ep; - unsigned int pipe; - unsigned int pktsz; - unsigned int framesperint; - unsigned int rd, wr, buflen; - unsigned int flags; - unsigned int schedcnt, unschedcnt; - - void *hcbuf[2]; - void *hcisodesc[2]; - unsigned char *buf; -}; +struct async { + struct list_head asynclist; + struct ezusb *ez; + void *data; + unsigned dataorder; + void *userdata; + unsigned datalen; + union { + struct usb_isoc_desc *iso; + void *bulk; + } desc; + unsigned numframes; /* 0 means bulk, > 0 means iso */ + struct ezusb_asynccompleted completed; +}; -#define ISOFLG_ACTIVE (1<<0) +/* --------------------------------------------------------------------- */ + +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; +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ void async_removelist(struct async *as) +{ + struct ezusb *ez = as->ez; + unsigned long flags; + + spin_lock_irqsave(&ez->lock, flags); + list_del(&as->asynclist); + INIT_LIST_HEAD(&as->asynclist); + spin_unlock_irqrestore(&ez->lock, flags); +} + +extern __inline__ void async_newpending(struct async *as) +{ + struct ezusb *ez = as->ez; + unsigned long flags; + + spin_lock_irqsave(&ez->lock, flags); + list_add_tail(&as->asynclist, &ez->async_pending); + spin_unlock_irqrestore(&ez->lock, flags); +} + +extern __inline__ void async_movetocompleted(struct async *as) +{ + struct ezusb *ez = as->ez; + unsigned long flags; + + spin_lock_irqsave(&ez->lock, flags); + list_del(&as->asynclist); + list_add_tail(&as->asynclist, &ez->async_completed); + spin_unlock_irqrestore(&ez->lock, flags); +} + +extern __inline__ struct async *async_getcompleted(struct ezusb *ez) +{ + unsigned long flags; + struct async *as = NULL; + + spin_lock_irqsave(&ez->lock, flags); + if (!list_empty(&ez->async_completed)) { + as = list_entry(ez->async_completed.next, struct async, asynclist); + list_del(&as->asynclist); + INIT_LIST_HEAD(&as->asynclist); + } + spin_unlock_irqrestore(&ez->lock, flags); + return as; +} + +extern __inline__ struct async *async_getpending(struct ezusb *ez, void *context) +{ + unsigned long flags; + struct async *as; + struct list_head *p; + + spin_lock_irqsave(&ez->lock, flags); + for (p = ez->async_pending.next; p != &ez->async_pending; ) { + as = list_entry(p, struct async, asynclist); + p = p->next; + if (as->completed.context != context) + continue; + list_del(&as->asynclist); + INIT_LIST_HEAD(&as->asynclist); + spin_unlock_irqrestore(&ez->lock, flags); + return as; + } + spin_unlock_irqrestore(&ez->lock, flags); + return NULL; +} + +/* --------------------------------------------------------------------- */ + +static int async_completed(int status, void *__buffer, int rval, void *dev_id) +{ + struct async *as = (struct async *)dev_id; + struct ezusb *ez = as->ez; + unsigned cnt; + +printk(KERN_DEBUG "ezusb: async_completed: status %d rval %d\n", status, rval); + as->completed.length = rval; + if (as->numframes > 0) { + as->completed.status = USB_ST_NOERROR; + for (cnt = 0; cnt < as->numframes; cnt++) { + as->completed.isostat[cnt].status = as->desc.iso->frames[cnt].frame_status; + as->completed.isostat[cnt].length = as->desc.iso->frames[cnt].frame_length; + } + } else + as->completed.status = status; + spin_lock(&ez->lock); + list_del(&as->asynclist); + list_add_tail(&as->asynclist, &ez->async_completed); + spin_unlock(&ez->lock); + wake_up(&ez->wait); + return 0; +} + +static void remove_async(struct async *as) +{ + if (as->data && as->dataorder) + free_pages((unsigned long)as->data, as->dataorder); + if (as->numframes) + usb_free_isoc(as->desc.iso); + kfree(as); +} + +static void kill_async(struct async *as) +{ + struct ezusb *ez = as->ez; + + if (as->numframes) + /* ISO case */ + usb_kill_isoc(as->desc.iso); + else + usb_terminate_bulk(ez->usbdev, as->desc.bulk); + as->completed.status = USB_ST_REMOVED; + async_movetocompleted(as); +} + +static void destroy_all_async(struct ezusb *ez) +{ + struct async *as; + unsigned long flags; + + spin_lock_irqsave(&ez->lock, flags); + if (!list_empty(&ez->async_pending)) { + as = list_entry(ez->async_pending.next, struct async, asynclist); + list_del(&as->asynclist); + INIT_LIST_HEAD(&as->asynclist); + spin_unlock_irqrestore(&ez->lock, flags); + kill_async(as); + spin_lock_irqsave(&ez->lock, flags); + } + spin_unlock_irqrestore(&ez->lock, flags); + while ((as = async_getcompleted(ez))) + remove_async(as); +} /* --------------------------------------------------------------------- */ @@ -216,439 +383,505 @@ up(&ez->mutex); file->f_pos = 0; file->private_data = ez; + MOD_INC_USE_COUNT; return 0; } static int ezusb_release(struct inode *inode, struct file *file) { struct ezusb *ez = (struct ezusb *)file->private_data; + + down(&ez->mutex); + destroy_all_async(ez); + up(&ez->mutex); + MOD_DEC_USE_COUNT; + return 0; +} + +static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype, + unsigned char request, unsigned short value, + unsigned short index, unsigned short length, + void *data) +{ + unsigned char *tbuf = NULL; + unsigned int pipe; + int i; + + if (length > PAGE_SIZE) + return -EINVAL; + /* __range_ok is broken; + with unsigned short size, it gave + addl %si,%edx ; sbbl %ecx,%ecx; cmpl %edx,12(%eax); sbbl $0,%ecx + */ + if (requesttype & 0x80) { + pipe = usb_rcvctrlpipe(usbdev, 0); + if (length > 0 && !access_ok(VERIFY_WRITE, data, (unsigned int)length)) + return -EFAULT; + } else + pipe = usb_sndctrlpipe(usbdev, 0); + if (length > 0) { + if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) + return -ENOMEM; + if (!(requesttype & 0x80)) { + if (copy_from_user(tbuf, data, length)) { + free_page((unsigned long)tbuf); + return -EFAULT; + } + } + } + i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length); + if (i < 0) { + if (length > 0) + free_page((unsigned long)tbuf); + printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", + requesttype, request, length, i); + return -ENXIO; + } + if (requesttype & 0x80 && length > 0 && copy_to_user(data, tbuf, length)) + i = -EFAULT; + if (length > 0) + free_page((unsigned long)tbuf); + return i; +} + +static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, void *data) +{ + unsigned char *tbuf = NULL; + unsigned int pipe; + unsigned long len2 = 0; + int ret = 0; + + if (length > PAGE_SIZE) + return -EINVAL; + if ((ep & ~0x80) >= 16) + return -EINVAL; + if (ep & 0x80) { + pipe = usb_rcvbulkpipe(usbdev, ep & 0x7f); + if (length > 0 && !access_ok(VERIFY_WRITE, data, length)) + return -EFAULT; + } else + pipe = usb_sndbulkpipe(usbdev, ep & 0x7f); + if (!usb_maxpacket(usbdev, pipe, !(ep & 0x80))) + return -EINVAL; + if (length > 0) { + if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) + return -ENOMEM; + if (!(ep & 0x80)) { + if (copy_from_user(tbuf, data, length)) { + free_page((unsigned long)tbuf); + return -EFAULT; + } + } + } + ret = usbdev->bus->op->bulk_msg(usbdev, pipe, tbuf, length, &len2); + if (ret < 0) { + if (length > 0) + free_page((unsigned long)tbuf); + printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", + ep, length, ret); + return -ENXIO; + } + if (len2 > length) + len2 = length; + ret = len2; + if (ep & 0x80 && len2 > 0 && copy_to_user(data, tbuf, len2)) + ret = -EFAULT; + if (length > 0) + free_page((unsigned long)tbuf); + return ret; +} + +static int ezusb_resetep(struct usb_device *usbdev, unsigned int ep) +{ + if ((ep & ~0x80) >= 16) + return -EINVAL; + usb_settoggle(usbdev, ep & 0xf, !(ep & 0x80), 0); return 0; } -static void iso_schedrcv(struct isodesc *isodesc) +static int ezusb_setinterface(struct usb_device *usbdev, unsigned int interface, unsigned int altsetting) { - unsigned diff; + if (usb_set_interface(usbdev, interface, altsetting) < 0) + return -EINVAL; + return 0; +} + +static int ezusb_setconfiguration(struct usb_device *usbdev, unsigned int config) +{ + if (usb_set_configuration(usbdev, config) < 0) + return -EINVAL; + return 0; +} + +static int ezusb_requestbulk(struct ezusb *ez, struct ezusb_asyncbulk *ab) +{ + struct async *as = NULL; + unsigned int pipe; + + if (ab->len > PAGE_SIZE) + return -EINVAL; + if ((ab->ep & ~0x80) >= 16) + return -EINVAL; + if (ab->ep & 0x80) { + pipe = usb_rcvbulkpipe(ez->usbdev, ab->ep & 0x7f); + if (ab->len > 0 && !access_ok(VERIFY_WRITE, ab->data, ab->len)) + return -EFAULT; + } else + pipe = usb_sndbulkpipe(ez->usbdev, ab->ep & 0x7f); + if (!usb_maxpacket(ez->usbdev, pipe, !(ab->ep & 0x80))) + return -EINVAL; + if (!(as = kmalloc(sizeof(struct async), GFP_KERNEL))) + return -ENOMEM; + INIT_LIST_HEAD(&as->asynclist); + as->ez = ez; + as->userdata = ab->data; + as->numframes = 0; + as->data = 0; + as->dataorder = 0; + as->datalen = ab->len; + as->completed.context = ab->context; + if (ab->len > 0) { + as->dataorder = 1; + if (!(as->data = (unsigned char *)__get_free_page(GFP_KERNEL))) { + kfree(as); + return -ENOMEM; + } + if (!(ab->ep & 0x80)) { + if (copy_from_user(as->data, ab->data, ab->len)) + goto err_fault; + as->datalen = 0; /* no need to copy back at completion */ + } + } + async_newpending(as); + if (!(as->desc.bulk = usb_request_bulk(ez->usbdev, pipe, async_completed, as->data, ab->len, as))) { + async_removelist(as); + goto err_inval; + } + return 0; - if (!(isodesc->flags & ISOFLG_ACTIVE)) - return; - diff = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen; - if (diff < isodesc->framesperint * isodesc->pktsz) - return; - for (;;) { - diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3; - if (diff >= 2) - return; - usb_schedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->schedcnt & 1], - diff ? isodesc->hcisodesc[(isodesc->schedcnt - 1) & 1] : NULL); - isodesc->schedcnt++; - } -} - -static void iso_schedsnd(struct isodesc *isodesc) -{ - unsigned diff, bcnt, x; - unsigned char *p1, *p2; - - if (!(isodesc->flags & ISOFLG_ACTIVE)) - return; - for (;;) { - diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3; - if (diff >= 2) - return; - bcnt = (isodesc->buflen - isodesc->rd + isodesc->wr) % isodesc->buflen; - if (bcnt < isodesc->framesperint * isodesc->pktsz) - return; - p2 = isodesc->hcbuf[isodesc->schedcnt & 1]; - for (bcnt = 0; bcnt < isodesc->framesperint; bcnt++) { - p1 = isodesc->buf + isodesc->rd; - if (isodesc->rd + isodesc->pktsz > isodesc->buflen) { - x = isodesc->buflen - isodesc->rd; - memcpy(p2, p1, x); - memcpy(p2+x, isodesc->buf, isodesc->pktsz - x); - } else - memcpy(p2, p1, isodesc->pktsz); - isodesc->rd = (isodesc->rd + isodesc->pktsz) % isodesc->buflen; - p2 += isodesc->pktsz; - if (((unsigned long)p2 ^ ((unsigned long)p2 + isodesc->pktsz - 1)) & (~(PAGE_SIZE - 1))) - p2 = (void *)(((unsigned long)p2 + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1))); - } - usb_schedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->schedcnt & 1], - diff ? isodesc->hcisodesc[(isodesc->schedcnt - 1) & 1] : NULL); - isodesc->schedcnt++; - } -} - -static int ezusb_isorcv_irq(int status, void *__buffer, int __len, void *dev_id) -{ - struct isodesc *isodesc = (struct isodesc *)dev_id; - unsigned int len, len2; - unsigned char *p1; - - spin_lock(&isodesc->lock); - usb_unschedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]); - len = usb_compress_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]); - printk(KERN_DEBUG "ezusb_isorcv_irq: %u bytes recvd\n", len); - p1 = isodesc->hcbuf[isodesc->unschedcnt & 1]; - while (len > 0) { - len2 = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen; - if (!len2) - break; - if (isodesc->wr + len2 > isodesc->buflen) - len2 = isodesc->buflen - isodesc->wr; - if (len2 > len) - len2 = len; - memcpy(isodesc->buf + isodesc->wr, p1, len2); - isodesc->wr = (isodesc->wr + len2) % isodesc->buflen; - p1 += len2; - len -= len2; - } - isodesc->unschedcnt++; - iso_schedrcv(isodesc); - spin_unlock(&isodesc->lock); - return 1; -} - -static int ezusb_isosnd_irq(int status, void *__buffer, int len, void *dev_id) -{ - struct isodesc *isodesc = (struct isodesc *)dev_id; - - spin_lock(&isodesc->lock); - usb_unschedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]); - isodesc->unschedcnt++; - iso_schedsnd(isodesc); - spin_unlock(&isodesc->lock); - return 1; -} - -static struct isodesc *findiso(struct ezusb *ez, unsigned int ep) -{ - struct list_head *head = &ez->iso; - struct list_head *tmp = head->next; - struct isodesc *id; - - while (tmp != head) { - id = list_entry(tmp, struct isodesc, isolist); - if (id->ep == ep) - return id; - tmp = tmp->next; + err_fault: + if (as) { + if (as->data) + free_page((unsigned long)as->data); + kfree(as); } - return NULL; + return -EFAULT; + + err_inval: + if (as) { + if (as->data) + free_page((unsigned long)as->data); + kfree(as); + } + return -EINVAL; +} + +static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigned char *cmd) +{ + struct async *as; + unsigned int maxpkt, pipe; + unsigned int dsize, order, assize, j; + int i; + + if ((ai->ep & ~0x80) >= 16 || ai->framecnt < 1 || ai->framecnt > 128) + return -EINVAL; + if (ai->ep & 0x80) + pipe = usb_rcvisocpipe(ez->usbdev, ai->ep & 0x7f); + else + pipe = usb_sndisocpipe(ez->usbdev, ai->ep & 0x7f); + if (!(maxpkt = usb_maxpacket(ez->usbdev, pipe, !(ai->ep & 0x80)))) + return -EINVAL; + dsize = maxpkt * ai->framecnt; + if (dsize > 65536) + return -EINVAL; + order = ld2(dsize >> PAGE_SHIFT); + if (dsize > (PAGE_SIZE << order)) + order++; + if (ai->ep & 0x80) + if (dsize > 0 && !access_ok(VERIFY_WRITE, ai->data, dsize)) + return -EFAULT; + assize = sizeof(struct async) + ai->framecnt * sizeof(struct ezusb_isoframestat); + if (!(as = kmalloc(assize, GFP_KERNEL))) + return -ENOMEM; + memset(as, 0, assize); + INIT_LIST_HEAD(&as->asynclist); + as->ez = ez; + as->userdata = ai->data; + as->numframes = ai->framecnt; + as->data = 0; + as->dataorder = order; + as->datalen = dsize; + as->completed.context = ai->context; + as->desc.iso = NULL; + if (dsize > 0) { + if (!(as->data = (unsigned char *)__get_free_pages(GFP_KERNEL, order))) { + kfree(as); + return -ENOMEM; + } + if (!(ai->ep & 0x80)) { + if (copy_from_user(as->data, ai->data, dsize)) + goto err_fault; + as->datalen = 0; /* no need to copy back at completion */ + } + } + if ((i = usb_init_isoc(ez->usbdev, pipe, ai->framecnt, as, &as->desc.iso))) { + printk(KERN_DEBUG "ezusb: usb_init_isoc error %d\n", i); + goto err_inval; + } + as->desc.iso->start_type = START_ABSOLUTE; + as->desc.iso->start_frame = ai->startframe; + as->desc.iso->callback_frames = 0; + as->desc.iso->callback_fn = async_completed; + as->desc.iso->data = as->data; + as->desc.iso->buf_size = dsize; + for (j = 0; j < ai->framecnt; j++) { + if (get_user(i, (int *)(cmd + j * sizeof(struct ezusb_isoframestat)))) { + usb_free_isoc(as->desc.iso); + kfree(as); + return -EFAULT; + } + if (i < 0) + i = 0; + as->desc.iso->frames[j].frame_length = i; + } + async_newpending(as); + if ((i = usb_run_isoc(as->desc.iso, NULL))) { + printk(KERN_DEBUG "ezusb: usb_run_isoc error %d\n", i); + async_removelist(as); + goto err_inval; + } + return 0; + + err_fault: + if (as) { + if (as->desc.iso) + usb_free_isoc(as->desc.iso); + if (as->data) + free_page((unsigned long)as->data); + kfree(as); + } + return -EFAULT; + + err_inval: + if (as) { + if (as->desc.iso) + usb_free_isoc(as->desc.iso); + if (as->data) + free_page((unsigned long)as->data); + kfree(as); + } + return -EINVAL; +} + +static int ezusb_terminateasync(struct ezusb *ez, void *context) +{ + struct async *as; + int ret = 0; + + while ((as = async_getpending(ez, context))) { + kill_async(as); + ret++; + } + return ret; +} + +static int ezusb_asynccompl(struct async *as, void *arg) +{ + if (as->datalen > 0) { + if (copy_to_user(as->userdata, as->data, as->datalen)) { + remove_async(as); + return -EFAULT; + } + } + if (copy_to_user(arg, &as->completed, + sizeof(struct ezusb_asynccompleted) + + as->numframes * sizeof(struct ezusb_isoframestat))) { + remove_async(as); + return -EFAULT; + } + remove_async(as); + return 0; } static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct ezusb *ez = (struct ezusb *)file->private_data; + DECLARE_WAITQUEUE(wait, current); + struct usb_proc_ctrltransfer pctrl; + struct usb_proc_bulktransfer pbulk; + struct usb_proc_setinterface psetintf; struct ezusb_ctrltransfer ctrl; struct ezusb_bulktransfer bulk; struct ezusb_setinterface setintf; - unsigned int len1, ep, pipe, cnt; - unsigned long len2; - unsigned char tbuf[1024]; - int i; - struct ezusb_isotransfer isot; - struct ezusb_isodata isod; - struct isodesc *isodesc; - usb_device_irq isocompl; - unsigned long flags; - unsigned char *p1, *p2; + struct ezusb_asyncbulk abulk; + struct ezusb_asynciso aiso; + struct async *as; + void *context; + unsigned int ep, cfg; + int i, ret = 0; + down(&ez->mutex); + if (!ez->usbdev) { + up(&ez->mutex); + return -EIO; + } switch (cmd) { - case EZUSB_CONTROL: - copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT); - if (ctrl.dlen > sizeof(tbuf) || ctrl.dlen > 1024) - return -EINVAL; - if (ctrl.requesttype & 0x80) { - if (ctrl.dlen && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.dlen)) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), - (devrequest *)&ctrl, tbuf, ctrl.dlen); - up(&ez->mutex); - if (!i && ctrl.dlen) { - copy_to_user_ret(ctrl.data, tbuf, ctrl.dlen, -EFAULT); - } - } else { - if (ctrl.dlen) { - copy_from_user_ret(tbuf, ctrl.data, ctrl.dlen, -EFAULT); - } - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), - (devrequest *)&ctrl, tbuf, ctrl.dlen); - up(&ez->mutex); + case USB_PROC_CONTROL: + if (copy_from_user(&pctrl, (void *)arg, sizeof(pctrl))) { + ret = -EFAULT; + break; } - if (i) { - printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", - ctrl.requesttype, ctrl.request, ctrl.length, i); - return -ENXIO; + ret = ezusb_control(ez->usbdev, pctrl.requesttype, pctrl.request, + pctrl.value, pctrl.index, pctrl.length, pctrl.data); + break; + + case USB_PROC_BULK: + if (copy_from_user(&pbulk, (void *)arg, sizeof(pbulk))) { + ret = -EFAULT; + break; } - return 0; + ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len, pbulk.data); + break; - case EZUSB_BULK: - copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT); - if (bulk.ep & 0x80) - pipe = usb_rcvbulkpipe(ez->usbdev, bulk.ep & 0x7f); - else - pipe = usb_sndbulkpipe(ez->usbdev, bulk.ep & 0x7f); - if (!usb_maxpacket(ez->usbdev, pipe, !(bulk.ep & 0x80))) - return -EINVAL; - len1 = bulk.len; - if (len1 > sizeof(tbuf)) - len1 = sizeof(tbuf); - if (bulk.ep & 0x80) { - if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, pipe, tbuf, len1, &len2); - up(&ez->mutex); - if (!i && len2) { - copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT); - } - } else { - if (len1) { - copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT); - } - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, pipe, tbuf, len1, &len2); - up(&ez->mutex); + case USB_PROC_RESETEP: + if (get_user(ep, (unsigned int *)arg)) { + ret = -EFAULT; + break; } - if (i) { - printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", - bulk.ep, bulk.len, i); - return -ENXIO; + ret = ezusb_resetep(ez->usbdev, ep); + break; + + case USB_PROC_SETINTERFACE: + if (copy_from_user(&psetintf, (void *)arg, sizeof(psetintf))) { + ret = -EFAULT; + break; } - return len2; + ret = ezusb_setinterface(ez->usbdev, psetintf.interface, psetintf.altsetting); + break; - case EZUSB_RESETEP: - get_user_ret(ep, (unsigned int *)arg, -EFAULT); - if ((ep & ~0x80) >= 16) - return -EINVAL; - usb_settoggle(ez->usbdev, ep & 0xf, !(ep & 0x80), 0); - return 0; + case USB_PROC_SETCONFIGURATION: + if (get_user(cfg, (unsigned int *)arg)) { + ret = -EFAULT; + break; + } + ret = ezusb_setconfiguration(ez->usbdev, cfg); + break; - case EZUSB_SETINTERFACE: - copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT); - if (usb_set_interface(ez->usbdev, setintf.interface, setintf.altsetting)) - return -EINVAL; - return 0; - - case EZUSB_STARTISO: - copy_from_user_ret(&isot, (void *)arg, sizeof(isot), -EFAULT); - len1 = isot.framesperint * isot.pktsz; - if (len1 > PAGE_SIZE) { - len1 = PAGE_SIZE / isot.pktsz; - len1 = PAGE_SIZE * ((isot.framesperint + len1 - 1) / len1); - } - len2 = (isot.pktsz * 1000 + PAGE_SIZE - 1) & (PAGE_SIZE-1); - if (len2 > 32*PAGE_SIZE) - len2 = PAGE_SIZE; - if ((isot.ep & ~0x80) >= 16 || isot.pktsz < 1 || isot.pktsz > 1023 || - isot.framesperint < 1 || isot.framesperint > 1000 || - len1 > 4*PAGE_SIZE) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; + case EZUSB_CONTROL: + if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) { + ret = -EFAULT; + break; } - if (findiso(ez, isod.ep)) { - up(&ez->mutex); - return -EBUSY; + if (ctrl.dlen != ctrl.length) { + ret = -EINVAL; + break; } - if (isot.ep & 0x80) { - pipe = usb_rcvisocpipe(ez->usbdev, isot.ep & 15); - isocompl = ezusb_isorcv_irq; - } else { - pipe = usb_sndisocpipe(ez->usbdev, isot.ep & 15); - isocompl = ezusb_isosnd_irq; + ret = ezusb_control(ez->usbdev, ctrl.requesttype, ctrl.request, + ctrl.value, ctrl.index, ctrl.length, ctrl.data); + break; + + case EZUSB_BULK: + if (copy_from_user(&bulk, (void *)arg, sizeof(bulk))) { + ret = -EFAULT; + break; } - if (!(isodesc = kmalloc(sizeof(struct isodesc), GFP_KERNEL))) { - up(&ez->mutex); - return -ENOMEM; + ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len, bulk.data); + break; + + case EZUSB_RESETEP: + if (get_user(ep, (unsigned int *)arg)) { + ret = -EFAULT; + break; } - memset(isodesc, 0, sizeof(struct isodesc)); - INIT_LIST_HEAD(&isodesc->isolist); - spin_lock_init(&isodesc->lock); - isodesc->usbdev = ez->usbdev; - isodesc->ep = isot.ep; - isodesc->pktsz = isot.pktsz; - isodesc->framesperint = isot.framesperint; - isodesc->buflen = len2; - if (!(isodesc->hcbuf[0] = kmalloc(len1, GFP_KERNEL)) || - !(isodesc->hcbuf[1] = kmalloc(len1, GFP_KERNEL))) - goto startisomemerr; - if (!(isodesc->hcisodesc[0] = usb_allocate_isochronous(ez->usbdev, pipe, isodesc->hcbuf[0], - len1, isodesc->pktsz, isocompl, isodesc)) || - !(isodesc->hcisodesc[1] = usb_allocate_isochronous(ez->usbdev, pipe, isodesc->hcbuf[1], - len1, isodesc->pktsz, isocompl, isodesc))) - goto startisomemerr; - if (!(isodesc->buf = vmalloc(isodesc->buflen))) - goto startisomemerr; - up(&ez->mutex); - return 0; + ret = ezusb_resetep(ez->usbdev, ep); + break; + + case EZUSB_SETINTERFACE: + if (copy_from_user(&setintf, (void *)arg, sizeof(setintf))) { + ret = -EFAULT; + break; + } + ret = ezusb_setinterface(ez->usbdev, setintf.interface, setintf.altsetting); + break; - startisomemerr: - if (isodesc->hcisodesc[0]) - usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]); - if (isodesc->hcisodesc[1]) - usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]); - if (isodesc->hcbuf[0]) - kfree(isodesc->hcbuf[0]); - if (isodesc->hcbuf[1]) - kfree(isodesc->hcbuf[1]); - if (isodesc->buf) - vfree(isodesc->buf); - up(&ez->mutex); - return -ENOMEM; + case EZUSB_SETCONFIGURATION: + if (get_user(cfg, (unsigned int *)arg)) { + ret = -EFAULT; + break; + } + ret = ezusb_setconfiguration(ez->usbdev, cfg); + break; - case EZUSB_STOPISO: - get_user_ret(ep, (unsigned int *)arg, -EFAULT); - if ((ep & ~0x80) >= 16) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { + case EZUSB_ASYNCCOMPLETED: + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&ez->wait, &wait); + for (;;) { + if (!ez->usbdev) + break; + if ((as = async_getcompleted(ez))) + break; + if (signal_pending(current)) + break; up(&ez->mutex); - return -EIO; + schedule(); + down(&ez->mutex); } - if (!(isodesc = findiso(ez, ep))) { - up(&ez->mutex); - return -EINVAL; + remove_wait_queue(&ez->wait, &wait); + current->state = TASK_RUNNING; + if (as) { + ret = ezusb_asynccompl(as, (void *)arg); + break; } - list_del(&isodesc->isolist); - usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]); - usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]); - kfree(isodesc->hcbuf[0]); - kfree(isodesc->hcbuf[1]); - vfree(isodesc->buf); - up(&ez->mutex); - return 0; - - case EZUSB_ISODATA: - copy_from_user_ret(&isod, (void *)arg, sizeof(isod), -EFAULT); - if ((isod.ep & ~0x80) >= 16) - return -EINVAL; - if (isod.size) - if (!access_ok((isod.ep & 0x80) ? VERIFY_WRITE : VERIFY_READ, isod.data, isod.size)) - return -EFAULT; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; + if (signal_pending(current)) { + ret = -EINTR; + break; } - if (!(isodesc = findiso(ez, ep))) { - up(&ez->mutex); - return -EINVAL; + ret = -EIO; + break; + + case EZUSB_ASYNCCOMPLETEDNB: + if ((as = async_getcompleted(ez))) { + ret = ezusb_asynccompl(as, (void *)arg); + break; } - if (isod.ep & 0x80) { - cnt = 0; - p1 = isod.data; - while (cnt < isod.size) { - spin_lock_irqsave(&isodesc->lock, flags); - p2 = isodesc->buf + isodesc->rd; - len2 = (isodesc->rd >= isodesc->wr) ? isodesc->buflen : isodesc->wr; - len2 -= isodesc->rd; - spin_unlock_irqrestore(&isodesc->lock, flags); - if (len2 <= 0) - break; - if (len2 >= isod.size - cnt) - len2 = isod.size - cnt; - if (__copy_to_user(p1, p2, len2)) { - up(&ez->mutex); - return -EFAULT; - } - p1 += len2; - cnt += len2; - spin_lock_irqsave(&isodesc->lock, flags); - isodesc->rd = (isodesc->rd + len2) % isodesc->buflen; - spin_unlock_irqrestore(&isodesc->lock, flags); - } - isod.size = cnt; - iso_schedrcv(isodesc); - } else { - cnt = 0; - p1 = isod.data; - while (cnt < isod.size) { - spin_lock_irqsave(&isodesc->lock, flags); - p2 = isodesc->buf + isodesc->wr; - len2 = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen; - if (isodesc->wr + len2 > isodesc->buflen) - len2 = isodesc->buflen - isodesc->wr; - spin_unlock_irqrestore(&isodesc->lock, flags); - if (len2 <= 0) - break; - if (len2 >= isod.size - cnt) - len2 = isod.size - cnt; - if (__copy_from_user(p2, p1, len2)) { - up(&ez->mutex); - return -EFAULT; - } - p1 += len2; - cnt += len2; - spin_lock_irqsave(&isodesc->lock, flags); - isodesc->wr = (isodesc->wr + len2) % isodesc->buflen; - spin_unlock_irqrestore(&isodesc->lock, flags); - } - isod.size = cnt; - iso_schedsnd(isodesc); + ret = -EAGAIN; + break; + + case EZUSB_REQUESTBULK: + if (copy_from_user(&abulk, (void *)arg, sizeof(abulk))) { + ret = -EFAULT; + break; } - spin_lock_irqsave(&isodesc->lock, flags); - isod.bufqueued = (isodesc->buflen + isodesc->wr - isodesc->rd) % isodesc->buflen; - isod.buffree = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen; - spin_unlock_irqrestore(&isodesc->lock, flags); - up(&ez->mutex); - copy_to_user_ret((void *)arg, &isod, sizeof(isod), -EFAULT); - return 0; + ret = ezusb_requestbulk(ez, &abulk); + break; - case EZUSB_PAUSEISO: - get_user_ret(ep, (unsigned int *)arg, -EFAULT); - if ((ep & ~0x80) >= 16) - return -EINVAL; - if (!(isodesc = findiso(ez, ep))) - return -EINVAL; - spin_lock_irqsave(&isodesc->lock, flags); - isodesc->flags &= ~ISOFLG_ACTIVE; - spin_unlock_irqrestore(&isodesc->lock, flags); - return 0; - - case EZUSB_RESUMEISO: - get_user_ret(ep, (unsigned int *)arg, -EFAULT); - if ((ep & ~0x80) >= 16) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; + case EZUSB_REQUESTISO: + if (copy_from_user(&aiso, (void *)arg, sizeof(aiso))) { + ret = -EFAULT; + break; } - if (!(isodesc = findiso(ez, ep))) { - up(&ez->mutex); - return -EINVAL; + ret = ezusb_requestiso(ez, &aiso, ((unsigned char *)arg)+sizeof(aiso)); + break; + + case EZUSB_TERMINATEASYNC: + if (get_user(context, (void **)arg)) { + ret = -EFAULT; + break; } - spin_lock_irqsave(&isodesc->lock, flags); - isodesc->flags |= ISOFLG_ACTIVE; - if (isot.ep & 0x80) - iso_schedrcv(isodesc); - else - iso_schedsnd(isodesc); - spin_unlock_irqrestore(&isodesc->lock, flags); - up(&ez->mutex); - return 0; + ret = ezusb_terminateasync(ez, context); + break; + + case EZUSB_GETFRAMENUMBER: + i = usb_get_current_frame_number(ez->usbdev); + ret = put_user(i, (int *)arg); + break; + + default: + ret = -ENOIOCTLCMD; + break; } - return -ENOIOCTLCMD; + up(&ez->mutex); + return ret; } static struct file_operations ezusb_fops = { @@ -707,12 +940,12 @@ } ez->usbdev = usbdev; usbdev->private = ez; - if (usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue)) { + if (usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue) < 0) { printk(KERN_ERR "ezusb: set_configuration failed\n"); goto err; } interface = &usbdev->config[0].interface[0].altsetting[1]; - if (usb_set_interface(usbdev, 0, 1)) { + if (usb_set_interface(usbdev, 0, 1) < 0) { printk(KERN_ERR "ezusb: set_interface failed\n"); goto err; } @@ -730,20 +963,12 @@ static void ezusb_disconnect(struct usb_device *usbdev) { struct ezusb *ez = (struct ezusb *)usbdev->private; - struct isodesc *isodesc; down(&ez->mutex); - while (!list_empty(&ez->iso)) { - isodesc = list_entry(ez->iso.next, struct isodesc, isolist); - list_del(ez->iso.next); - usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]); - usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]); - kfree(isodesc->hcbuf[0]); - kfree(isodesc->hcbuf[1]); - vfree(isodesc->buf); - } + destroy_all_async(ez); ez->usbdev = NULL; up(&ez->mutex); + wake_up(&ez->wait); usbdev->private = NULL; MOD_DEC_USE_COUNT; } @@ -765,7 +990,10 @@ for (u = 0; u < NREZUSB; u++) { init_MUTEX(&ezusb[u].mutex); ezusb[u].usbdev = NULL; - INIT_LIST_HEAD(&ezusb[u].iso); + INIT_LIST_HEAD(&ezusb[u].async_pending); + INIT_LIST_HEAD(&ezusb[u].async_completed); + init_waitqueue_head(&ezusb[u].wait); + spin_lock_init(&ezusb[u].lock); } /* register misc device */ if (misc_register(&ezusb_misc)) { diff -u --recursive --new-file v2.3.16/linux/drivers/usb/ezusb.h linux/drivers/usb/ezusb.h --- v2.3.16/linux/drivers/usb/ezusb.h Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/ezusb.h Tue Sep 7 10:19:45 1999 @@ -43,45 +43,58 @@ void *data; }; -#define EZUSB_CONTROL _IOWR('E', 0, struct ezusb_ctrltransfer) - struct ezusb_bulktransfer { unsigned int ep; unsigned int len; void *data; }; -#define EZUSB_BULK _IOWR('E', 2, struct ezusb_bulktransfer) - -#define EZUSB_RESETEP _IOR('E', 3, unsigned int) - struct ezusb_setinterface { unsigned int interface; unsigned int altsetting; }; -#define EZUSB_SETINTERFACE _IOR('E', 4, struct ezusb_setinterface) +struct ezusb_isoframestat { + unsigned int length; + unsigned int status; +}; + +struct ezusb_asynccompleted { + int status; + unsigned length; + void *context; + struct ezusb_isoframestat isostat[0]; +}; -struct ezusb_isotransfer { +struct ezusb_asyncbulk { unsigned int ep; - unsigned int pktsz; - unsigned int framesperint; + unsigned int len; + void *context; + void *data; }; -struct ezusb_isodata { +struct ezusb_asynciso { unsigned int ep; - unsigned int size; - unsigned int bufqueued; - unsigned int buffree; + + unsigned int framecnt; + unsigned int startframe; + + void *context; void *data; + struct ezusb_isoframestat isostat[0]; }; -#define EZUSB_STARTISO _IOR('E', 8, struct ezusb_isotransfer) -#define EZUSB_STOPISO _IOR('E', 9, unsigned int) -#define EZUSB_ISODATA _IOWR('E', 10, struct ezusb_isodata) -#define EZUSB_PAUSEISO _IOR('E', 11, unsigned int) -#define EZUSB_RESUMEISO _IOR('E', 12, unsigned int) +#define EZUSB_CONTROL _IOWR('E', 0, struct ezusb_ctrltransfer) +#define EZUSB_BULK _IOWR('E', 2, struct ezusb_bulktransfer) +#define EZUSB_RESETEP _IOR('E', 3, unsigned int) +#define EZUSB_SETINTERFACE _IOR('E', 4, struct ezusb_setinterface) +#define EZUSB_SETCONFIGURATION _IOR('E', 5, unsigned int) +#define EZUSB_ASYNCCOMPLETED _IOW('E', 8, struct ezusb_asynccompleted) +#define EZUSB_ASYNCCOMPLETEDNB _IOW('E', 9, struct ezusb_asynccompleted) +#define EZUSB_REQUESTBULK _IOR('E', 16, struct ezusb_asyncbulk) +#define EZUSB_REQUESTISO _IOR('E', 17, struct ezusb_asynciso) +#define EZUSB_TERMINATEASYNC _IOR('E', 18, void *) +#define EZUSB_GETFRAMENUMBER _IOW('E', 18, unsigned int) /* --------------------------------------------------------------------- */ #endif /* _LINUX_EZUSB_H */ - diff -u --recursive --new-file v2.3.16/linux/drivers/usb/hp_scanner.c linux/drivers/usb/hp_scanner.c --- v2.3.16/linux/drivers/usb/hp_scanner.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hp_scanner.c Wed Sep 1 15:31:47 1999 @@ -0,0 +1,344 @@ +/* -*- linux-c -*- */ + +/* + * Driver for USB HP Scanners + * + * David E. Nelson (dnelson@jump.net) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * 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. + * + * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee). + * + * History + * 0.1 8/31/1999 + * + * Developed/tested using linux-2.3.15 with minor ohci.c changes to + * support short packes during bulk xfer mode. Some testing was + * done with ohci-hcd but the performace was low. Very limited + * testing was performed with uhci but I was unable to get it to + * work. Initial relase to the linux-usb development effort. + * + * */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usb.h" + +/* stall/wait timeout for scanner */ +#define NAK_TIMEOUT (HZ) + +/* For some reason, an IBUF_SIZE of 8192 causes REALLY big problems + * with linux-2.3.15. Anything more than 4k seems to not have an + * effect on increasing performance. Anything smaller than 4k hurts + * it. */ +#define IBUF_SIZE 4096 + +/* This is a scanner, so not much data is sent to it. The largest + * stuff may be some kind of maps and stuff but that's kinda rare. */ +#define OBUF_SIZE 128 + +#define USB_SCANNER_MAJOR 16 + +struct hpscan_usb_data { + struct usb_device *hpscan_dev; /* init: probe_scanner */ + __u8 isopen; /* nz if open */ + + __u8 present; /* Device is present on the bus */ + char *obuf; /* transfer buffers */ + char *ibuf; + wait_queue_head_t wait_q; /* for timeouts */ +}; + +static struct hpscan_usb_data hpscan; + +static int +open_scanner(struct inode * inode, struct file * file) +{ + struct hpscan_usb_data *hps = &hpscan; + + if (hps->isopen) { + return -EBUSY; + } + hps->isopen = 1; + + init_waitqueue_head(&hps->wait_q); + + MOD_INC_USE_COUNT; + + return 0; +} + +static int +close_scanner(struct inode * inode, struct file * file) +{ + struct hpscan_usb_data *hps = &hpscan; + + hps->isopen = 0; + + MOD_DEC_USE_COUNT; + + return 0; +} + +static ssize_t +write_scanner(struct file * file, const char * buffer, + size_t count, loff_t *ppos) +{ + struct hpscan_usb_data *hps = &hpscan; + + unsigned long copy_size; + unsigned long bytes_written = 0; + unsigned long partial; + + int result = 0; + int maxretry; + + do { + unsigned long thistime; + char *obuf = hps->obuf; + + thistime = copy_size = (count > OBUF_SIZE) ? OBUF_SIZE : count; + if (copy_from_user(hps->obuf, buffer, copy_size)) + return -EFAULT; + maxretry = 5; + while (thistime) { + if (!hps->hpscan_dev) + return -ENODEV; + if (signal_pending(current)) { + return bytes_written ? bytes_written : -EINTR; + } + + result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, 2), obuf, thistime, &partial); + + //printk(KERN_DEBUG "write stats: result:%d thistime:%lu partial:%lu\n", result, thistime, partial); + + if (result == USB_ST_TIMEOUT) { /* NAK - so hold for a while */ + if(!maxretry--) { + return -ETIME; + } + interruptible_sleep_on_timeout(&hps->wait_q, NAK_TIMEOUT); + continue; + } else if (!result & partial) { + obuf += partial; + thistime -= partial; + } else + break; + }; + if (result) { + printk("Write Whoops - %x\n", result); + return -EIO; + } + bytes_written += copy_size; + count -= copy_size; + buffer += copy_size; + } while ( count > 0 ); + + return bytes_written ? bytes_written : -EIO; +} + +static ssize_t +read_scanner(struct file * file, char * buffer, + size_t count, loff_t *ppos) +{ + struct hpscan_usb_data *hps = &hpscan; + + ssize_t read_count; + + unsigned long partial; + + int this_read; + int result; + +/* Wait for the scanner to get it's act together. This may involve + * resetting the head, warming up the lamp, etc. maxretry is number + * of seconds. */ + int maxretry = 30; + + char *ibuf = hps->ibuf; + + read_count = 0; + + while (count) { + if (signal_pending(current)) { + return read_count ? read_count : -EINTR; + } + if (!hps->hpscan_dev) + return -ENODEV; + this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count; + + result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, 1), ibuf, this_read, &partial); + + printk(KERN_DEBUG "read stats: result:%d this_read:%u partial:%lu\n", result, this_read, partial); + + if (partial) { + count = this_read = partial; + } else if (result == USB_ST_TIMEOUT || result == 15) { + if(!maxretry--) { + printk(KERN_DEBUG "read_scanner: maxretry timeout\n"); + return -ETIME; + } + interruptible_sleep_on_timeout(&hps->wait_q, NAK_TIMEOUT); + continue; + } else if (result != USB_ST_DATAUNDERRUN) { + printk("Read Whoops - result:%u partial:%lu this_read:%u\n", result, partial, this_read); + return -EIO; + } else { + return (0); + } + + if (this_read) { + if (copy_to_user(buffer, ibuf, this_read)) + return -EFAULT; + count -= this_read; + read_count += this_read; + buffer += this_read; + } + } + return read_count; +} + +static int +probe_scanner(struct usb_device *dev) +{ + struct hpscan_usb_data *hps = &hpscan; + + /* + * Don't bother using an HP 4200C since it does NOT understand + * SCL and HP isn't going to be releasing the specs any time + * soon. */ + if (dev->descriptor.idVendor != 0x3f0 ) { + printk(KERN_INFO "Scanner is not an HP Scanner.\n"); + return -1; + } + + if (dev->descriptor.idProduct != 0x101 && /* HP 4100C */ + dev->descriptor.idProduct != 0x202 && /* HP 5100C */ + dev->descriptor.idProduct != 0x601) { /* HP 6300C */ + printk(KERN_INFO "Scanner model not supported/tested.\n"); + return -1; + } + + printk(KERN_DEBUG "USB Scanner found at address %d\n", dev->devnum); + + if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { + printk(KERN_DEBUG "Failed to set configuration\n"); + return -1; + } + + hps->present = 1; + hps->hpscan_dev = dev; + + if (!(hps->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) { + return -ENOMEM; + } + + if (!(hps->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) { + return -ENOMEM; + } + + return 0; +} + +static void +disconnect_scanner(struct usb_device *dev) +{ + struct hpscan_usb_data *hps = &hpscan; + + if (hps->isopen) { + /* better let it finish - the release will do whats needed */ + hps->hpscan_dev = NULL; + return; + } + kfree(hps->ibuf); + kfree(hps->obuf); + + dev->private = NULL; /* just in case */ + hps->present = 0; +} + +static struct +usb_driver scanner_driver = { + "usbscanner", + probe_scanner, + disconnect_scanner, + { NULL, NULL } +}; + +static struct +file_operations usb_scanner_fops = { + NULL, /* seek */ + read_scanner, + write_scanner, + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + open_scanner, + NULL, /* flush */ + close_scanner, + NULL, + NULL, /* fasync */ +}; + +int +usb_hp_scanner_init(void) +{ + int result; + + if ((result = register_chrdev(USB_SCANNER_MAJOR, "usbscanner", &usb_scanner_fops)) < 0) { + printk(KERN_WARNING "hp_scanner: Cannot register device\n"); + return result; + } + usb_register(&scanner_driver); + printk(KERN_DEBUG "USB Scanner support registered.\n"); + return 0; +} + + +void +usb_hp_scanner_cleanup(void) +{ + struct hpscan_usb_data *hps = &hpscan; + + hps->present = 0; + usb_deregister(&scanner_driver); + unregister_chrdev(USB_SCANNER_MAJOR, "usbscanner"); +} + +#ifdef MODULE + +int +init_module(void) +{ + return usb_hp_scanner_init(); +} + +void +cleanup_module(void) +{ + usb_hp_scanner_cleanup(); +} +#endif + diff -u --recursive --new-file v2.3.16/linux/drivers/usb/inits.h linux/drivers/usb/inits.h --- v2.3.16/linux/drivers/usb/inits.h Tue Jul 27 16:05:50 1999 +++ linux/drivers/usb/inits.h Wed Sep 1 16:24:19 1999 @@ -5,5 +5,6 @@ int usb_printer_init(void); void usb_hub_cleanup(void); void usb_mouse_cleanup(void); +int usb_scsi_init(void); int proc_usb_init (void); void proc_usb_cleanup (void); diff -u --recursive --new-file v2.3.16/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c --- v2.3.16/linux/drivers/usb/mouse.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/mouse.c Wed Sep 1 16:24:19 1999 @@ -4,6 +4,12 @@ * * Brad Keryan 4/3/1999 * + * version 0.30? Paul Ashton 1999/08/19 - Fixed behaviour on mouse + * disconnect and suspend/resume. Added module parameter "force=1" + * to allow opening of the mouse driver before mouse has been plugged + * in (enables consistent XF86Config settings). Fixed module use count. + * Documented missing blocking/non-blocking read handling (not fixed). + * * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it * correctly. Events are added together, not queued, to keep the rodent sober. * @@ -49,6 +55,7 @@ int present; /* this mouse is plugged in */ int active; /* someone is has this mouse's device open */ int ready; /* the mouse has changed state since the last read */ + int suspended; /* mouse disconnected */ wait_queue_head_t wait; /* for polling */ struct fasync_struct *fasync; /* later, add a list here to support multiple mice */ @@ -65,12 +72,38 @@ spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED; +static int force=0; /* allow the USB mouse to be opened even if not there (yet) */ +MODULE_PARM(force,"i"); + static int mouse_irq(int state, void *__buffer, int len, void *dev_id) { signed char *data = __buffer; /* finding the mouse is easy when there's only one */ struct mouse_state *mouse = &static_mouse_state; + if (state) + printk(KERN_DEBUG "%s(%d):state %d, bp %p, len %d, dp %p\n", + __FILE__, __LINE__, state, __buffer, len, dev_id); + + /* + * USB_ST_NOERROR is the normal case. + * USB_ST_REMOVED occurs if mouse disconnected or suspend/resume + * USB_ST_INTERNALERROR occurs if system suspended then mouse removed + * followed by resume. On UHCI could then occur every second + * In both cases, suspend the mouse + * On other states, ignore + */ + switch (state) { + case USB_ST_REMOVED: + case USB_ST_INTERNALERROR: + printk(KERN_DEBUG "%s(%d): Suspending\n", + __FILE__, __LINE__); + mouse->suspended = 1; + return 0; /* disable */ + case USB_ST_NOERROR: break; + default: return 1; /* ignore */ + } + /* if a mouse moves with no one listening, do we care? no */ if(!mouse->active) return 1; @@ -110,9 +143,11 @@ fasync_mouse(-1, file, 0); + printk(KERN_DEBUG "%s(%d): MOD_DEC\n", __FILE__, __LINE__); MOD_DEC_USE_COUNT; if (--mouse->active == 0) { + mouse->suspended = 0; /* stop polling the mouse while its not in use */ usb_release_irq(mouse->dev, mouse->irq_handle); /* never keep a reference to a released IRQ! */ @@ -126,15 +161,38 @@ { struct mouse_state *mouse = &static_mouse_state; + printk(KERN_DEBUG "%s(%d): open_mouse\n", __FILE__, __LINE__); + /* + * First open may fail since mouse_probe() may get called after this + * if module load is in response to the open + * mouse_probe() sets mouse->present. This open can be delayed by + * specifying force=1 in module load + * This helps if you want to insert the USB mouse after starting X + */ if (!mouse->present) - return -EINVAL; + { + if (force) /* always load the driver even if no mouse (yet) */ + { + printk(KERN_DEBUG "%s(%d): forced open\n", + __FILE__, __LINE__); + mouse->suspended = 1; + } + else + return -EINVAL; + } + + /* prevent the driver from being unloaded while its in use */ + printk(KERN_DEBUG "%s(%d): MOD_INC\n", __FILE__, __LINE__); + /* Increment use count even if already active */ + MOD_INC_USE_COUNT; + if (mouse->active++) return 0; /* flush state */ mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0; - /* prevent the driver from being unloaded while its in use */ - MOD_INC_USE_COUNT; + if (!mouse->present) /* only get here if force == 1 */ + return 0; /* start the usb controller's polling of the mouse */ mouse->irq_handle = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), mouse_irq, mouse->bInterval, NULL); @@ -160,6 +218,10 @@ static int state = 0; struct mouse_state *mouse = &static_mouse_state; + /* + * FIXME - Other mouse drivers handle blocking and nonblocking reads + * differently here... + */ if (count) { mouse->ready = 0; switch (state) { @@ -304,6 +366,19 @@ mouse->bInterval = endpoint->bInterval; mouse->present = 1; + + /* This appears to let USB mouse survive disconnection and */ + /* APM suspend/resume */ + if (mouse->suspended) + { + printk(KERN_DEBUG "%s(%d): mouse resume\n", __FILE__, __LINE__); + /* restart the usb controller's polling of the mouse */ + mouse->irq_handle = usb_request_irq(mouse->dev, + usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), + mouse_irq, mouse->bInterval, NULL); + mouse->suspended = 0; + } + return 0; } @@ -315,7 +390,6 @@ if (mouse->present) { usb_release_irq(mouse->dev, mouse->irq_handle); /* never keep a reference to a released IRQ! */ - mouse->irq_handle = NULL; } mouse->irq_handle = NULL; @@ -336,7 +410,7 @@ { struct mouse_state *mouse = &static_mouse_state; - mouse->present = mouse->active = 0; + mouse->present = mouse->active = mouse->suspended = 0; mouse->irq_handle = NULL; init_waitqueue_head(&mouse->wait); mouse->fasync = NULL; diff -u --recursive --new-file v2.3.16/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c --- v2.3.16/linux/drivers/usb/ohci.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/ohci.c Wed Sep 1 15:31:47 1999 @@ -1455,7 +1455,7 @@ return ohci_generic_trans(usb_dev, pipe, TOGGLE_AUTO, - 1 /* round */, 1 /* autofree */, + 0 /* round */, 1 /* autofree */, dev_id, handler, data, len, HCD_ED_BULK, NULL /* no setup_td */, NULL /* no status_td */ ); @@ -1504,7 +1504,7 @@ #endif /* only count TDs that were completed successfully */ - if (stats == USB_ST_NOERROR) + if (stats == USB_ST_NOERROR || stats == USB_ST_DATAUNDERRUN) /*DEN*/ req->_bytes_done += len; #ifdef OHCI_DEBUG diff -u --recursive --new-file v2.3.16/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.16/linux/drivers/usb/uhci.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/usb/uhci.c Thu Sep 2 10:22:08 1999 @@ -23,6 +23,12 @@ /* 4/4/1999 added data toggle for interrupt pipes -keryan */ /* 5/16/1999 added global toggles for bulk and control */ /* 6/25/1999 added fix for data toggles on bidirectional bulk endpoints */ +/* + * 1999-09-02: Thomas Sailer + * Added explicit frame list manipulation routines + * for inserting/removing iso td's to/from the frame list. + * START_ABSOLUTE fixes + */ #include #include @@ -463,6 +469,84 @@ } /* + * frame list manipulation. Used for Isochronous transfers. + * the list of (iso) TD's enqueued in a frame list entry + * is basically a doubly linked list with link being + * the forward pointer and backptr the backward ptr. + * the frame list entry itself doesn't have a back ptr + * (therefore the list is not circular), and the forward pointer + * stops at link entries having the UHCI_PTR_TERM or the UHCI_PTR_QH + * bit set. Maybe it could be extended to handle the QH's also, + * but it doesn't seem necessary right now. + * The layout looks as follows: + * frame list pointer -> iso td's (if any) -> + * periodic interrupt td (if framelist 0) -> irq qh -> control qh -> bulk qh + */ + +static spinlock_t framelist_lock = SPIN_LOCK_UNLOCKED; + +static void uhci_add_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum) +{ + unsigned long flags; + struct uhci_td *nexttd; + + framenum %= UHCI_NUMFRAMES; + spin_lock_irqsave(&framelist_lock, flags); + td->backptr = &uhci->fl->frame[framenum]; + td->link = uhci->fl->frame[framenum]; + if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) { + nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15); + nexttd->backptr = &td->link; + } + wmb(); + uhci->fl->frame[framenum] = virt_to_bus(td); + spin_unlock_irqrestore(&framelist_lock, flags); +} + +static void uhci_remove_frame_list(struct uhci *uhci, struct uhci_td *td) +{ + unsigned long flags; + struct uhci_td *nexttd; + + if (!td->backptr) + return; + spin_lock_irqsave(&framelist_lock, flags); + *(td->backptr) = td->link; + if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) { + nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15); + nexttd->backptr = td->backptr; + } + spin_unlock_irqrestore(&framelist_lock, flags); + td->backptr = NULL; + /* + * attention: td->link might still be in use by the + * hardware if the td is still active and the hardware + * was processing it. So td->link should be preserved + * until the frame number changes. Don't know what to do... + * udelay(1000) doesn't sound nice, and schedule() + * can't be used as this is called from within interrupt context. + */ + /* for now warn if there's a possible problem */ + if (td->status & TD_CTRL_ACTIVE) { + unsigned frn = inw(uhci->io_addr + USBFRNUM); + __u32 link = uhci->fl->frame[frn % UHCI_NUMFRAMES]; + if (!(link & (UHCI_PTR_TERM | UHCI_PTR_QH))) { + struct uhci_td *tdl = (struct uhci_td *)bus_to_virt(link & ~15); + for (;;) { + if (tdl == td) { + printk(KERN_WARNING "uhci_remove_frame_list: td possibly still in use!!\n"); + break; + } + if (tdl->link & (UHCI_PTR_TERM | UHCI_PTR_QH)) + break; + tdl = (struct uhci_td *)bus_to_virt(tdl->link & ~15); + } + } + } +} + + +/* * This function removes and disallocates all structures set up for a transfer. * It takes the qh out of the skeleton, removes the tq and the td's. * It only removes the associated interrupt handler if removeirq is set. @@ -619,6 +703,7 @@ struct usb_isoc_desc **isocdesc) { struct usb_isoc_desc *id; + int i; #ifdef BANDWIDTH_ALLOCATION /* TBD: add bandwidth allocation/checking/management HERE. */ @@ -628,7 +713,7 @@ *isocdesc = NULL; /* Check some parameters. */ - if ((frame_count < 0) || (frame_count > UHCI_NUMFRAMES)) { + if ((frame_count <= 0) || (frame_count > UHCI_NUMFRAMES)) { #ifdef CONFIG_USB_DEBUG_ISOC printk (KERN_DEBUG "uhci_init_isoc: invalid frame_count (%d)\n", frame_count); @@ -648,16 +733,20 @@ if (!id) return -ENOMEM; + memset (id, 0, sizeof (*id) + + (sizeof (struct isoc_frame_desc) * frame_count)); + id->td = kmalloc (sizeof (struct uhci_td) * frame_count, GFP_KERNEL); if (!id->td) { kfree (id); return -ENOMEM; } - memset (id, 0, sizeof (*id) + - (sizeof (struct isoc_frame_desc) * frame_count)); memset (id->td, 0, sizeof (struct uhci_td) * frame_count); + for (i = 0; i < frame_count; i++) + INIT_LIST_HEAD(&((struct uhci_td *)(id->td))[i].irq_list); + id->frame_count = frame_count; id->frame_size = usb_maxpacket (usb_dev, pipe, usb_pipeout(pipe)); /* TBD: or make this a parameter to allow for frame_size @@ -755,7 +844,7 @@ cur_frame = uhci_get_current_frame_number (isocdesc->usb_dev); /* if not START_ASAP (i.e., RELATIVE or ABSOLUTE): */ - if (!pr_isocdesc) + if (!pr_isocdesc) { if (isocdesc->start_type == START_RELATIVE) { if ((isocdesc->start_frame < 0) || (isocdesc->start_frame > CAN_SCHEDULE_FRAMES)) { #ifdef CONFIG_USB_DEBUG_ISOC @@ -766,9 +855,10 @@ } } /* end START_RELATIVE */ else - if (isocdesc->start_type == START_ABSOLUTE) { - if (isocdesc->start_frame > cur_frame) { - if ((isocdesc->start_frame - cur_frame) > CAN_SCHEDULE_FRAMES) { + if (isocdesc->start_type == START_ABSOLUTE) { /* within the scope of cur_frame */ + ix = USB_WRAP_FRAMENR(isocdesc->start_frame - cur_frame); + if (ix < START_FRAME_FUDGE || /* too small */ + ix > CAN_SCHEDULE_FRAMES) { /* too large */ #ifdef CONFIG_USB_DEBUG_ISOC printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n", isocdesc->start_frame); @@ -787,6 +877,7 @@ } } } /* end START_ABSOLUTE */ + } /* * Set the start/end frame numbers. @@ -800,16 +891,14 @@ } else if (isocdesc->start_type == START_ASAP) { isocdesc->start_frame = cur_frame + START_FRAME_FUDGE; } - /* else for start_type == START_ABSOLUTE, use start_frame as is. */ /* and see if start_frame needs any correction */ - if (isocdesc->start_frame >= UHCI_NUMFRAMES) - isocdesc->start_frame -= UHCI_NUMFRAMES; + /* only wrap to USB frame numbers, the frame_list insertion routine + takes care of the wrapping to the frame_list size */ + isocdesc->start_frame = USB_WRAP_FRAMENR(isocdesc->start_frame); /* and fix the end_frame value */ - isocdesc->end_frame = isocdesc->start_frame + isocdesc->frame_count - 1; - if (isocdesc->end_frame >= UHCI_NUMFRAMES) - isocdesc->end_frame -= UHCI_NUMFRAMES; + isocdesc->end_frame = USB_WRAP_FRAMENR(isocdesc->start_frame + isocdesc->frame_count - 1); isocdesc->prev_completed_frame = -1; isocdesc->cur_completed_frame = -1; @@ -857,6 +946,7 @@ td->status |= TD_CTRL_IOC; td->completed = isocdesc->callback_fn; cb_frames = 0; + uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context); } bufptr += fd->frame_length; /* or isocdesc->frame_size; */ @@ -864,21 +954,20 @@ /* * Insert the TD in the frame list. */ - td->backptr = &uhci->fl->frame [cur_frame]; - td->link = uhci->fl->frame [cur_frame]; - uhci->fl->frame [cur_frame] = virt_to_bus (td); + uhci_add_frame_list(uhci, td, cur_frame); - if (++cur_frame >= UHCI_NUMFRAMES) - cur_frame = 0; + cur_frame = USB_WRAP_FRAMENR(cur_frame+1); } /* end for ix */ /* * Add IOC on the last TD. */ td--; - td->status |= TD_CTRL_IOC; - uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */ - + if (!(td->status & TD_CTRL_IOC)) { + td->status |= TD_CTRL_IOC; + td->completed = isocdesc->callback_fn; + uhci_add_irq_list(dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */ + } return 0; } /* end uhci_run_isoc */ @@ -897,9 +986,9 @@ struct uhci_device *dev = usb_to_uhci (isocdesc->usb_dev); struct uhci *uhci = dev->uhci; struct uhci_td *td; - int ix, cur_frame; + int ix; - if ((isocdesc->start_frame < 0) || (isocdesc->start_frame >= UHCI_NUMFRAMES)) { + if (USB_WRAP_FRAMENR(isocdesc->start_frame) != isocdesc->start_frame) { #ifdef CONFIG_USB_DEBUG_ISOC printk (KERN_DEBUG "uhci_kill_isoc: invalid start_frame (%d)\n", isocdesc->start_frame); @@ -907,13 +996,9 @@ return -EINVAL; } - for (ix = 0, td = isocdesc->td, cur_frame = isocdesc->start_frame; - ix < isocdesc->frame_count; ix++, td++) { + for (ix = 0, td = isocdesc->td; ix < isocdesc->frame_count; ix++, td++) { + uhci_remove_frame_list(uhci, td); td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC); - uhci->fl->frame [cur_frame] = td->link; - - if (++cur_frame >= UHCI_NUMFRAMES) - cur_frame = 0; } /* end for ix */ isocdesc->start_frame = -1; @@ -922,18 +1007,21 @@ static void uhci_free_isoc (struct usb_isoc_desc *isocdesc) { + int i; + /* If still Active, kill it. */ if (isocdesc->start_frame >= 0) - uhci_kill_isoc (isocdesc); + uhci_kill_isoc(isocdesc); - /* Remove it from the IRQ list. */ - uhci_remove_irq_list ((struct uhci_td *)&(isocdesc->td [isocdesc->frame_count - 1])); + /* Remove all td's from the IRQ list. */ + for(i = 0; i < isocdesc->frame_count; i++) + uhci_remove_irq_list(((struct uhci_td *)(isocdesc->td))+i); /* Free the associate memory. */ if (isocdesc->td) - kfree (isocdesc->td); + kfree(isocdesc->td); - kfree (isocdesc); + kfree(isocdesc); } /* end uhci_free_isoc */ /* @@ -1512,7 +1600,7 @@ td, isocdesc, first_comp, cur_comp, num_comp); #endif - for (ix = 0, fx = first_comp, prtd = &isocdesc->td [first_comp], frm = &isocdesc->frames [first_comp]; + for (ix = 0, fx = first_comp, prtd = ((struct uhci_td *)(isocdesc->td))+first_comp, frm = &isocdesc->frames [first_comp]; ix < num_comp; ix++) { frm->frame_length = uhci_actual_length (prtd->status); isocdesc->total_length += frm->frame_length; @@ -1666,6 +1754,7 @@ /* Don't clobber the frame */ td->link = uhci->fl->frame[0]; + td->backptr = &uhci->fl->frame[0]; td->status = TD_CTRL_IOC; td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN; /* (ignored) input packet, 16 bytes, device 127 */ td->buffer = 0; diff -u --recursive --new-file v2.3.16/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c --- v2.3.16/linux/drivers/usb/usb-core.c Tue Jul 27 16:05:50 1999 +++ linux/drivers/usb/usb-core.c Wed Sep 1 15:31:47 1999 @@ -44,6 +44,9 @@ # ifdef CONFIG_USB_MOUSE usb_mouse_init(); # endif +# ifdef CONFIG_USB_HP_SCANNER + usb_hp_scanner_init(); +# endif # ifdef CONFIG_USB_KBD usb_kbd_init(); # endif @@ -86,6 +89,9 @@ # ifdef CONFIG_USB_MOUSE usb_mouse_cleanup(); # endif +# ifdef CONFIG_USB_HP_SCANNER + usb_hp_scanner_cleanup(); +# endif #endif } diff -u --recursive --new-file v2.3.16/linux/drivers/usb/usb.h linux/drivers/usb/usb.h --- v2.3.16/linux/drivers/usb/usb.h Tue Aug 31 17:29:14 1999 +++ linux/drivers/usb/usb.h Tue Sep 7 10:19:45 1999 @@ -121,7 +121,7 @@ void *data; }; -#define USB_PROC_CONTROL _IOWR('U', 0, struct usb_proc_ctrltransfer) +#define USB_PROC_CONTROL _IOWR('U', 0, struct usb_proc_ctrltransfer) struct usb_proc_bulktransfer { unsigned int ep; @@ -129,16 +129,18 @@ void *data; }; -#define USB_PROC_BULK _IOWR('U', 2, struct usb_proc_bulktransfer) +#define USB_PROC_BULK _IOWR('U', 2, struct usb_proc_bulktransfer) -#define USB_PROC_RESETEP _IOR('U', 3, unsigned int) +#define USB_PROC_RESETEP _IOR('U', 3, unsigned int) struct usb_proc_setinterface { unsigned int interface; unsigned int altsetting; }; -#define USB_PROC_SETINTERFACE _IOR('U', 4, struct usb_proc_setinterface) +#define USB_PROC_SETINTERFACE _IOR('U', 4, struct usb_proc_setinterface) + +#define USB_PROC_SETCONFIGURATION _IOR('U', 5, unsigned int) @@ -349,6 +351,8 @@ */ #define START_FRAME_FUDGE 3 +#define USB_WRAP_FRAMENR(x) ((x) & 2047) + /* for start_type: */ enum { START_ASAP = 0, @@ -527,13 +531,6 @@ extern void usb_disconnect(struct usb_device **); extern void usb_destroy_configuration(struct usb_device *dev); - -extern void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, - int maxsze, usb_device_irq completed, void *dev_id); -extern void usb_delete_isochronous (struct usb_device *dev, void *_isodesc); -extern int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc); -extern int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc); -extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc); int usb_get_current_frame_number (struct usb_device *usb_dev); diff -u --recursive --new-file v2.3.16/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c --- v2.3.16/linux/drivers/usb/usb_scsi.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/usb/usb_scsi.c Wed Sep 1 16:26:26 1999 @@ -92,6 +92,7 @@ int ip_wanted; /* needed */ int pid; /* control thread */ struct semaphore *notify; /* wait for thread to begin */ + void *irq_handle; /* for USB interrupt requests */ }; /* @@ -374,6 +375,7 @@ __u8 status[2]; devrequest dr; int retry = 5; + void *irq_handle; US_DEBUGP("pop_CB_status, proto=%x\n", us->protocol); switch (us->protocol) { @@ -409,13 +411,15 @@ /* add interrupt transfer, marked for removal */ us->ip_wanted = 1; - result = us->pusb_dev->bus->op->request_irq(us->pusb_dev, + irq_handle = us->pusb_dev->bus->op->request_irq(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev, us->ep_int), pop_CBI_irq, 0, (void *)us); - if (result) { - US_DEBUGP("No interrupt for CBI %x\n", result); + if (!irq_handle) { + US_DEBUGP("No interrupt for CBI\n"); return DID_ABORT << 16; } + us->irq_handle = irq_handle; + sleep_on(&us->ip_waitq); if (us->ip_wanted) { US_DEBUGP("Did not get interrupt on CBI\n"); @@ -647,13 +651,17 @@ struct us_data *us = (struct us_data *)psh->hostdata[0]; struct us_data *prev = (struct us_data *)&us_list; + if (us->irq_handle) { + usb_release_irq(us->pusb_dev, us->irq_handle); + us->irq_handle = NULL; + } if (us->filter) us->filter->release(us->fdata); if (us->pusb_dev) usb_deregister(&scsi_driver); /* FIXME - leaves hanging host template copy */ - /* (bacause scsi layer uses it after removal !!!) */ + /* (because scsi layer uses it after removal !!!) */ while(prev->next != us) prev = prev->next; prev->next = us->next; @@ -1280,6 +1288,7 @@ dev->descriptor.idProduct == 0x0001) { devrequest dr; __u8 qstat[2]; + void *irq_handle; /* shuttle E-USB */ dr.requesttype = 0xC0; @@ -1290,9 +1299,12 @@ ss->pusb_dev->bus->op->control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), &dr, qstat, 2); US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]); init_waitqueue_head(&ss->ip_waitq); - ss->pusb_dev->bus->op->request_irq(ss->pusb_dev, + irq_handle = ss->pusb_dev->bus->op->request_irq(ss->pusb_dev, usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int), pop_CBI_irq, 0, (void *)ss); + if (!irq_handle) + return -1; + ss->irq_handle = irq_handle; interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*5); } else if (ss->protocol == US_PR_CBI) diff -u --recursive --new-file v2.3.16/linux/fs/Config.in linux/fs/Config.in --- v2.3.16/linux/fs/Config.in Thu Aug 12 12:26:06 1999 +++ linux/fs/Config.in Sat Sep 4 12:42:30 1999 @@ -31,6 +31,11 @@ define_bool CONFIG_JOLIET n fi +tristate 'UDF filesystem support' CONFIG_UDF_FS +if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' UDF read-write support (EXPERIMENTAL)' CONFIG_UDF_RW +fi + tristate 'Minix fs support' CONFIG_MINIX_FS tristate 'NTFS filesystem support (read only)' CONFIG_NTFS_FS if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -71,11 +76,10 @@ if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then bool ' Root file system on NFS' CONFIG_ROOT_NFS fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'NFS server support' CONFIG_NFSD - if [ "$CONFIG_NFSD" != "n" ]; then - bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN - fi + # considering that RedHat-6.0 ships with this on, I guess it's not really experimental + tristate 'NFS server support' CONFIG_NFSD + if [ "$CONFIG_NFSD" != "n" ]; then + bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN fi if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then define_bool CONFIG_SUNRPC y diff -u --recursive --new-file v2.3.16/linux/fs/Makefile linux/fs/Makefile --- v2.3.16/linux/fs/Makefile Thu Aug 12 12:26:06 1999 +++ linux/fs/Makefile Sat Sep 4 12:42:30 1999 @@ -18,7 +18,7 @@ MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \ - nfsd nls devpts adfs partitions qnx4 + nfsd nls devpts adfs partitions qnx4 udf SUB_DIRS := partitions @@ -222,6 +222,14 @@ else ifeq ($(CONFIG_QNX4FS_FS),m) MOD_SUB_DIRS += qnx4 + endif +endif + +ifeq ($(CONFIG_UDF_FS),y) +SUB_DIRS += udf +else + ifeq ($(CONFIG_UDF_FS),m) + MOD_SUB_DIRS += udf endif endif diff -u --recursive --new-file v2.3.16/linux/fs/buffer.c linux/fs/buffer.c --- v2.3.16/linux/fs/buffer.c Tue Aug 31 17:29:14 1999 +++ linux/fs/buffer.c Fri Sep 3 10:29:38 1999 @@ -898,19 +898,21 @@ */ void __bforget(struct buffer_head * buf) { + /* grab the lru lock here to block bdflush. */ spin_lock(&lru_list_lock); write_lock(&hash_table_lock); - if (atomic_read(&buf->b_count) != 1 || buffer_locked(buf)) { - touch_buffer(buf); - atomic_dec(&buf->b_count); - } else { - atomic_set(&buf->b_count, 0); - buf->b_state = 0; - if (buf->b_pprev) - __hash_unlink(buf); - __remove_from_lru_list(buf, buf->b_list); - put_last_free(buf); - } + if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf)) + goto in_use; + if (buf->b_pprev) + __hash_unlink(buf); + write_unlock(&hash_table_lock); + __remove_from_lru_list(buf, buf->b_list); + spin_unlock(&lru_list_lock); + buf->b_state = 0; + put_last_free(buf); + return; + + in_use: write_unlock(&hash_table_lock); spin_unlock(&lru_list_lock); } @@ -1231,16 +1233,12 @@ */ if (offset <= curr_off) { if (buffer_mapped(bh)) { - atomic_inc(&bh->b_count); - wait_on_buffer(bh); - if (bh->b_dev == B_FREE) - BUG(); mark_buffer_clean(bh); + wait_on_buffer(bh); clear_bit(BH_Uptodate, &bh->b_state); clear_bit(BH_Mapped, &bh->b_state); clear_bit(BH_Req, &bh->b_state); bh->b_blocknr = 0; - atomic_dec(&bh->b_count); } } curr_off = next_off; @@ -1258,8 +1256,7 @@ * instead. */ if (!offset) { - if (!try_to_free_buffers(page)) - { + if (!try_to_free_buffers(page)) { atomic_add(PAGE_CACHE_SIZE, &buffermem); return 0; } diff -u --recursive --new-file v2.3.16/linux/fs/exec.c linux/fs/exec.c --- v2.3.16/linux/fs/exec.c Thu Aug 26 13:05:40 1999 +++ linux/fs/exec.c Tue Sep 7 10:57:20 1999 @@ -274,7 +274,7 @@ mpnt->vm_ops = NULL; mpnt->vm_offset = 0; mpnt->vm_file = NULL; - mpnt->vm_pte = 0; + mpnt->vm_private_data = NULL; insert_vm_struct(current->mm, mpnt); current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } diff -u --recursive --new-file v2.3.16/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.3.16/linux/fs/ext2/inode.c Thu Aug 26 13:05:40 1999 +++ linux/fs/ext2/inode.c Fri Sep 3 10:24:35 1999 @@ -856,10 +856,11 @@ unsigned int flags; retval = -EPERM; - if ((iattr->ia_attr_flags & - (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^ - (inode->u.ext2_i.i_flags & - (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) { + if (iattr->ia_valid & ATTR_ATTR_FLAG && + ((!(iattr->ia_attr_flags & ATTR_FLAG_APPEND) != + !(inode->u.ext2_i.i_flags & EXT2_APPEND_FL)) || + (!(iattr->ia_attr_flags & ATTR_FLAG_IMMUTABLE) != + !(inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)))) { if (!capable(CAP_LINUX_IMMUTABLE)) goto out; } else if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) diff -u --recursive --new-file v2.3.16/linux/fs/filesystems.c linux/fs/filesystems.c --- v2.3.16/linux/fs/filesystems.c Thu May 13 23:50:15 1999 +++ linux/fs/filesystems.c Sat Sep 4 12:42:30 1999 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -148,6 +149,10 @@ #ifdef CONFIG_QNX4FS_FS init_qnx4_fs(); +#endif + +#ifdef CONFIG_UDF_FS + init_udf_fs(); #endif #ifdef CONFIG_NLS diff -u --recursive --new-file v2.3.16/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c --- v2.3.16/linux/fs/ncpfs/sock.c Tue Aug 31 17:29:14 1999 +++ linux/fs/ncpfs/sock.c Fri Sep 3 12:45:30 1999 @@ -176,7 +176,7 @@ instructions adding the wait_table waitqueues in the waitqueue-head before going to calculate the mask-retval. */ __set_current_state(TASK_INTERRUPTIBLE); - if (!(file->f_op->poll(file, &wait_table) & POLLIN)) { + if (!(sock->ops->poll(file, sock, &wait_table) & POLLIN)) { int timed_out; if (timeout > max_timeout) { /* JEJB/JSP 2/7/94 diff -u --recursive --new-file v2.3.16/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.3.16/linux/fs/nfsd/vfs.c Mon Jul 5 20:34:31 1999 +++ linux/fs/nfsd/vfs.c Thu Sep 2 10:18:33 1999 @@ -995,12 +995,15 @@ * that the parent is still our parent and * that we are still hashed onto it.. * - * This is requied in case two processes race + * This is required in case two processes race * on removing (or moving) the same entry: the * parent lock will serialize them, but the * other process will be too late.. + * + * Note that this nfsd_check_parent is different + * than the one in linux/include/dcache_func.h. */ -#define check_parent(dir, dentry) \ +#define nfsd_check_parent(dir, dentry) \ ((dir) == (dentry)->d_parent->d_inode && !list_empty(&dentry->d_hash)) /* @@ -1079,8 +1082,8 @@ nfsd_double_down(&tdir->i_sem, &fdir->i_sem); err = -ENOENT; /* GAM3 check for parent changes after locking. */ - if (check_parent(fdir, odentry) && - check_parent(tdir, ndentry)) { + if (nfsd_check_parent(fdir, odentry) && + nfsd_check_parent(tdir, ndentry)) { err = vfs_rename(fdir, odentry, tdir, ndentry); if (!err && EX_ISSYNC(tfhp->fh_export)) { @@ -1168,7 +1171,7 @@ fhp->fh_locked = 1; err = -ENOENT; - if (check_parent(dirp, rdentry)) + if (nfsd_check_parent(dirp, rdentry)) err = vfs_rmdir(dirp, rdentry); rdentry->d_count--; diff -u --recursive --new-file v2.3.16/linux/fs/partitions/Config.in linux/fs/partitions/Config.in --- v2.3.16/linux/fs/partitions/Config.in Tue Aug 31 17:29:14 1999 +++ linux/fs/partitions/Config.in Sat Sep 4 13:09:36 1999 @@ -13,7 +13,10 @@ if [ "$ARCH" = "ppc" -o "$CONFIG_MAC" = "y" ]; then define_bool CONFIG_MAC_PARTITION y fi - define_bool CONFIG_MSDOS_PARTITION y + if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \ + "$CONFIG_MAC" != "y" ]; then + define_bool CONFIG_MSDOS_PARTITION y + fi fi if [ "$CONFIG_MSDOS_PARTITION" = "y" ]; then bool ' BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL diff -u --recursive --new-file v2.3.16/linux/fs/partitions/atari.c linux/fs/partitions/atari.c --- v2.3.16/linux/fs/partitions/atari.c Thu Aug 12 12:26:06 1999 +++ linux/fs/partitions/atari.c Sat Sep 4 13:09:36 1999 @@ -13,7 +13,9 @@ #include #include #include +#include +#include #include #include "check.h" @@ -23,6 +25,14 @@ */ #define ICD_PARTS +/* check if a partition entry looks valid -- Atari format is assumed if at + least one of the primary entries is ok this way */ +#define VALID_PARTITION(pi,hdsiz) \ + (((pi)->flg & 1) && \ + isalnum((pi)->id[0]) && isalnum((pi)->id[1]) && isalnum((pi)->id[2]) && \ + be32_to_cpu((pi)->st) <= (hdsiz) && \ + be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz)) + int atari_partition (struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor) { @@ -30,9 +40,8 @@ struct buffer_head *bh; struct rootsector *rs; struct partition_info *pi; - ulong extensect; - unsigned int psum; - int i; + u32 extensect; + u32 hd_size; #ifdef ICD_PARTS int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */ #endif @@ -44,16 +53,18 @@ } /* Verify this is an Atari rootsector: */ - psum = 0; - for (i=0;i<256;i++) { - psum+=ntohs(((__u16 *) (bh->b_data))[i]); - } - if ((psum & 0xFFFF) != 0x1234) { - brelse(bh); - return 0; + rs = (struct rootsector *) bh->b_data; + hd_size = hd->part[minor - 1].nr_sects; + if (!VALID_PARTITION(&rs->part[0], hd_size) && + !VALID_PARTITION(&rs->part[1], hd_size) && + !VALID_PARTITION(&rs->part[2], hd_size) && + !VALID_PARTITION(&rs->part[3], hd_size)) { + /* if there's no valid primary partition, assume that no Atari + format partition table (there's no reliable magic or the like + :-() */ + return 0; } - rs = (struct rootsector *) bh->b_data; pi = &rs->part[0]; printk (" AHDI"); for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++) @@ -72,7 +83,7 @@ part_fmt = 1; #endif printk(" XGM<"); - partsect = extensect = ntohl(pi->st); + partsect = extensect = be32_to_cpu(pi->st); while (1) { xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev)); @@ -93,8 +104,9 @@ break; } - add_gd_partition(hd, minor, partsect + ntohl(xrs->part[0].st), - ntohl(xrs->part[0].siz)); + add_gd_partition(hd, minor, + partsect + be32_to_cpu(xrs->part[0].st), + be32_to_cpu(xrs->part[0].siz)); if (!(xrs->part[1].flg & 1)) { /* end of linked partition list */ @@ -107,7 +119,7 @@ break; } - partsect = ntohl(xrs->part[1].st) + extensect; + partsect = be32_to_cpu(xrs->part[1].st) + extensect; brelse (xbh); minor++; if (minor >= m_lim) { @@ -120,7 +132,8 @@ else { /* we don't care about other id's */ - add_gd_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz)); + add_gd_partition (hd, minor, be32_to_cpu(pi->st), + be32_to_cpu(pi->siz)); } } } @@ -147,7 +160,8 @@ memcmp (pi->id, "RAW", 3) == 0) ) { part_fmt = 2; - add_gd_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz)); + add_gd_partition (hd, minor, be32_to_cpu(pi->st), + be32_to_cpu(pi->siz)); } } printk(" >"); diff -u --recursive --new-file v2.3.16/linux/fs/partitions/atari.h linux/fs/partitions/atari.h --- v2.3.16/linux/fs/partitions/atari.h Thu Aug 12 12:26:06 1999 +++ linux/fs/partitions/atari.h Sat Sep 4 13:09:36 1999 @@ -13,10 +13,10 @@ struct partition_info { - u_char flg; /* bit 0: active; bit 7: bootable */ + u8 flg; /* bit 0: active; bit 7: bootable */ char id[3]; /* "GEM", "BGM", "XGM", or other */ - u_long st; /* start of partition */ - u_long siz; /* length of partition */ + u32 st; /* start of partition */ + u32 siz; /* length of partition */ }; struct rootsector @@ -24,11 +24,11 @@ char unused[0x156]; /* room for boot code */ struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */ char unused2[0xc]; - u_long hd_siz; /* size of disk in blocks */ + u32 hd_siz; /* size of disk in blocks */ struct partition_info part[4]; - u_long bsl_st; /* start of bad sector list */ - u_long bsl_cnt; /* length of bad sector list */ - u_short checksum; /* checksum for bootable disks */ + u32 bsl_st; /* start of bad sector list */ + u32 bsl_cnt; /* length of bad sector list */ + u16 checksum; /* checksum for bootable disks */ } __attribute__((__packed__)); int atari_partition (struct gendisk *hd, kdev_t dev, diff -u --recursive --new-file v2.3.16/linux/fs/partitions/mac.c linux/fs/partitions/mac.c --- v2.3.16/linux/fs/partitions/mac.c Thu Aug 12 12:26:06 1999 +++ linux/fs/partitions/mac.c Sat Sep 4 13:09:36 1999 @@ -1,5 +1,5 @@ /* - * fs/partitions/msdos.c + * fs/partitions/mac.c * * Code extracted from drivers/block/genhd.c * Copyright (C) 1991-1998 Linus Torvalds diff -u --recursive --new-file v2.3.16/linux/fs/pipe.c linux/fs/pipe.c --- v2.3.16/linux/fs/pipe.c Thu Aug 26 13:05:40 1999 +++ linux/fs/pipe.c Mon Sep 6 09:48:36 1999 @@ -213,7 +213,7 @@ wake_up_interruptible(PIPE_WAIT(*inode)); pipe_wait(inode); if (signal_pending(current)) - goto out; + goto out_nolock; if (down_interruptible(PIPE_SEM(*inode))) goto out_nolock; if (!PIPE_READERS(*inode)) diff -u --recursive --new-file v2.3.16/linux/fs/read_write.c linux/fs/read_write.c --- v2.3.16/linux/fs/read_write.c Thu Aug 26 13:05:40 1999 +++ linux/fs/read_write.c Tue Sep 7 10:22:12 1999 @@ -13,7 +13,7 @@ #include -static loff_t default_llseek(struct file *file, loff_t offset, int origin) +loff_t default_llseek(struct file *file, loff_t offset, int origin) { long long retval; diff -u --recursive --new-file v2.3.16/linux/fs/udf/Makefile linux/fs/udf/Makefile --- v2.3.16/linux/fs/udf/Makefile Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/Makefile Sat Sep 4 12:42:30 1999 @@ -0,0 +1,16 @@ +# +# Makefile for the linux udf-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .o file). +# +# Note 2! The CFLAGS definitions are now in the main makefile.. + +O_TARGET := udf.o +O_OBJS := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \ + partition.o super.o truncate.o symlink.o fsync.o \ + crc.o directory.o misc.o udftime.o unicode.o +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.16/linux/fs/udf/balloc.c linux/fs/udf/balloc.c --- v2.3.16/linux/fs/udf/balloc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/balloc.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,441 @@ +/* + * balloc.c + * + * PURPOSE + * Block allocation handling routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1999 Ben Fennema + * (C) 1999 Stelias Computing Inc + * + * HISTORY + * + * 02/24/99 blf Created. + * + */ + +#include "udfdecl.h" +#include +#include +#include + +#include + +#include "udf_i.h" +#include "udf_sb.h" + +static int read_block_bitmap(struct super_block * sb, unsigned int block, + unsigned long bitmap_nr) +{ + struct buffer_head *bh = NULL; + int retval = 0; + lb_addr loc; + + loc.logicalBlockNum = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap; + loc.partitionReferenceNum = UDF_SB_PARTITION(sb); + + bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block), sb->s_blocksize); + if (!bh) + { + retval = -EIO; + } + UDF_SB_BLOCK_BITMAP_NUMBER(sb, bitmap_nr) = block; + UDF_SB_BLOCK_BITMAP(sb, bitmap_nr) = bh; + return retval; +} + +static int load__block_bitmap(struct super_block * sb, unsigned int block_group) +{ + int i, j, retval = 0; + unsigned long block_bitmap_number; + struct buffer_head * block_bitmap = NULL; + int nr_groups = (UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)) + + (sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8); + + if (block_group >= nr_groups) + { + udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups); + } + + if (nr_groups <= UDF_MAX_BLOCK_LOADED) + { + if (UDF_SB_BLOCK_BITMAP(sb, block_group)) + { + if (UDF_SB_BLOCK_BITMAP_NUMBER(sb, block_group) == block_group) + return block_group; + } + retval = read_block_bitmap(sb, block_group, block_group); + if (retval < 0) + return retval; + return block_group; + } + + for (i=0; i0; j--) + { + UDF_SB_BLOCK_BITMAP_NUMBER(sb, j) = UDF_SB_BLOCK_BITMAP_NUMBER(sb, j-1); + UDF_SB_BLOCK_BITMAP(sb, j) = UDF_SB_BLOCK_BITMAP(sb, j-1); + } + UDF_SB_BLOCK_BITMAP_NUMBER(sb, 0) = block_bitmap_number; + UDF_SB_BLOCK_BITMAP(sb, 0) = block_bitmap; + + if (!block_bitmap) + retval = read_block_bitmap(sb, block_group, 0); + } + else + { + if (UDF_SB_LOADED_BLOCK_BITMAPS(sb) < UDF_MAX_BLOCK_LOADED) + UDF_SB_LOADED_BLOCK_BITMAPS(sb) ++; + else + brelse(UDF_SB_BLOCK_BITMAP(sb, UDF_MAX_BLOCK_LOADED-1)); + for (j=UDF_SB_LOADED_BLOCK_BITMAPS(sb)-1; j>0; j--) + { + UDF_SB_BLOCK_BITMAP_NUMBER(sb, j) = UDF_SB_BLOCK_BITMAP_NUMBER(sb, j-1); + UDF_SB_BLOCK_BITMAP(sb, j) = UDF_SB_BLOCK_BITMAP(sb, j-1); + } + retval = read_block_bitmap(sb, block_group, 0); + } + return retval; +} + +static inline int load_block_bitmap(struct super_block *sb, + unsigned int block_group) +{ + int slot; + int nr_groups = (UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)) + + (sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8); + + if (UDF_SB_LOADED_BLOCK_BITMAPS(sb) > 0 && + UDF_SB_BLOCK_BITMAP_NUMBER(sb, 0) == block_group && + UDF_SB_BLOCK_BITMAP(sb, block_group)) + { + return 0; + } + else if (nr_groups <= UDF_MAX_BLOCK_LOADED && + UDF_SB_BLOCK_BITMAP_NUMBER(sb, block_group) == block_group && + UDF_SB_BLOCK_BITMAP(sb, block_group)) + { + slot = block_group; + } + else + { + slot = load__block_bitmap(sb, block_group); + } + + if (slot < 0) + return slot; + + if (!UDF_SB_BLOCK_BITMAP(sb, slot)) + return -EIO; + + return slot; +} + +void udf_free_blocks(const struct inode * inode, lb_addr bloc, Uint32 offset, + Uint32 count) +{ + struct buffer_head * bh = NULL; + unsigned long block; + unsigned long block_group; + unsigned long bit; + unsigned long i; + int bitmap_nr; + unsigned long overflow; + struct super_block * sb; + + sb = inode->i_sb; + if (!sb) + { + udf_debug("nonexistent device"); + return; + } + + if (UDF_SB_PARTMAPS(sb)[bloc.partitionReferenceNum].s_uspace_bitmap == 0xFFFFFFFF) + return; + + lock_super(sb); + if (bloc.logicalBlockNum < 0 || + (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) + { + udf_debug("%d < %d || %d + %d > %d\n", + bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count, + UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)); + goto error_return; + } + + block = bloc.logicalBlockNum + offset + (sizeof(struct SpaceBitmapDesc) << 3); + +do_more: + overflow = 0; + block_group = block >> (sb->s_blocksize_bits + 3); + bit = block % (sb->s_blocksize << 3); + + /* + * Check to see if we are freeing blocks across a group boundary. + */ + if (bit + count > (sb->s_blocksize << 3)) + { + overflow = bit + count - (sb->s_blocksize << 3); + count -= overflow; + } + bitmap_nr = load_block_bitmap(sb, block_group); + if (bitmap_nr < 0) + goto error_return; + + bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr); + for (i=0; i < count; i++) + { + if (udf_set_bit(bit + i, bh->b_data)) + { + udf_debug("bit %ld already set\n", bit + i); + udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]); + } + else if (UDF_SB_LVIDBH(sb)) + { + UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] = + cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+1); + } + } + mark_buffer_dirty(bh, 1); + if (overflow) + { + block += count; + count = overflow; + goto do_more; + } +error_return: + sb->s_dirt = 1; + if (UDF_SB_LVIDBH(sb)) + mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + unlock_super(sb); + return; +} + +int udf_alloc_blocks(const struct inode * inode, Uint16 partition, + Uint32 first_block, Uint32 block_count) +{ + int alloc_count = 0; + int bit, block, block_group, group_start; + int nr_groups, bitmap_nr; + struct buffer_head *bh; + struct super_block *sb; + + sb = inode->i_sb; + if (!sb) + { + udf_debug("nonexistent device\n"); + return 0; + } + lock_super(sb); + + if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition)) + goto out; + +repeat: + nr_groups = (UDF_SB_PARTLEN(sb, partition) + + (sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8); + block = first_block + (sizeof(struct SpaceBitmapDesc) << 3); + block_group = block >> (sb->s_blocksize_bits + 3); + group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc); + + bitmap_nr = load_block_bitmap(sb, block_group); + if (bitmap_nr < 0) + goto out; + bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr); + + bit = block % (sb->s_blocksize << 3); + + while (bit < (sb->s_blocksize << 3) && block_count > 0) + { + if (!udf_test_bit(bit, bh->b_data)) + goto out; + if (!udf_clear_bit(bit, bh->b_data)) + { + udf_debug("bit already cleared for block %d\n", bit); + goto out; + } + block_count --; + alloc_count ++; + bit ++; + block ++; + + } + mark_buffer_dirty(bh, 1); + if (block_count > 0) + goto repeat; +out: + if (UDF_SB_LVIDBH(sb)) + { + UDF_SB_LVID(sb)->freeSpaceTable[partition] = + cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count); + mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + } + sb->s_dirt = 1; + unlock_super(sb); + return alloc_count; +} + +int udf_new_block(const struct inode * inode, Uint16 partition, Uint32 goal, int *err) +{ + int tmp, newbit, bit=0, block, block_group, group_start; + int end_goal, nr_groups, bitmap_nr, i; + struct buffer_head *bh = NULL; + struct super_block *sb; + char *ptr; + int newblock = 0; + + *err = -ENOSPC; + sb = inode->i_sb; + if (!sb) + { + udf_debug("nonexistent device\n"); + return newblock; + } + lock_super(sb); + +repeat: + if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition)) + goal = 0; + + nr_groups = (UDF_SB_PARTLEN(sb, partition) + + (sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8); + block = goal + (sizeof(struct SpaceBitmapDesc) << 3); + block_group = block >> (sb->s_blocksize_bits + 3); + group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc); + + bitmap_nr = load_block_bitmap(sb, block_group); + if (bitmap_nr < 0) + goto error_return; + bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr); + ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start); + + if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) + { + bit = block % (sb->s_blocksize << 3); + + if (udf_test_bit(bit, bh->b_data)) + { + goto got_block; + } + end_goal = (bit + 63) & ~63; + bit = udf_find_next_one_bit(bh->b_data, end_goal, bit); + if (bit < end_goal) + goto got_block; + ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF, sb->s_blocksize - ((bit + 7) >> 3)); + newbit = (ptr - ((char *)bh->b_data)) << 3; + if (newbit < sb->s_blocksize << 3) + { + bit = newbit; + goto search_back; + } + newbit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, bit); + if (newbit < sb->s_blocksize << 3) + { + bit = newbit; + goto got_block; + } + } + + for (i=0; i<(nr_groups*2); i++) + { + block_group ++; + if (block_group >= nr_groups) + block_group = 0; + group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc); + + bitmap_nr = load_block_bitmap(sb, block_group); + if (bitmap_nr < 0) + goto error_return; + bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr); + if (i < nr_groups) + { + ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start); + if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) + { + bit = (ptr - ((char *)bh->b_data)) << 3; + break; + } + } + else + { + bit = udf_find_next_one_bit((char *)bh->b_data, sb->s_blocksize << 3, group_start << 3); + if (bit < sb->s_blocksize << 3) + break; + } + } + if (i >= (nr_groups*2)) + { + unlock_super(sb); + return newblock; + } + if (bit < sb->s_blocksize << 3) + goto search_back; + else + bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3); + if (bit >= sb->s_blocksize << 3) + { + unlock_super(sb); + return 0; + } + +search_back: + for (i=0; i<7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--); + +got_block: + newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) - + (group_start << 3); + + tmp = udf_get_pblock(sb, newblock, partition, 0); + if (!udf_clear_bit(bit, bh->b_data)) + { + udf_debug("bit already cleared for block %d\n", bit); + goto repeat; + } + + mark_buffer_dirty(bh, 1); + if (!(bh = getblk(sb->s_dev, tmp, sb->s_blocksize))) + { + udf_debug("cannot get block %d\n", tmp); + unlock_super(sb); + return 0; + } + memset(bh->b_data, 0, sb->s_blocksize); + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh, 1); + udf_release_data(bh); + + if (UDF_SB_LVIDBH(sb)) + { + UDF_SB_LVID(sb)->freeSpaceTable[partition] = + cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1); + mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + } + sb->s_dirt = 1; + unlock_super(sb); + *err = 0; + return newblock; + +error_return: + *err = -EIO; + unlock_super(sb); + return 0; +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/crc.c linux/fs/udf/crc.c --- v2.3.16/linux/fs/udf/crc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/crc.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,178 @@ +/* + * crc.c + * + * PURPOSE + * Routines to generate, calculate, and test a 16-bit CRC. + * + * DESCRIPTION + * The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories + * and Ned W. Rhodes of Software Systems Group. It has been published in + * "Design and Validation of Computer Protocols", Prentice Hall, + * Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4. + * + * Copyright is held by AT&T. + * + * AT&T gives permission for the free use of the CRC source code. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + */ + +#include "udfdecl.h" + +static Uint16 crc_table[256] = { + 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U, + 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU, + 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U, + 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU, + 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U, + 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU, + 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U, + 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU, + 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, + 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU, + 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U, + 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU, + 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U, + 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U, + 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U, + 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U, + 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU, + 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, + 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU, + 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, + 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU, + 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, + 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU, + 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, + 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU, + 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U, + 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU, + 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U, + 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U, + 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U, + 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U, + 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U +}; + +/* + * udf_crc + * + * PURPOSE + * Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial. + * + * DESCRIPTION + * The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory. + * The polynomial used is: x^16 + x^12 + x^15 + 1 + * + * PRE-CONDITIONS + * data Pointer to the data block. + * size Size of the data block. + * + * POST-CONDITIONS + * CRC of the data block. + * + * HISTORY + * July 21, 1997 - Andrew E. Mileski + * Adapted from OSTA-UDF(tm) 1.50 standard. + */ +extern Uint16 +udf_crc(Uint8 *data, Uint32 size, Uint16 crc) +{ + while (size--) + crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8); + + return crc; +} + +/****************************************************************************/ +#if defined(TEST) + +/* + * PURPOSE + * Test udf_crc() + * + * HISTORY + * July 21, 1997 - Andrew E. Mileski + * Adapted from OSTA-UDF(tm) 1.50 standard. + */ + +unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U }; + +int main(void) +{ + unsigned short x; + + x = udf_crc16(bytes, sizeof bytes); + printf("udf_crc16: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U); + + return 0; +} + +#endif /* defined(TEST) */ + +/****************************************************************************/ +#if defined(GENERATE) + +/* + * PURPOSE + * Generate a table for fast 16-bit CRC calculations (any polynomial). + * + * DESCRIPTION + * The ITU-T V.41 polynomial is 010041. + * + * HISTORY + * July 21, 1997 - Andrew E. Mileski + * Adapted from OSTA-UDF(tm) 1.50 standard. + */ + +#include + +int main(int argc, char **argv) +{ + unsigned long crc, poly; + int n, i; + + /* Get the polynomial */ + sscanf(argv[1], "%lo", &poly); + if (poly & 0xffff0000U){ + fprintf(stderr, "polynomial is too large\en"); + exit(1); + } + + printf("/* CRC 0%o */\n", poly); + + /* Create a table */ + printf("static unsigned short crc_table[256] = {\n"); + for (n = 0; n < 256; n++){ + if (n % 8 == 0) + printf("\t"); + crc = n << 8; + for (i = 0; i < 8; i++){ + if(crc & 0x8000U) + crc = (crc << 1) ^ poly; + else + crc <<= 1; + crc &= 0xFFFFU; + } + if (n == 255) + printf("0x%04xU ", crc); + else + printf("0x%04xU, ", crc); + if(n % 8 == 7) + printf("\n"); + } + printf("};\n"); + + return 0; +} + +#endif /* defined(GENERATE) */ diff -u --recursive --new-file v2.3.16/linux/fs/udf/dir.c linux/fs/udf/dir.c --- v2.3.16/linux/fs/udf/dir.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/dir.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,296 @@ +/* + * dir.c + * + * PURPOSE + * Directory handling routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1998-1999 Ben Fennema + * + * HISTORY + * + * 10/05/98 dgb Split directory operations into it's own file + * Implemented directory reads via do_udf_readdir + * 10/06/98 Made directory operations work! + * 11/17/98 Rewrote directory to support ICB_FLAG_AD_LONG + * 11/25/98 blf Rewrote directory handling (readdir+lookup) to support reading + * across blocks. + * 12/12/98 Split out the lookup code to namei.c. bulk of directory + * code now in directory.c:udf_fileident_read. + */ + +#include "udfdecl.h" + +#if defined(__linux__) && defined(__KERNEL__) +#include +#include "udf_i.h" +#include "udf_sb.h" +#include +#include +#include +#include +#include +#endif + +/* Prototypes for file operations */ +static int udf_readdir(struct file *, void *, filldir_t); +static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *); + +/* readdir and lookup functions */ + +static struct file_operations udf_dir_operations = { + NULL, /* lllseek */ + NULL, /* read */ + NULL, /* write */ + udf_readdir, /* readdir */ + NULL, /* poll */ + udf_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* flush */ + NULL, /* release */ + udf_sync_file, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ +}; + +struct inode_operations udf_dir_inode_operations = { + &udf_dir_operations, +#ifdef CONFIG_UDF_RW + udf_create, /* create */ +#else + NULL, /* create */ +#endif + udf_lookup, /* lookup */ +#ifdef CONFIG_UDF_RW + udf_link, /* link */ + udf_unlink, /* unlink */ + udf_symlink, /* symlink */ + udf_mkdir, /* mkdir */ + udf_rmdir, /* rmdir */ + udf_mknod, /* mknod */ + udf_rename, /* rename */ +#else + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ +#endif + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* get_block */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* flushpage */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +/* + * udf_readdir + * + * PURPOSE + * Read a directory entry. + * + * DESCRIPTION + * Optional - sys_getdents() will return -ENOTDIR if this routine is not + * available. + * + * Refer to sys_getdents() in fs/readdir.c + * sys_getdents() -> . + * + * PRE-CONDITIONS + * filp Pointer to directory file. + * buf Pointer to directory entry buffer. + * filldir Pointer to filldir function. + * + * POST-CONDITIONS + * >=0 on success. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ + +int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + struct inode *dir = filp->f_dentry->d_inode; + int result; + + if (!dir) + return -EBADF; + + if (!S_ISDIR(dir->i_mode)) + return -ENOTDIR; + + if ( filp->f_pos == 0 ) + { + if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino) < 0) + return 0; + } + + result = do_udf_readdir(dir, filp, filldir, dirent); + UPDATE_ATIME(dir); + return result; +} + +static int +do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent) +{ + struct udf_fileident_bh fibh; + struct FileIdentDesc *fi=NULL; + struct FileIdentDesc cfi; + int block, iblock; + int nf_pos = filp->f_pos; + int flen; + char fname[255]; + char *nameptr; + Uint16 liu; + Uint8 lfi; + int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2; + struct buffer_head * bh = NULL; + lb_addr bloc, eloc; + Uint32 extoffset, elen, offset; + + if (nf_pos >= size) + return 1; + + if (nf_pos == 0) + nf_pos = (UDF_I_EXT0OFFS(dir) >> 2); + + fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; + if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2), + &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED) + { + block = udf_get_lb_pblock(dir->i_sb, eloc, offset); + if (++offset < (elen >> dir->i_sb->s_blocksize_bits)) + { + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT) + extoffset -= sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG) + extoffset -= sizeof(long_ad); + } + else + offset = 0; + } + else + { + udf_release_data(bh); + return 0; + } + + if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize))) + { + udf_release_data(bh); + return 0; + } + + while ( nf_pos < size ) + { + filp->f_pos = nf_pos; + + fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &offset, &bh); + liu = le16_to_cpu(cfi.lengthOfImpUse); + lfi = cfi.lengthFileIdent; + + if (!fi) + { + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + udf_release_data(bh); + return 1; + } + + if (fibh.sbh == fibh.ebh) + nameptr = fi->fileIdent + liu; + else + { + int poffset; /* Unpaded ending offset */ + + poffset = fibh.soffset + sizeof(struct FileIdentDesc) + liu + lfi; + + if (poffset >= lfi) + nameptr = (char *)(fibh.ebh->b_data + poffset - lfi); + else + { + nameptr = fname; + memcpy(nameptr, fi->fileIdent + liu, lfi - poffset); + memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset); + } + } + + if ( (cfi.fileCharacteristics & FILE_DELETED) != 0 ) + { + if ( !IS_UNDELETE(dir->i_sb) ) + continue; + } + + if ( (cfi.fileCharacteristics & FILE_HIDDEN) != 0 ) + { + if ( !IS_UNHIDE(dir->i_sb) ) + continue; + } + + iblock = udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0); + + if (!lfi) /* parent directory */ + { + if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino) < 0) + { + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + udf_release_data(bh); + return 1; + } + } + else + { + if ((flen = udf_get_filename(nameptr, fname, lfi))) + { + if (filldir(dirent, fname, flen, filp->f_pos, iblock) < 0) + { + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + udf_release_data(bh); + return 1; /* halt enum */ + } + } + else + { + udf_debug("size=%d, nf_pos=%d, liu=%d, lfi=%d\n", size, nf_pos, liu, lfi); + } + } + } /* end while */ + + filp->f_pos = nf_pos; + + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + udf_release_data(bh); + + if ( filp->f_pos >= size) + return 1; + else + return 0; +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/directory.c linux/fs/udf/directory.c --- v2.3.16/linux/fs/udf/directory.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/directory.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,332 @@ +/* + * directory.c + * + * PURPOSE + * Directory related functions + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + */ + +#include "udfdecl.h" +#include "udf_sb.h" + +#if defined(__linux__) && defined(__KERNEL__) + +#include +#include +#include + +#else + +#include +#include +#include + +#endif + +#ifdef __KERNEL__ + +Uint8 * udf_filead_read(struct inode *dir, Uint8 *tmpad, Uint8 ad_size, + lb_addr fe_loc, int *pos, int *offset, struct buffer_head **bh, int *error) +{ + int loffset = *offset; + int block; + Uint8 *ad; + int remainder; + + *error = 0; + + ad = (Uint8 *)(*bh)->b_data + *offset; + *offset += ad_size; + + if (!ad) + { + udf_release_data(*bh); + *error = 1; + return NULL; + } + + if (*offset == dir->i_sb->s_blocksize) + { + udf_release_data(*bh); + block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos); + if (!block) + return NULL; + if (!(*bh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize))) + return NULL; + } + else if (*offset > dir->i_sb->s_blocksize) + { + ad = tmpad; + + remainder = dir->i_sb->s_blocksize - loffset; + memcpy((Uint8 *)ad, (*bh)->b_data + loffset, remainder); + + udf_release_data(*bh); + block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos); + if (!block) + return NULL; + if (!((*bh) = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize))) + return NULL; + + memcpy((Uint8 *)ad + remainder, (*bh)->b_data, ad_size - remainder); + *offset = ad_size - remainder; + } + return ad; +} + +struct FileIdentDesc * +udf_fileident_read(struct inode *dir, int *nf_pos, + struct udf_fileident_bh *fibh, + struct FileIdentDesc *cfi, + lb_addr *bloc, Uint32 *extoffset, + Uint32 *offset, struct buffer_head **bh) +{ + struct FileIdentDesc *fi; + lb_addr eloc; + Uint32 elen; + int block; + + fibh->soffset = fibh->eoffset; + + if (fibh->eoffset == dir->i_sb->s_blocksize) + { + int lextoffset = *extoffset; + + if (udf_next_aext(dir, bloc, extoffset, &eloc, &elen, bh, 1) != + EXTENT_RECORDED_ALLOCATED) + { + return NULL; + } + + block = udf_get_lb_pblock(dir->i_sb, eloc, *offset); + + (*offset) ++; + + if (*offset >= (elen >> dir->i_sb->s_blocksize_bits)) + *offset = 0; + else + *extoffset = lextoffset; + + udf_release_data(fibh->sbh); + if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize))) + return NULL; + fibh->soffset = fibh->eoffset = 0; + } + else if (fibh->sbh != fibh->ebh) + { + udf_release_data(fibh->sbh); + fibh->sbh = fibh->ebh; + } + + fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize, + &(fibh->eoffset)); + + if (!fi) + return NULL; + + *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2); + + if (fibh->eoffset <= dir->i_sb->s_blocksize) + { + memcpy((Uint8 *)cfi, (Uint8 *)fi, sizeof(struct FileIdentDesc)); + } + else if (fibh->eoffset > dir->i_sb->s_blocksize) + { + int lextoffset = *extoffset; + + if (udf_next_aext(dir, bloc, extoffset, &eloc, &elen, bh, 1) != + EXTENT_RECORDED_ALLOCATED) + { + return NULL; + } + + block = udf_get_lb_pblock(dir->i_sb, eloc, *offset); + + (*offset) ++; + + if (*offset >= (elen >> dir->i_sb->s_blocksize_bits)) + *offset = 0; + else + *extoffset = lextoffset; + + fibh->soffset -= dir->i_sb->s_blocksize; + fibh->eoffset -= dir->i_sb->s_blocksize; + + if (!(fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize))) + return NULL; + + if (sizeof(struct FileIdentDesc) > - fibh->soffset) + { + int fi_len; + + memcpy((Uint8 *)cfi, (Uint8 *)fi, - fibh->soffset); + memcpy((Uint8 *)cfi - fibh->soffset, fibh->ebh->b_data, + sizeof(struct FileIdentDesc) + fibh->soffset); + + fi_len = (sizeof(struct FileIdentDesc) + cfi->lengthFileIdent + + le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3; + + *nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2); + fibh->eoffset = fibh->soffset + fi_len; + } + else + { + memcpy((Uint8 *)cfi, (Uint8 *)fi, sizeof(struct FileIdentDesc)); + } + } + return fi; +} +#endif + +struct FileIdentDesc * +udf_get_fileident(void * buffer, int bufsize, int * offset) +{ + struct FileIdentDesc *fi; + int lengthThisIdent; + Uint8 * ptr; + int padlen; + + if ( (!buffer) || (!offset) ) { +#ifdef __KERNEL__ + udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset); +#endif + return NULL; + } + + ptr = buffer; + + if ( (*offset > 0) && (*offset < bufsize) ) { + ptr += *offset; + } + fi=(struct FileIdentDesc *)ptr; + if (le16_to_cpu(fi->descTag.tagIdent) != TID_FILE_IDENT_DESC) + { +#ifdef __KERNEL__ + udf_debug("0x%x != TID_FILE_IDENT_DESC\n", + le16_to_cpu(fi->descTag.tagIdent)); + udf_debug("offset: %u sizeof: %u bufsize: %u\n", + *offset, sizeof(struct FileIdentDesc), bufsize); +#endif + return NULL; + } + if ( (*offset + sizeof(struct FileIdentDesc)) > bufsize ) + { + lengthThisIdent = sizeof(struct FileIdentDesc); + } + else + lengthThisIdent = sizeof(struct FileIdentDesc) + + fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse); + + /* we need to figure padding, too! */ + padlen = lengthThisIdent % UDF_NAME_PAD; + if (padlen) + lengthThisIdent += (UDF_NAME_PAD - padlen); + *offset = *offset + lengthThisIdent; + + return fi; +} + +extent_ad * +udf_get_fileextent(void * buffer, int bufsize, int * offset) +{ + extent_ad * ext; + struct FileEntry *fe; + Uint8 * ptr; + + if ( (!buffer) || (!offset) ) + { +#ifdef __KERNEL__ + printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n"); +#endif + return NULL; + } + + fe = (struct FileEntry *)buffer; + + if ( le16_to_cpu(fe->descTag.tagIdent) != TID_FILE_ENTRY ) + { +#ifdef __KERNEL__ + udf_debug("0x%x != TID_FILE_ENTRY\n", + le16_to_cpu(fe->descTag.tagIdent)); +#endif + return NULL; + } + + ptr=(Uint8 *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr); + + if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) ) + { + ptr += *offset; + } + + ext = (extent_ad *)ptr; + + *offset = *offset + sizeof(extent_ad); + return ext; +} + +short_ad * +udf_get_fileshortad(void * buffer, int maxoffset, int *offset, int inc) +{ + short_ad * sa; + Uint8 * ptr; + + if ( (!buffer) || (!offset) ) + { +#ifdef __KERNEL__ + printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n"); +#endif + return NULL; + } + + ptr = (Uint8 *)buffer; + + if ( (*offset > 0) && (*offset < maxoffset) ) + ptr += *offset; + else + return NULL; + + if ((sa = (short_ad *)ptr)->extLength == 0) + return NULL; + else if (inc) + (*offset) += sizeof(short_ad); + return sa; +} + +long_ad * +udf_get_filelongad(void * buffer, int maxoffset, int * offset, int inc) +{ + long_ad * la; + Uint8 * ptr; + + if ( (!buffer) || !(offset) ) + { +#ifdef __KERNEL__ + printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n"); +#endif + return NULL; + } + + ptr = (Uint8 *)buffer; + + if ( (*offset > 0) && (*offset < maxoffset) ) + ptr += *offset; + else + return NULL; + + if ((la = (long_ad *)ptr)->extLength == 0) + return NULL; + else if (inc) + (*offset) += sizeof(long_ad); + return la; +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/file.c linux/fs/udf/file.c --- v2.3.16/linux/fs/udf/file.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/file.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,443 @@ +/* + * file.c + * + * PURPOSE + * File handling routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1998-1999 Dave Boynton + * (C) 1998-1999 Ben Fennema + * (C) 1999 Stelias Computing Inc + * + * HISTORY + * + * 10/02/98 dgb Attempt to integrate into udf.o + * 10/07/98 Switched to using generic_readpage, etc., like isofs + * And it works! + * 12/06/98 blf Added udf_file_read. uses generic_file_read for all cases but + * ICB_FLAG_AD_IN_ICB. + * 04/06/99 64 bit file handling on 32 bit systems taken from ext2 file.c + * 05/12/99 Preliminary file write support + */ + +#include "udfdecl.h" +#include +#include +#include +#include +#include /* memset */ +#include +#include + +#include "udf_i.h" +#include "udf_sb.h" + +#define NBUF 32 + +typedef void * poll_table; + +static long long udf_file_llseek(struct file *, long long, int); +static ssize_t udf_file_read_adinicb (struct file *, char *, size_t, loff_t *); +static ssize_t udf_file_write (struct file *, const char *, size_t, loff_t *); +#if BITS_PER_LONG < 64 +static int udf_open_file(struct inode *, struct file *); +#endif +static int udf_release_file(struct inode *, struct file *); + +static struct file_operations udf_file_operations = { + udf_file_llseek, /* llseek */ + generic_file_read, /* read */ + udf_file_write, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + udf_ioctl, /* ioctl */ + generic_file_mmap, /* mmap */ +#if BITS_PER_LONG == 64 + NULL, /* open */ +#else + udf_open_file, /* open */ +#endif + NULL, /* flush */ + udf_release_file, /* release */ + udf_sync_file, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ +}; + +struct inode_operations udf_file_inode_operations = { + &udf_file_operations, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + udf_get_block, /* get_block */ + block_read_full_page, /* readpage */ + block_write_full_page, /* writepage */ + block_flushpage, /* flushpage */ +#ifdef CONFIG_UDF_RW + udf_truncate, /* truncate */ +#else + NULL, /* truncate */ +#endif + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +static struct file_operations udf_file_operations_adinicb = { + udf_file_llseek, /* llseek */ + udf_file_read_adinicb,/* read */ + udf_file_write, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + udf_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* flush */ + udf_release_file, /* release */ + udf_sync_file, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ +}; + +struct inode_operations udf_file_inode_operations_adinicb = { + &udf_file_operations_adinicb, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + udf_get_block, /* get_block */ + block_read_full_page, /* readpage */ + block_write_full_page, /* writepage */ + block_flushpage, /* flushpage */ +#ifdef CONFIG_UDF_RW + udf_truncate, /* truncate */ +#else + NULL, /* truncate */ +#endif + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +/* + * Make sure the offset never goes beyond the 32-bit mark.. + */ +static long long udf_file_llseek(struct file * file, long long offset, int origin) +{ + struct inode * inode = file->f_dentry->d_inode; + + switch (origin) + { + case 2: + { + offset += inode->i_size; + break; + } + case 1: + { + offset += file->f_pos; + break; + } + } + if (((unsigned long long) offset >> 32) != 0) + { +#if BITS_PER_LONG < 64 + return -EINVAL; +#else + if (offset > ???) + return -EINVAL; +#endif + } + if (offset != file->f_pos) + { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++event; + } + return offset; +} + +static inline void remove_suid(struct inode * inode) +{ + unsigned int mode; + + /* set S_IGID if S_IXGRP is set, and always set S_ISUID */ + mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID; + + /* was any of the uid bits set? */ + mode &= inode->i_mode; + if (mode && !capable(CAP_FSETID)) + { + inode->i_mode &= ~mode; + mark_inode_dirty(inode); + } +} + +static ssize_t udf_file_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + ssize_t retval; + struct inode *inode = file->f_dentry->d_inode; + remove_suid(inode); + + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) + { + int i, err; + struct buffer_head *bh; + + if ((bh = udf_expand_adinicb(inode, &i, 0, &err))) + udf_release_data(bh); + } + + retval = generic_file_write(file, buf, count, ppos, block_write_partial_page); + + if (retval > 0) + { + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + UDF_I_UCTIME(inode) = UDF_I_UMTIME(inode) = CURRENT_UTIME; + } + mark_inode_dirty(inode); + return retval; +} + +/* + * udf_file_read + * + * PURPOSE + * Read from an open file. + * + * DESCRIPTION + * Optional - sys_read() will return -EINVAL if this routine is not + * available. + * + * Refer to sys_read() in fs/read_write.c + * sys_read() -> . + * + * Note that you can use generic_file_read() instead, which requires that + * udf_readpage() be available, but you can use generic_readpage(), which + * requires that udf_block_map() be available. Reading will then be done by + * memory-mapping the file a page at a time. This is not suitable for + * devices that don't handle read-ahead [example: CD-R/RW that may have + * blank sectors that shouldn't be read]. + * + * Refer to generic_file_read() in mm/filemap.c and to generic_readpage() + * in fs/buffer.c + * + * Block devices can use block_read() instead. Refer to fs/block_dev.c + * + * PRE-CONDITIONS + * inode Pointer to inode to read from (never NULL). + * filp Pointer to file to read from (never NULL). + * buf Point to read buffer (validated). + * bufsize Size of read buffer. + * + * POST-CONDITIONS + * Bytes read (>=0) or an error code (<0) that + * sys_read() will return. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +static ssize_t udf_file_read_adinicb(struct file * filp, char * buf, + size_t bufsize, loff_t * loff) +{ + struct inode *inode = filp->f_dentry->d_inode; + Uint32 size, left, pos, block; + struct buffer_head *bh = NULL; + + size = inode->i_size; + if (*loff > size) + left = 0; + else + left = size - *loff; + if (left > bufsize) + left = bufsize; + + if (left <= 0) + return 0; + + pos = *loff + UDF_I_EXT0OFFS(inode); + block = udf_block_map(inode, 0); + if (!(bh = udf_tread(inode->i_sb, + udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0), + inode->i_sb->s_blocksize))) + { + return 0; + } + if (!copy_to_user(buf, bh->b_data + pos, left)) + *loff += left; + else + return -EFAULT; + + return left; +} + +/* + * udf_ioctl + * + * PURPOSE + * Issue an ioctl. + * + * DESCRIPTION + * Optional - sys_ioctl() will return -ENOTTY if this routine is not + * available, and the ioctl cannot be handled without filesystem help. + * + * sys_ioctl() handles these ioctls that apply only to regular files: + * FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD + * These ioctls are also handled by sys_ioctl(): + * FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC + * All other ioctls are passed to the filesystem. + * + * Refer to sys_ioctl() in fs/ioctl.c + * sys_ioctl() -> . + * + * PRE-CONDITIONS + * inode Pointer to inode that ioctl was issued on. + * filp Pointer to file that ioctl was issued on. + * cmd The ioctl command. + * arg The ioctl argument [can be interpreted as a + * user-space pointer if desired]. + * + * POST-CONDITIONS + * Success (>=0) or an error code (<=0) that + * sys_ioctl() will return. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int result=-1; + int size; + struct buffer_head *bh = NULL; + struct FileEntry *fe; + Uint16 ident; + + if ( permission(inode, MAY_READ) != 0 ) + { + udf_debug("no permission to access inode %lu\n", + inode->i_ino); + return -EPERM; + } + + if ( !arg ) + { + udf_debug("invalid argument to udf_ioctl\n"); + return -EINVAL; + } + + /* first, do ioctls that don't need to udf_read */ + switch (cmd) + { + case UDF_GETVOLIDENT: + if ( (result == verify_area(VERIFY_WRITE, (char *)arg, 32)) == 0) + result = copy_to_user((char *)arg, UDF_SB_VOLIDENT(inode->i_sb), 32); + return result; + + } + + /* ok, we need to read the inode */ + bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident); + + if (!bh || ident != TID_FILE_ENTRY) + { + udf_debug("bread failed (ino=%ld) or ident (%d) != TID_FILE_ENTRY", + inode->i_ino, ident); + return -EFAULT; + } + + fe = (struct FileEntry *)bh->b_data; + size = le32_to_cpu(fe->lengthExtendedAttr); + + switch (cmd) + { + case UDF_GETEASIZE: + if ( (result = verify_area(VERIFY_WRITE, (char *)arg, 4)) == 0) + result= put_user(size, (int *)arg); + break; + + case UDF_GETEABLOCK: + if ( (result = verify_area(VERIFY_WRITE, (char *)arg, size)) == 0) + result= copy_to_user((char *)arg, fe->extendedAttr, size); + break; + + default: + udf_debug("ino=%ld, cmd=%d\n", inode->i_ino, cmd); + break; + } + + udf_release_data(bh); + return result; +} + +/* + * udf_release_file + * + * PURPOSE + * Called when all references to the file are closed + * + * DESCRIPTION + * Discard prealloced blocks + * + * HISTORY + * + */ +static int udf_release_file(struct inode * inode, struct file * filp) +{ + if (filp->f_mode & FMODE_WRITE) + udf_discard_prealloc(inode); + return 0; +} + +#if BITS_PER_LONG < 64 +/* + * udf_open_file + * + * PURPOSE + * Called when an inode is about to be open. + * + * DESCRIPTION + * Use this to disallow opening RW large files on 32 bit systems. + * + * HISTORY + * + */ +static int udf_open_file(struct inode * inode, struct file * filp) +{ + if (inode->i_size == (Uint32)-1 && (filp->f_mode & FMODE_WRITE)) + return -EFBIG; + return 0; +} +#endif diff -u --recursive --new-file v2.3.16/linux/fs/udf/fsync.c linux/fs/udf/fsync.c --- v2.3.16/linux/fs/udf/fsync.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/fsync.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,110 @@ +/* + * fsync.c + * + * PURPOSE + * Fsync handling routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1999 Ben Fennema + * (C) 1999 Stelias Computing Inc + * + * HISTORY + * + * 05/22/99 blf Created. + * + */ + +#include "udfdecl.h" + +#include +#include +#include "udf_i.h" + +static int sync_extent_block (struct inode * inode, Uint32 block, int wait) +{ + struct buffer_head * bh; + + if (!block) + return 0; + bh = get_hash_table (inode->i_dev, block, inode->i_sb->s_blocksize); + if (!bh) + return 0; + if (wait && buffer_req(bh) && !buffer_uptodate(bh)) { + brelse (bh); + return -1; + } + if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) { + brelse (bh); + return 0; + } + ll_rw_block (WRITE, 1, &bh); + atomic_dec(&bh->b_count); + return 0; +} + +static int sync_all_extents(struct inode * inode, int wait) +{ + lb_addr bloc, eloc; + Uint32 extoffset, lextoffset, elen, offset, block; + int err = 0, etype; + struct buffer_head *bh = NULL; + + if ((etype = inode_bmap(inode, 0, &bloc, &extoffset, &eloc, &elen, &offset, &bh)) != -1) + { + block = udf_get_lb_pblock(inode->i_sb, bloc, 0); + err |= sync_extent_block(inode, block, wait); + lextoffset = extoffset; + + while ((etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1) + { + if (lextoffset > extoffset) + { + block = udf_get_lb_pblock(inode->i_sb, bloc, 0); + err |= sync_extent_block(inode, block, wait); + } + lextoffset = extoffset; + } + } + udf_release_data(bh); + return err; +} + +/* + * File may be NULL when we are called. Perhaps we shouldn't + * even pass file to fsync ? + */ + +int udf_sync_file(struct file * file, struct dentry *dentry) +{ + int wait, err = 0; + struct inode *inode = dentry->d_inode; + + if ((S_ISLNK(inode->i_mode) && !(inode->i_blocks)) || + UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) + { + /* + * Don't sync fast links! or ICB_FLAG_AD_IN_ICB + */ + goto skip; + } + + err = generic_buffer_fdatasync(inode, 0, ~0UL); + + for (wait=0; wait<=1; wait++) + { + err |= sync_all_extents (inode, wait); + } +skip: + err |= udf_sync_inode (inode); + return err ? -EIO : 0; +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/ialloc.c linux/fs/udf/ialloc.c --- v2.3.16/linux/fs/udf/ialloc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/ialloc.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,169 @@ +/* + * ialloc.c + * + * PURPOSE + * Inode allocation handling routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1998-1999 Ben Fennema + * + * HISTORY + * + * 02/24/99 blf Created. + * + */ + +#include "udfdecl.h" +#include +#include +#include + +#include "udf_i.h" +#include "udf_sb.h" + +void udf_free_inode(struct inode * inode) +{ + struct super_block * sb = inode->i_sb; + int is_directory; + unsigned long ino; + + if (!inode->i_dev) + { + udf_debug("inode has no device\n"); + return; + } + if (inode->i_count > 1) + { + udf_debug("inode has count=%d\n", inode->i_count); + return; + } + if (inode->i_nlink) + { + udf_debug("inode has nlink=%d\n", inode->i_nlink); + return; + } + if (!sb) + { + udf_debug("inode on nonexistent device\n"); + return; + } + + ino = inode->i_ino; + + lock_super(sb); + + is_directory = S_ISDIR(inode->i_mode); + + clear_inode(inode); + + if (UDF_SB_LVIDBH(sb)) + { + if (is_directory) + UDF_SB_LVIDIU(sb)->numDirs = + cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) - 1); + else + UDF_SB_LVIDIU(sb)->numFiles = + cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1); + + mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + } + + unlock_super(sb); + + udf_free_blocks(inode, UDF_I_LOCATION(inode), 0, 1); +} + +struct inode * udf_new_inode (const struct inode *dir, int mode, int * err) +{ + struct super_block *sb; + struct inode * inode; + int block; + Uint32 start = UDF_I_LOCATION(dir).logicalBlockNum; + + inode = get_empty_inode(); + if (!inode) + { + *err = -ENOMEM; + return NULL; + } + sb = dir->i_sb; + inode->i_sb = sb; + inode->i_flags = 0; + *err = -ENOSPC; + + block = udf_new_block(dir, UDF_I_LOCATION(dir).partitionReferenceNum, + start, err); + if (*err) + { + iput(inode); + return NULL; + } + lock_super(sb); + + if (UDF_SB_LVIDBH(sb)) + { + struct LogicalVolHeaderDesc *lvhd; + Uint64 uniqueID; + lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(sb)->logicalVolContentsUse); + if (S_ISDIR(mode)) + UDF_SB_LVIDIU(sb)->numDirs = + cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) + 1); + else + UDF_SB_LVIDIU(sb)->numFiles = + cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) + 1); + UDF_I_UNIQUE(inode) = uniqueID = le64_to_cpu(lvhd->uniqueID); + if (!(++uniqueID & 0x00000000FFFFFFFFUL)) + uniqueID += 16; + lvhd->uniqueID = cpu_to_le64(uniqueID); + mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + } + inode->i_mode = mode; + inode->i_sb = sb; + inode->i_nlink = 1; + inode->i_dev = sb->s_dev; + inode->i_uid = current->fsuid; + if (dir->i_mode & S_ISGID) + { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } + else + inode->i_gid = current->fsgid; + UDF_I_LOCATION(inode).logicalBlockNum = block; + UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum; + inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0); + inode->i_blksize = PAGE_SIZE; + inode->i_blocks = 0; + inode->i_size = 0; + UDF_I_LENEATTR(inode) = 0; + UDF_I_LENALLOC(inode) = 0; + UDF_I_EXT0LOC(inode) = UDF_I_LOCATION(inode); + UDF_I_EXT0LEN(inode) = 0; +#if 1 + UDF_I_EXT0OFFS(inode) = sizeof(struct FileEntry); + UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_IN_ICB; +#else + UDF_I_EXT0OFFS(inode) = 0; + UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG; +#endif + + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + UDF_I_UMTIME(inode) = UDF_I_UATIME(inode) = UDF_I_UCTIME(inode) = CURRENT_UTIME; + inode->i_op = NULL; + insert_inode_hash(inode); + mark_inode_dirty(inode); + unlock_super(sb); + *err = 0; + return inode; +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/inode.c linux/fs/udf/inode.c --- v2.3.16/linux/fs/udf/inode.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/inode.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,1944 @@ +/* + * inode.c + * + * PURPOSE + * Inode handling routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1998 Dave Boynton + * (C) 1998-1999 Ben Fennema + * (C) 1999 Stelias Computing Inc + * + * HISTORY + * + * 10/04/98 dgb Added rudimentary directory functions + * 10/07/98 Fully working udf_block_map! It works! + * 11/25/98 bmap altered to better support extents + * 12/06/98 blf partition support in udf_iget, udf_block_map and udf_read_inode + * 12/12/98 rewrote udf_block_map to handle next extents and descs across + * block boundaries (which is not actually allowed) + * 12/20/98 added support for strategy 4096 + * 03/07/99 rewrote udf_block_map (again) + * New funcs, inode_bmap, udf_next_aext + * 04/19/99 Support for writing device EA's for major/minor # + * + */ + +#include "udfdecl.h" +#include +#include +#include + +#include "udf_i.h" +#include "udf_sb.h" + +#define EXTENT_MERGE_SIZE 5 + +static mode_t udf_convert_permissions(struct FileEntry *); +static int udf_update_inode(struct inode *, int); +static void udf_fill_inode(struct inode *, struct buffer_head *); +static struct buffer_head *inode_getblk(struct inode *, long, int *, long *, int *); +static void udf_split_extents(struct inode *, int *, int, int, + long_ad [EXTENT_MERGE_SIZE], int *); +static void udf_prealloc_extents(struct inode *, int, int, + long_ad [EXTENT_MERGE_SIZE], int *); +static void udf_merge_extents(struct inode *, + long_ad [EXTENT_MERGE_SIZE], int *); +static void udf_update_extents(struct inode *, + long_ad [EXTENT_MERGE_SIZE], int, int, + lb_addr, Uint32, struct buffer_head **); + +static DECLARE_MUTEX(read_semaphore); + +/* + * udf_put_inode + * + * PURPOSE + * + * DESCRIPTION + * This routine is called whenever the kernel no longer needs the inode. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + * + * Called at each iput() + */ +void udf_put_inode(struct inode * inode) +{ + udf_discard_prealloc(inode); +} + +/* + * udf_delete_inode + * + * PURPOSE + * Clean-up before the specified inode is destroyed. + * + * DESCRIPTION + * This routine is called when the kernel destroys an inode structure + * ie. when iput() finds i_count == 0. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + * + * Called at the last iput() if i_nlink is zero. + */ +void udf_delete_inode(struct inode * inode) +{ + inode->i_size = 0; + if (inode->i_blocks) + udf_truncate(inode); + udf_free_inode(inode); +} + +void udf_discard_prealloc(struct inode * inode) +{ +#ifdef UDF_PREALLOCATE +#if 0 + unsigned short total; + lb_addr loc = UDF_I_LOCATION(inode); + + if (UDF_I_PREALLOC_COUNT(inode)) + { + total = UDF_I_PREALLOC_COUNT(inode); + UDF_I_PREALLOC_COUNT(inode) = 0; + loc.logicalBlockNum = UDF_I_PREALLOC_BLOCK(inode); + udf_free_blocks(inode, loc, 0, total); + } +#endif +#endif +} + +static int udf_alloc_block(struct inode *inode, Uint16 partition, + Uint32 goal, int *err) +{ + int result = 0; + wait_on_super(inode->i_sb); + + result = udf_new_block(inode, partition, goal, err); + + return result; +} + +struct buffer_head * udf_expand_adinicb(struct inode *inode, int *block, int isdir, int *err) +{ + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) + { + long_ad newad; + int newblock; + struct buffer_head *sbh = NULL, *dbh = NULL; + + if (!UDF_I_LENALLOC(inode)) + { + UDF_I_EXT0OFFS(inode) = 0; + UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG; + return NULL; + } + + /* alloc block, and copy data to it */ + *block = udf_alloc_block(inode, + UDF_I_LOCATION(inode).partitionReferenceNum, + UDF_I_LOCATION(inode).logicalBlockNum, err); + + if (!(*block)) + return NULL; + newblock = udf_get_pblock(inode->i_sb, *block, + UDF_I_LOCATION(inode).partitionReferenceNum, 0); + if (!newblock) + return NULL; + sbh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize); + if (!sbh) + return NULL; + dbh = udf_tread(inode->i_sb, newblock, inode->i_sb->s_blocksize); + if (!dbh) + return NULL; + + if (isdir) + { + struct udf_fileident_bh sfibh, dfibh; + int f_pos = UDF_I_EXT0OFFS(inode) >> 2; + int size = (UDF_I_EXT0OFFS(inode) + inode->i_size) >> 2; + struct FileIdentDesc cfi, *sfi, *dfi; + + sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2; + sfibh.sbh = sfibh.ebh = sbh; + dfibh.soffset = dfibh.eoffset = 0; + dfibh.sbh = dfibh.ebh = dbh; + while ( (f_pos < size) ) + { + sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL); + if (!sfi) + { + udf_release_data(sbh); + udf_release_data(dbh); + return NULL; + } + sfi->descTag.tagLocation = *block; + dfibh.soffset = dfibh.eoffset; + dfibh.eoffset += (sfibh.eoffset - sfibh.soffset); + dfi = (struct FileIdentDesc *)(dbh->b_data + dfibh.soffset); + if (udf_write_fi(sfi, dfi, &dfibh, sfi->impUse, + sfi->fileIdent + sfi->lengthOfImpUse)) + { + udf_release_data(sbh); + udf_release_data(dbh); + return NULL; + } + } + } + else + { + memcpy(dbh->b_data, sbh->b_data + udf_file_entry_alloc_offset(inode), + UDF_I_LENALLOC(inode)); + } + mark_buffer_dirty(dbh, 1); + + memset(sbh->b_data + udf_file_entry_alloc_offset(inode), + 0, UDF_I_LENALLOC(inode)); + + newad.extLength = UDF_I_EXT0LEN(inode) = inode->i_size; + newad.extLocation.logicalBlockNum = *block; + newad.extLocation.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; + UDF_I_EXT0LOC(inode) = newad.extLocation; + /* UniqueID stuff */ + + memcpy(sbh->b_data + udf_file_entry_alloc_offset(inode), + &newad, sizeof(newad)); + + UDF_I_LENALLOC(inode) = sizeof(newad); + UDF_I_EXT0OFFS(inode) = 0; + UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG; + inode->i_blocks += inode->i_sb->s_blocksize / 512; + udf_release_data(sbh); + mark_inode_dirty(inode); + inode->i_version ++; + if (inode->i_op == &udf_file_inode_operations_adinicb) + inode->i_op = &udf_file_inode_operations; + return dbh; + } + else + return NULL; +} + +struct buffer_head * udf_getblk(struct inode * inode, long block, + int create, int * err) +{ + struct buffer_head dummy; + int error; + + dummy.b_state = 0; + dummy.b_blocknr = -1000; + error = udf_get_block(inode, block, &dummy, create); + *err = error; + if (!error & buffer_mapped(&dummy)) + { + struct buffer_head *bh; + bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize); + if (buffer_new(&dummy)) + { + memset(bh->b_data, 0, inode->i_sb->s_blocksize); + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh, 1); + } + return bh; + } + return NULL; +} + +int udf_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create) +{ + int err, new; + struct buffer_head *bh; + unsigned long phys; + + if (!create) + { + phys = udf_block_map(inode, block); + if (phys) + { + bh_result->b_dev = inode->i_dev; + bh_result->b_blocknr = phys; + bh_result->b_state |= (1UL << BH_Mapped); + } + return 0; + } + + err = -EIO; + + lock_kernel(); + + if (block < 0) + goto abort_negative; + + if (block == UDF_I_NEXT_ALLOC_BLOCK(inode) + 1) + { + UDF_I_NEXT_ALLOC_BLOCK(inode) ++; + UDF_I_NEXT_ALLOC_GOAL(inode) ++; + } + + err = 0; + + bh = inode_getblk(inode, block, &err, &phys, &new); + if (bh) + BUG(); + if (err) + goto abort; + if (!phys) + BUG(); + + bh_result->b_dev = inode->i_dev; + bh_result->b_blocknr = phys; + bh_result->b_state |= (1UL << BH_Mapped); + if (new) + bh_result->b_state |= (1UL << BH_New); +abort: + unlock_kernel(); + return err; + +abort_negative: + udf_warning(inode->i_sb, "udf_get_block", "block < 0"); + goto abort; +} + +static struct buffer_head * inode_getblk(struct inode * inode, long block, + int *err, long *phys, int *new) +{ + struct buffer_head *pbh = NULL, *cbh = NULL, *result = NULL; + long_ad laarr[EXTENT_MERGE_SIZE]; + Uint32 pextoffset = 0, cextoffset = 0, nextoffset = 0; + int count = 0, startnum = 0, endnum = 0; + Uint32 elen = 0; + lb_addr eloc, pbloc = UDF_I_LOCATION(inode), cbloc = UDF_I_LOCATION(inode); + int c = 1; + int lbcount = 0, b_off = 0, offset = 0; + Uint32 newblocknum, newblock; + char etype; + int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum; + char lastblock = 0; + + pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode); + b_off = block << inode->i_sb->s_blocksize_bits; + pbloc = cbloc = UDF_I_LOCATION(inode); + + /* find the extent which contains the block we are looking for. + alternate between laarr[0] and laarr[1] for locations of the + current extent, and the previous extent */ + do + { + if (pbh != cbh) + { + udf_release_data(pbh); + atomic_inc(&cbh->b_count); + pbloc = cbloc; + } + + lbcount += elen; + + pextoffset = cextoffset; + cextoffset = nextoffset; + + if ((etype = udf_next_aext(inode, &cbloc, &nextoffset, &eloc, &elen, &cbh, 1)) == -1) + break; + + c = !c; + + laarr[c].extLength = (etype << 30) | elen; + laarr[c].extLocation = eloc; + + if (etype != EXTENT_NOT_RECORDED_NOT_ALLOCATED) + pgoal = eloc.logicalBlockNum + + ((elen + inode->i_sb->s_blocksize - 1) >> + inode->i_sb->s_blocksize); + + count ++; + } while (lbcount + elen <= b_off); + + b_off -= lbcount; + offset = b_off >> inode->i_sb->s_blocksize_bits; + + /* if the extent is allocated and recorded, return the block + if the extent is not a multiple of the blocksize, round up */ + + if (etype == EXTENT_RECORDED_ALLOCATED) + { + if (elen & (inode->i_sb->s_blocksize - 1)) + { + elen = (EXTENT_RECORDED_ALLOCATED << 30) | + ((elen + inode->i_sb->s_blocksize - 1) & + ~(inode->i_sb->s_blocksize - 1)); + etype = udf_write_aext(inode, cbloc, &cextoffset, eloc, elen, &cbh, 1); + } + udf_release_data(pbh); + udf_release_data(cbh); + newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset); + *phys = newblock; + return NULL; + } + + if (etype == -1) + { + endnum = startnum = ((count > 1) ? 1 : count); + c = !c; + laarr[c].extLength = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) | + ((offset + 1) << inode->i_sb->s_blocksize_bits); + memset(&laarr[c].extLocation, 0x00, sizeof(lb_addr)); + count ++; + endnum ++; + lastblock = 1; + } + else + endnum = startnum = ((count > 2) ? 2 : count); + + /* if the current extent is in position 0, swap it with the previous */ + if (!c && count != 1) + { + laarr[2] = laarr[0]; + laarr[0] = laarr[1]; + laarr[1] = laarr[2]; + c = 1; + } + + /* if the current block is located in a extent, read the next extent */ + if (etype != -1) + { + if ((etype = udf_next_aext(inode, &cbloc, &nextoffset, &eloc, &elen, &cbh, 0)) != -1) + { + laarr[c+1].extLength = (etype << 30) | elen; + laarr[c+1].extLocation = eloc; + count ++; + startnum ++; + endnum ++; + } + else + lastblock = 1; + } + udf_release_data(cbh); + + *err = -EFBIG; + + /* Check file limits.. */ + { + unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; + if (limit < RLIM_INFINITY) + { + limit >>= inode->i_sb->s_blocksize_bits; + if (block >= limit) + { + send_sig(SIGXFSZ, current, 0); + *err = -EFBIG; + return NULL; + } + } + } + + /* if the current extent is not recorded but allocated, get the + block in the extent corresponding to the requested block */ + if ((laarr[c].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) + newblocknum = laarr[c].extLocation.logicalBlockNum + offset; + else /* otherwise, allocate a new block */ + { + if (UDF_I_NEXT_ALLOC_BLOCK(inode) == block) + goal = UDF_I_NEXT_ALLOC_GOAL(inode); + + if (!goal) + { + if (!(goal = pgoal)) + goal = UDF_I_LOCATION(inode).logicalBlockNum + 1; + } + + if (!(newblocknum = udf_alloc_block(inode, + UDF_I_LOCATION(inode).partitionReferenceNum, goal, err))) + { + udf_release_data(pbh); + udf_release_data(cbh); + *err = -ENOSPC; + return NULL; + } + } + + /* if the extent the requsted block is located in contains multiple blocks, + split the extent into at most three extents. blocks prior to requested + block, requested block, and blocks after requested block */ + udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum); + +#ifdef UDF_PREALLOCATE + /* preallocate blocks */ + udf_prealloc_extents(inode, c, lastblock, laarr, &endnum); +#endif + + /* merge any continuous blocks in laarr */ + udf_merge_extents(inode, laarr, &endnum); + + /* write back the new extents, inserting new extents if the new number + of extents is greater than the old number, and deleting extents if + the new number of extents is less than the old number */ + udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh); + + udf_release_data(pbh); + + if (c == 0 || c == 1) + { + UDF_I_EXT0LEN(inode) = laarr[0].extLength; + UDF_I_EXT0LOC(inode) = laarr[0].extLocation; + } + + if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum, + UDF_I_LOCATION(inode).partitionReferenceNum, 0))) + { + return NULL; + } + *phys = newblock; + *err = 0; + *new = 1; + UDF_I_NEXT_ALLOC_BLOCK(inode) = block; + UDF_I_NEXT_ALLOC_GOAL(inode) = newblocknum; + inode->i_ctime = CURRENT_TIME; + UDF_I_UCTIME(inode) = CURRENT_UTIME; + inode->i_blocks += inode->i_sb->s_blocksize / 512; +#if 0 + if (IS_SYNC(inode) || UDF_I_OSYNC(inode)) + udf_sync_inode(inode); + else +#endif + mark_inode_dirty(inode); + return result; +} + +static void udf_split_extents(struct inode *inode, int *c, int offset, int newblocknum, + long_ad laarr[EXTENT_MERGE_SIZE], int *endnum) +{ + if ((laarr[*c].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED || + (laarr[*c].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) + { + int curr = *c; + int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; + int type = laarr[curr].extLength & ~UDF_EXTENT_LENGTH_MASK; + + if (blen == 1) + ; + else if (!offset || blen == offset + 1) + { + laarr[curr+2] = laarr[curr+1]; + laarr[curr+1] = laarr[curr]; + } + else + { + laarr[curr+3] = laarr[curr+1]; + laarr[curr+2] = laarr[curr+1] = laarr[curr]; + } + + if (offset) + { + laarr[curr].extLength = type | + (offset << inode->i_sb->s_blocksize_bits); + curr ++; + (*c) ++; + (*endnum) ++; + } + + laarr[curr].extLocation.logicalBlockNum = newblocknum; + if ((type >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) + laarr[curr].extLocation.partitionReferenceNum = + UDF_I_LOCATION(inode).partitionReferenceNum; + laarr[curr].extLength = (EXTENT_RECORDED_ALLOCATED << 30) | + inode->i_sb->s_blocksize; + curr ++; + + if (blen != offset + 1) + { + if ((type >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) + laarr[curr].extLocation.logicalBlockNum += (offset + 1); + laarr[curr].extLength = type | + ((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits); + curr ++; + (*endnum) ++; + } + } +} + +static void udf_prealloc_extents(struct inode *inode, int c, int lastblock, + long_ad laarr[EXTENT_MERGE_SIZE], int *endnum) +{ + int start, length = 0, currlength = 0, i; + + if (*endnum == (c+1) && !lastblock) + return; + + if ((laarr[c+1].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) + { + start = c+1; + length = currlength = (((laarr[c+1].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits); + } + else + start = c; + + for (i=start+1; i<=*endnum; i++) + { + if (i == *endnum) + { + if (lastblock) + length += UDF_DEFAULT_PREALLOC_BLOCKS; + } + else if ((laarr[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) + length += (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits); + else + break; + } + + if (length) + { + int next = laarr[start].extLocation.logicalBlockNum + + (((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits); + int numalloc = udf_alloc_blocks(inode, + laarr[start].extLocation.partitionReferenceNum, + next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length : + UDF_DEFAULT_PREALLOC_BLOCKS) - currlength); + + if (numalloc) + { + if (start == (c+1)) + laarr[start].extLength += + (numalloc << inode->i_sb->s_blocksize_bits); + else + { + memmove(&laarr[c+2], &laarr[c+1], + sizeof(long_ad) * (*endnum - (c+1))); + (*endnum) ++; + laarr[c+1].extLocation.logicalBlockNum = next; + laarr[c+1].extLocation.partitionReferenceNum = + laarr[c].extLocation.partitionReferenceNum; + laarr[c+1].extLength = (EXTENT_NOT_RECORDED_ALLOCATED << 30) | + (numalloc << inode->i_sb->s_blocksize_bits); + start = c+1; + } + + for (i=start+1; numalloc && i<*endnum; i++) + { + int elen = ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; + + if (elen > numalloc) + { + laarr[c+1].extLength -= + (numalloc << inode->i_sb->s_blocksize_bits); + numalloc = 0; + } + else + { + numalloc -= elen; + if (*endnum > (i+1)) + memmove(&laarr[i], &laarr[i+1], + sizeof(long_ad) * (*endnum - (i+1))); + i --; + (*endnum) --; + } + } + } + } +} + +static void udf_merge_extents(struct inode *inode, + long_ad laarr[EXTENT_MERGE_SIZE], int *endnum) +{ + int i; + + for (i=0; i<(*endnum-1); i++) + { + if ((laarr[i].extLength >> 30) == (laarr[i+1].extLength >> 30)) + { + if (((laarr[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) || + ((laarr[i+1].extLocation.logicalBlockNum - laarr[i].extLocation.logicalBlockNum) == + (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits))) + { + laarr[i].extLength = laarr[i+1].extLength + + (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1)); + if (*endnum > (i+2)) + memmove(&laarr[i+1], &laarr[i+2], + sizeof(long_ad) * (*endnum - (i+2))); + i --; + (*endnum) --; + } + } + } +} + +static void udf_update_extents(struct inode *inode, + long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum, + lb_addr pbloc, Uint32 pextoffset, struct buffer_head **pbh) +{ + int start = 0, i; + lb_addr tmploc; + Uint32 tmplen; + + if (startnum > endnum) + { + for (i=0; i<(startnum-endnum); i++) + { + udf_delete_aext(inode, pbloc, pextoffset, laarr[i].extLocation, + laarr[i].extLength, *pbh); + } + } + else if (startnum < endnum) + { + for (i=0; i<(endnum-startnum); i++) + { + udf_insert_aext(inode, pbloc, pextoffset, laarr[i].extLocation, + laarr[i].extLength, *pbh); + udf_next_aext(inode, &pbloc, &pextoffset, &laarr[i].extLocation, + &laarr[i].extLength, pbh, 1); + start ++; + } + } + + for (i=start; ii_blocks; + + bh = udf_getblk(inode, block, create, err); + if (!bh) + return NULL; + +#if 0 + if (create && + S_ISDIR(inode->i_mode) && + inode->i_blocks > prev_blocks) + { + int i; + struct buffer_head *tmp_bh = NULL; + + for (i=1; + i < UDF_DEFAULT_PREALLOC_DIR_BLOCKS; + i++) + { + tmp_bh = udf_getblk(inode, block+i, create, err); + if (!tmp_bh) + { + udf_release_data(bh); + return 0; + } + udf_release_data(tmp_bh); + } + } +#endif + + if (buffer_uptodate(bh)) + return bh; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (buffer_uptodate(bh)) + return bh; + brelse(bh); + *err = -EIO; + return NULL; +} + +/* + * udf_read_inode + * + * PURPOSE + * Read an inode. + * + * DESCRIPTION + * This routine is called by iget() [which is called by udf_iget()] + * (clean_inode() will have been called first) + * when an inode is first read into memory. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + * + * 12/19/98 dgb Updated to fix size problems. + */ +void +udf_read_inode(struct inode *inode) +{ + struct buffer_head *bh = NULL; + struct FileEntry *fe; + Uint16 ident; + + /* + * Set defaults, but the inode is still incomplete! + * Note: get_new_inode() sets the following on a new inode: + * i_sb = sb + * i_dev = sb->s_dev; + * i_no = ino + * i_flags = sb->s_flags + * i_state = 0 + * clean_inode(): zero fills and sets + * i_count = 1 + * i_nlink = 1 + * i_op = NULL; + */ + + inode->i_blksize = inode->i_sb->s_blocksize; + inode->i_version = 1; + + UDF_I_EXT0LEN(inode)=0; + UDF_I_EXT0LOC(inode).logicalBlockNum = 0xFFFFFFFF; + UDF_I_EXT0LOC(inode).partitionReferenceNum = 0xFFFF; + UDF_I_EXT0OFFS(inode)=0; + UDF_I_ALLOCTYPE(inode)=0; + + memcpy(&UDF_I_LOCATION(inode), &UDF_SB_LOCATION(inode->i_sb), sizeof(lb_addr)); + + bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident); + + if (!bh) + { + printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed !bh\n", + inode->i_ino); + make_bad_inode(inode); + return; + } + + if (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY) + { + printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n", + inode->i_ino, ident); + udf_release_data(bh); + make_bad_inode(inode); + return; + } + + fe = (struct FileEntry *)bh->b_data; + + if (le16_to_cpu(fe->icbTag.strategyType) == 4096) + { + struct buffer_head *ibh = NULL, *nbh = NULL; + struct IndirectEntry *ie; + + ibh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 1, &ident); + if (ident == TID_INDIRECT_ENTRY) + { + if (ibh) + { + lb_addr loc; + ie = (struct IndirectEntry *)ibh->b_data; + + loc = lelb_to_cpu(ie->indirectICB.extLocation); + + if (ie->indirectICB.extLength && + (nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident))) + { + if (ident == TID_FILE_ENTRY || + ident == TID_EXTENDED_FILE_ENTRY) + { + memcpy(&UDF_SB_LOCATION(inode->i_sb), &loc, sizeof(lb_addr)); + udf_release_data(bh); + udf_release_data(ibh); + udf_release_data(nbh); + udf_read_inode(inode); + return; + } + else + { + udf_release_data(nbh); + udf_release_data(ibh); + } + } + else + udf_release_data(ibh); + } + } + else + udf_release_data(ibh); + } + else if (le16_to_cpu(fe->icbTag.strategyType) != 4) + { + printk(KERN_ERR "udf: unsupported strategy type: %d\n", + le16_to_cpu(fe->icbTag.strategyType)); + udf_release_data(bh); + make_bad_inode(inode); + return; + } + udf_fill_inode(inode, bh); + udf_release_data(bh); +} + +static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) +{ + struct FileEntry *fe; + struct ExtendedFileEntry *efe; + time_t convtime; + int offset, alen; + + fe = (struct FileEntry *)bh->b_data; + efe = (struct ExtendedFileEntry *)bh->b_data; + + if (fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY) + UDF_I_EXTENDED_FE(inode) = 1; + else /* fe->descTag.tagIdent == TID_FILE_ENTRY */ + UDF_I_EXTENDED_FE(inode) = 0; + + if (le16_to_cpu(fe->icbTag.strategyType) == 4) + UDF_I_STRAT4096(inode) = 0; + else /* if (le16_to_cpu(fe->icbTag.strategyType) == 4096) */ + UDF_I_STRAT4096(inode) = 1; + + inode->i_uid = udf_convert_uid(le32_to_cpu(fe->uid)); + if ( !inode->i_uid ) inode->i_uid = UDF_SB(inode->i_sb)->s_uid; + + inode->i_gid = udf_convert_gid(le32_to_cpu(fe->gid)); + if ( !inode->i_gid ) inode->i_gid = UDF_SB(inode->i_sb)->s_gid; + + inode->i_nlink = le16_to_cpu(fe->fileLinkCount); + if (!inode->i_nlink) + inode->i_nlink = 1; + + inode->i_size = le64_to_cpu(fe->informationLength); +#if BITS_PER_LONG < 64 + if (le64_to_cpu(fe->informationLength) & 0xFFFFFFFF00000000) + inode->i_size = (Uint32)-1; +#endif + + inode->i_mode = udf_convert_permissions(fe); + inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask; + +#ifdef UDF_PREALLOCATE +#if 0 + UDF_I_PREALLOC_BLOCK(inode) = 0; + UDF_I_PREALLOC_COUNT(inode) = 0; +#endif +#endif + UDF_I_NEXT_ALLOC_BLOCK(inode) = 0; + UDF_I_NEXT_ALLOC_GOAL(inode) = 0; + + UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICB_FLAG_ALLOC_MASK; + + if (UDF_I_EXTENDED_FE(inode) == 0) + { + inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << + (inode->i_sb->s_blocksize_bits - 9); + + if ( udf_stamp_to_time(&convtime, lets_to_cpu(fe->modificationTime)) ) + { + inode->i_mtime = convtime; + inode->i_ctime = convtime; + } + else + { + inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb); + inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb); + } + + if ( udf_stamp_to_time(&convtime, lets_to_cpu(fe->accessTime)) ) + inode->i_atime = convtime; + else + inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb); + + UDF_I_UNIQUE(inode) = le64_to_cpu(fe->uniqueID); + UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr); + UDF_I_LENALLOC(inode) = le32_to_cpu(fe->lengthAllocDescs); + offset = sizeof(struct FileEntry) + UDF_I_LENEATTR(inode); + alen = offset + UDF_I_LENALLOC(inode); + } + else + { + inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << + (inode->i_sb->s_blocksize_bits - 9); + + if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->modificationTime)) ) + inode->i_mtime = convtime; + else + inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb); + + if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->accessTime)) ) + inode->i_atime = convtime; + else + inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb); + + if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->createTime)) ) + inode->i_ctime = convtime; + else + inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb); + + UDF_I_UNIQUE(inode) = le64_to_cpu(efe->uniqueID); + UDF_I_LENEATTR(inode) = le32_to_cpu(efe->lengthExtendedAttr); + UDF_I_LENALLOC(inode) = le32_to_cpu(efe->lengthAllocDescs); + offset = sizeof(struct ExtendedFileEntry) + UDF_I_LENEATTR(inode); + alen = offset + UDF_I_LENALLOC(inode); + } + + switch (UDF_I_ALLOCTYPE(inode)) + { + case ICB_FLAG_AD_SHORT: + { + short_ad * sa; + + sa = udf_get_fileshortad(fe, alen, &offset, 1); + if (sa) + { + UDF_I_EXT0LEN(inode) = le32_to_cpu(sa->extLength); + UDF_I_EXT0LOC(inode).logicalBlockNum = le32_to_cpu(sa->extPosition); + UDF_I_EXT0LOC(inode).partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; + } + break; + } + case ICB_FLAG_AD_LONG: + { + long_ad * la; + + la = udf_get_filelongad(fe, alen, &offset, 1); + if (la) + { + UDF_I_EXT0LEN(inode) = le32_to_cpu(la->extLength); + UDF_I_EXT0LOC(inode).logicalBlockNum = le32_to_cpu(la->extLocation.logicalBlockNum); + UDF_I_EXT0LOC(inode).partitionReferenceNum = le16_to_cpu(la->extLocation.partitionReferenceNum); + } + break; + } + case ICB_FLAG_AD_EXTENDED: + { + extent_ad * ext; + + ext = udf_get_fileextent(fe, alen, &offset); + if ( (ext) && (ext->extLength) ) + { + UDF_I_EXT0LEN(inode) = le32_to_cpu(ext->extLength); +#if 0 + UDF_I_EXT0LOC(inode) = ext->extLocation; +#endif + } + break; + } + case ICB_FLAG_AD_IN_ICB: /* short directories */ + { + UDF_I_EXT0LEN(inode) = le32_to_cpu(fe->lengthAllocDescs); + UDF_I_EXT0LOC(inode) = UDF_I_LOCATION(inode); + UDF_I_EXT0OFFS(inode) = sizeof(struct FileEntry) + + le32_to_cpu(fe->lengthExtendedAttr); + break; + } + } /* end switch ad_type */ + + switch (fe->icbTag.fileType) + { + case FILE_TYPE_DIRECTORY: + { + inode->i_op = &udf_dir_inode_operations; + inode->i_mode |= S_IFDIR; + inode->i_nlink ++; + break; + } + case FILE_TYPE_REGULAR: + case FILE_TYPE_NONE: + { + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) + inode->i_op = &udf_file_inode_operations_adinicb; + else + inode->i_op = &udf_file_inode_operations; + inode->i_mode |= S_IFREG; + break; + } + case FILE_TYPE_BLOCK: + { + inode->i_op = &blkdev_inode_operations; + inode->i_mode |= S_IFBLK; + break; + } + case FILE_TYPE_CHAR: + { + inode->i_op = &chrdev_inode_operations; + inode->i_mode |= S_IFCHR; + break; + } + case FILE_TYPE_FIFO: + { + init_fifo(inode); + } + case FILE_TYPE_SYMLINK: + { + /* untested! */ + inode->i_op = &udf_symlink_inode_operations; + inode->i_mode = S_IFLNK|S_IRWXUGO; + break; + } + default: + { + printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n", + inode->i_ino, fe->icbTag.fileType); + make_bad_inode(inode); + return; + } + } + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + { + struct buffer_head *tbh = NULL; + struct DeviceSpecificationExtendedAttr *dsea = + (struct DeviceSpecificationExtendedAttr *) + udf_get_extendedattr(inode, 12, 1, &tbh); + + if (dsea) + { + inode->i_rdev = to_kdev_t( + (le32_to_cpu(dsea->majorDeviceIdent)) << 8) | + (le32_to_cpu(dsea->minorDeviceIdent) & 0xFF); + /* Developer ID ??? */ + udf_release_data(tbh); + } + else + { + make_bad_inode(inode); + } + } +} + +static mode_t +udf_convert_permissions(struct FileEntry *fe) +{ + mode_t mode; + Uint32 permissions; + Uint32 flags; + + permissions = le32_to_cpu(fe->permissions); + flags = le16_to_cpu(fe->icbTag.flags); + + mode = (( permissions ) & S_IRWXO) | + (( permissions >> 2 ) & S_IRWXG) | + (( permissions >> 4 ) & S_IRWXU) | + (( flags & ICB_FLAG_SETUID) ? S_ISUID : 0) | + (( flags & ICB_FLAG_SETGID) ? S_ISGID : 0) | + (( flags & ICB_FLAG_STICKY) ? S_ISVTX : 0); + + return mode; +} + +/* + * udf_write_inode + * + * PURPOSE + * Write out the specified inode. + * + * DESCRIPTION + * This routine is called whenever an inode is synced. + * Currently this routine is just a placeholder. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ + +void udf_write_inode(struct inode * inode) +{ + udf_update_inode(inode, 0); +} + +int udf_sync_inode(struct inode * inode) +{ + return udf_update_inode(inode, 1); +} + +static int +udf_update_inode(struct inode *inode, int do_sync) +{ + struct buffer_head *bh = NULL; + struct FileEntry *fe; + struct ExtendedFileEntry *efe; + Uint32 udfperms; + Uint16 icbflags; + Uint16 crclen; + int i; + timestamp cpu_time; + int err = 0; + + bh = udf_tread(inode->i_sb, + udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0), + inode->i_sb->s_blocksize); + if (!bh) + { + udf_debug("bread failure\n"); + return -EIO; + } + fe = (struct FileEntry *)bh->b_data; + efe = (struct ExtendedFileEntry *)bh->b_data; + + if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid) + fe->uid = cpu_to_le32(inode->i_uid); + + if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid) + fe->gid = cpu_to_le32(inode->i_gid); + + udfperms = ((inode->i_mode & S_IRWXO) ) | + ((inode->i_mode & S_IRWXG) << 2) | + ((inode->i_mode & S_IRWXU) << 4); + + udfperms |= (le32_to_cpu(fe->permissions) & + (PERM_O_DELETE | PERM_O_CHATTR | + PERM_G_DELETE | PERM_G_CHATTR | + PERM_U_DELETE | PERM_U_CHATTR)); + fe->permissions = cpu_to_le32(udfperms); + + if (S_ISDIR(inode->i_mode)) + fe->fileLinkCount = cpu_to_le16(inode->i_nlink - 1); + else + fe->fileLinkCount = cpu_to_le16(inode->i_nlink); + + + fe->informationLength = cpu_to_le64(inode->i_size); + + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + { + EntityID *eid; + struct buffer_head *tbh = NULL; + struct DeviceSpecificationExtendedAttr *dsea = + (struct DeviceSpecificationExtendedAttr *) + udf_get_extendedattr(inode, 12, 1, &tbh); + + if (!dsea) + { + dsea = (struct DeviceSpecificationExtendedAttr *) + udf_add_extendedattr(inode, + sizeof(struct DeviceSpecificationExtendedAttr) + + sizeof(EntityID), 12, 0x3, &tbh); + dsea->attrType = 12; + dsea->attrSubtype = 1; + dsea->attrLength = sizeof(struct DeviceSpecificationExtendedAttr) + + sizeof(EntityID); + dsea->impUseLength = sizeof(EntityID); + } + eid = (EntityID *)dsea->impUse; + memset(eid, 0, sizeof(EntityID)); + strcpy(eid->ident, UDF_ID_DEVELOPER); + eid->identSuffix[0] = UDF_OS_CLASS_UNIX; + eid->identSuffix[1] = UDF_OS_ID_LINUX; + dsea->majorDeviceIdent = kdev_t_to_nr(inode->i_rdev) >> 8; + dsea->minorDeviceIdent = kdev_t_to_nr(inode->i_rdev) & 0xFF; + mark_buffer_dirty(tbh, 1); + udf_release_data(tbh); + } + + if (UDF_I_EXTENDED_FE(inode) == 0) + { + fe->logicalBlocksRecorded = cpu_to_le64( + (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >> + (inode->i_sb->s_blocksize_bits - 9)); + + if (udf_time_to_stamp(&cpu_time, inode->i_atime, UDF_I_UATIME(inode))) + fe->accessTime = cpu_to_lets(cpu_time); + if (udf_time_to_stamp(&cpu_time, inode->i_mtime, UDF_I_UMTIME(inode))) + fe->modificationTime = cpu_to_lets(cpu_time); + memset(&(fe->impIdent), 0, sizeof(EntityID)); + strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER); + fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; + fe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; + fe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode)); + fe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode)); + fe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode)); + fe->descTag.tagIdent = le16_to_cpu(TID_FILE_ENTRY); + crclen = sizeof(struct FileEntry); + } + else + { + efe->logicalBlocksRecorded = cpu_to_le64( + (inode->i_blocks + (2 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >> + (inode->i_sb->s_blocksize_bits - 9)); + + if (udf_time_to_stamp(&cpu_time, inode->i_atime, UDF_I_UATIME(inode))) + efe->accessTime = cpu_to_lets(cpu_time); + if (udf_time_to_stamp(&cpu_time, inode->i_mtime, UDF_I_UMTIME(inode))) + efe->modificationTime = cpu_to_lets(cpu_time); + if (udf_time_to_stamp(&cpu_time, inode->i_ctime, UDF_I_UCTIME(inode))) + efe->createTime = cpu_to_lets(cpu_time); + memset(&(efe->impIdent), 0, sizeof(EntityID)); + strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER); + efe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; + efe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; + efe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode)); + efe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode)); + efe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode)); + efe->descTag.tagIdent = le16_to_cpu(TID_EXTENDED_FILE_ENTRY); + crclen = sizeof(struct ExtendedFileEntry); + } + fe->icbTag.strategyType = UDF_I_STRAT4096(inode) ? cpu_to_le16(4096) : + cpu_to_le16(4); + + if (S_ISDIR(inode->i_mode)) + fe->icbTag.fileType = FILE_TYPE_DIRECTORY; + else if (S_ISREG(inode->i_mode)) + fe->icbTag.fileType = FILE_TYPE_REGULAR; + else if (S_ISLNK(inode->i_mode)) + fe->icbTag.fileType = FILE_TYPE_SYMLINK; + else if (S_ISBLK(inode->i_mode)) + fe->icbTag.fileType = FILE_TYPE_BLOCK; + else if (S_ISCHR(inode->i_mode)) + fe->icbTag.fileType = FILE_TYPE_CHAR; + else if (S_ISFIFO(inode->i_mode)) + fe->icbTag.fileType = FILE_TYPE_FIFO; + + icbflags = UDF_I_ALLOCTYPE(inode) | + ((inode->i_mode & S_ISUID) ? ICB_FLAG_SETUID : 0) | + ((inode->i_mode & S_ISGID) ? ICB_FLAG_SETGID : 0) | + ((inode->i_mode & S_ISVTX) ? ICB_FLAG_STICKY : 0) | + (le16_to_cpu(fe->icbTag.flags) & + ~(ICB_FLAG_ALLOC_MASK | ICB_FLAG_SETUID | + ICB_FLAG_SETGID | ICB_FLAG_STICKY)); + + fe->icbTag.flags = cpu_to_le16(icbflags); + fe->descTag.descVersion = cpu_to_le16(2); + fe->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb)); + fe->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum); + crclen += UDF_I_LENEATTR(inode) + UDF_I_LENALLOC(inode) - sizeof(tag); + fe->descTag.descCRCLength = cpu_to_le16(crclen); + fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), crclen, 0)); + + fe->descTag.tagChecksum = 0; + for (i=0; i<16; i++) + if (i != 4) + fe->descTag.tagChecksum += ((Uint8 *)&(fe->descTag))[i]; + + /* write the data blocks */ + mark_buffer_dirty(bh, 1); + if (do_sync) + { + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + if (buffer_req(bh) && !buffer_uptodate(bh)) + { + printk("IO error syncing udf inode [%s:%08lx]\n", + bdevname(inode->i_dev), inode->i_ino); + err = -EIO; + } + } + udf_release_data(bh); + return err; +} + +/* + * udf_iget + * + * PURPOSE + * Get an inode. + * + * DESCRIPTION + * This routine replaces iget() and read_inode(). + * + * HISTORY + * October 3, 1997 - Andrew E. Mileski + * Written, tested, and released. + * + * 12/19/98 dgb Added semaphore and changed to be a wrapper of iget + */ +struct inode * +udf_iget(struct super_block *sb, lb_addr ino) +{ + struct inode *inode; + unsigned long block; + + block = udf_get_lb_pblock(sb, ino, 0); + + down(&read_semaphore); /* serialize access to UDF_SB_LOCATION() */ + /* This is really icky.. should fix -- blf */ + + /* put the location where udf_read_inode can find it */ + memcpy(&UDF_SB_LOCATION(sb), &ino, sizeof(lb_addr)); + + /* Get the inode */ + + inode = iget(sb, block); + /* calls udf_read_inode() ! */ + + up(&read_semaphore); + + if (!inode) + { + printk(KERN_ERR "udf: iget() failed\n"); + return NULL; + } + else if (is_bad_inode(inode)) + { + iput(inode); + return NULL; + } + + if ( ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum) ) + { + udf_debug("block=%d, partition=%d out of range\n", + ino.logicalBlockNum, ino.partitionReferenceNum); + return NULL; + } + + return inode; +} + +int udf_add_aext(struct inode *inode, lb_addr *bloc, int *extoffset, + lb_addr eloc, Uint32 elen, struct buffer_head **bh, int inc) +{ + int adsize; + short_ad *sad = NULL; + long_ad *lad = NULL; + struct AllocExtDesc *aed; + int ret; + + if (!(*bh)) + { + if (!(*bh = udf_tread(inode->i_sb, + udf_get_lb_pblock(inode->i_sb, *bloc, 0), + inode->i_sb->s_blocksize))) + { + udf_debug("reading block %d failed!\n", + udf_get_lb_pblock(inode->i_sb, *bloc, 0)); + return -1; + } + } + + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT) + adsize = sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG) + adsize = sizeof(long_ad); + else + return -1; + + if (*extoffset + (2 * adsize) > inode->i_sb->s_blocksize) + { + char *sptr, *dptr; + struct buffer_head *nbh; + int err, loffset; + Uint32 lblock = bloc->logicalBlockNum; + Uint16 lpart = bloc->partitionReferenceNum; + + if (!(bloc->logicalBlockNum = udf_new_block(inode, + lpart, lblock, &err))) + { + return -1; + } + if (!(nbh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, + *bloc, 0), inode->i_sb->s_blocksize))) + { + return -1; + } + aed = (struct AllocExtDesc *)(nbh->b_data); + aed->previousAllocExtLocation = cpu_to_le32(lblock); + if (*extoffset + adsize > inode->i_sb->s_blocksize) + { + loffset = *extoffset; + aed->lengthAllocDescs = cpu_to_le32(adsize); + sptr = (*bh)->b_data + *extoffset - adsize; + dptr = nbh->b_data + sizeof(struct AllocExtDesc); + memcpy(dptr, sptr, adsize); + *extoffset = sizeof(struct AllocExtDesc) + adsize; + } + else + { + loffset = *extoffset + adsize; + aed->lengthAllocDescs = cpu_to_le32(0); + sptr = (*bh)->b_data + *extoffset; + *extoffset = sizeof(struct AllocExtDesc); + + if (UDF_I_LOCATION(inode).logicalBlockNum == lblock) + UDF_I_LENALLOC(inode) += adsize; + else + { + aed = (struct AllocExtDesc *)(*bh)->b_data; + aed->lengthAllocDescs = + cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); + } + } + udf_new_tag(nbh->b_data, TID_ALLOC_EXTENT_DESC, 2, 1, + bloc->logicalBlockNum, sizeof(tag)); + switch (UDF_I_ALLOCTYPE(inode)) + { + case ICB_FLAG_AD_SHORT: + { + sad = (short_ad *)sptr; + sad->extLength = EXTENT_NEXT_EXTENT_ALLOCDECS << 30 | + inode->i_sb->s_blocksize; + sad->extPosition = cpu_to_le32(bloc->logicalBlockNum); + break; + } + case ICB_FLAG_AD_LONG: + { + lad = (long_ad *)sptr; + lad->extLength = EXTENT_NEXT_EXTENT_ALLOCDECS << 30 | + inode->i_sb->s_blocksize; + lad->extLocation = cpu_to_lelb(*bloc); + break; + } + } + udf_update_tag((*bh)->b_data, loffset); + mark_buffer_dirty(*bh, 1); + udf_release_data(*bh); + *bh = nbh; + } + + ret = udf_write_aext(inode, *bloc, extoffset, eloc, elen, bh, inc); + + if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr))) + { + UDF_I_LENALLOC(inode) += adsize; + mark_inode_dirty(inode); + } + else + { + aed = (struct AllocExtDesc *)(*bh)->b_data; + aed->lengthAllocDescs = + cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); + udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize)); + mark_buffer_dirty(*bh, 1); + } + + return ret; +} + +int udf_write_aext(struct inode *inode, lb_addr bloc, int *extoffset, + lb_addr eloc, Uint32 elen, struct buffer_head **bh, int inc) +{ + int adsize; + short_ad *sad = NULL; + long_ad *lad = NULL; + + if (!(*bh)) + { + if (!(*bh = udf_tread(inode->i_sb, + udf_get_lb_pblock(inode->i_sb, bloc, 0), + inode->i_sb->s_blocksize))) + { + udf_debug("reading block %d failed!\n", + udf_get_lb_pblock(inode->i_sb, bloc, 0)); + return -1; + } + } + + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT) + adsize = sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG) + adsize = sizeof(long_ad); + else + return -1; + + switch (UDF_I_ALLOCTYPE(inode)) + { + case ICB_FLAG_AD_SHORT: + { + sad = (short_ad *)((*bh)->b_data + *extoffset); + sad->extLength = cpu_to_le32(elen); + sad->extPosition = cpu_to_le32(eloc.logicalBlockNum); + break; + } + case ICB_FLAG_AD_LONG: + { + lad = (long_ad *)((*bh)->b_data + *extoffset); + lad->extLength = cpu_to_le32(elen); + lad->extLocation = cpu_to_lelb(eloc); + break; + } + } + + if (memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) + { + struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data; + udf_update_tag((*bh)->b_data, + le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct AllocExtDesc)); + } + + mark_buffer_dirty(*bh, 1); + + if (inc) + *extoffset += adsize; + return (elen >> 30); +} + +int udf_next_aext(struct inode *inode, lb_addr *bloc, int *extoffset, + lb_addr *eloc, Uint32 *elen, struct buffer_head **bh, int inc) +{ + int pos, alen; + Uint8 etype; + + if (!(*bh)) + { + if (!(*bh = udf_tread(inode->i_sb, + udf_get_lb_pblock(inode->i_sb, *bloc, 0), + inode->i_sb->s_blocksize))) + { + udf_debug("reading block %d failed!\n", + udf_get_lb_pblock(inode->i_sb, *bloc, 0)); + return -1; + } + } + + if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr))) + { + pos = udf_file_entry_alloc_offset(inode); + alen = UDF_I_LENALLOC(inode) + pos; + } + else + { + struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data; + + pos = sizeof(struct AllocExtDesc); + alen = le32_to_cpu(aed->lengthAllocDescs) + pos; + } + + if (!(*extoffset)) + *extoffset = pos; + + switch (UDF_I_ALLOCTYPE(inode)) + { + case ICB_FLAG_AD_SHORT: + { + short_ad *sad; + + if (!(sad = udf_get_fileshortad((*bh)->b_data, alen, extoffset, inc))) + return -1; + + if ((etype = le32_to_cpu(sad->extLength) >> 30) == EXTENT_NEXT_EXTENT_ALLOCDECS) + { + bloc->logicalBlockNum = le32_to_cpu(sad->extPosition); + *extoffset = 0; + udf_release_data(*bh); + *bh = NULL; + return udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, inc); + } + else + { + eloc->logicalBlockNum = le32_to_cpu(sad->extPosition); + eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; + *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK; + } + break; + } + case ICB_FLAG_AD_LONG: + { + long_ad *lad; + + if (!(lad = udf_get_filelongad((*bh)->b_data, alen, extoffset, inc))) + return -1; + + if ((etype = le32_to_cpu(lad->extLength) >> 30) == EXTENT_NEXT_EXTENT_ALLOCDECS) + { + *bloc = lelb_to_cpu(lad->extLocation); + *extoffset = 0; + udf_release_data(*bh); + *bh = NULL; + return udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, inc); + } + else + { + *eloc = lelb_to_cpu(lad->extLocation); + *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK; + } + break; + } + default: + { + udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode)); + return -1; + } + } + if (*elen) + return etype; + + udf_debug("Empty Extent!\n"); + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT) + *extoffset -= sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG) + *extoffset -= sizeof(long_ad); + return -1; +} + +int udf_current_aext(struct inode *inode, lb_addr *bloc, int *extoffset, + lb_addr *eloc, Uint32 *elen, struct buffer_head **bh, int inc) +{ + int pos, alen; + Uint8 etype; + + if (!(*bh)) + { + if (!(*bh = udf_tread(inode->i_sb, + udf_get_lb_pblock(inode->i_sb, *bloc, 0), + inode->i_sb->s_blocksize))) + { + udf_debug("reading block %d failed!\n", + udf_get_lb_pblock(inode->i_sb, *bloc, 0)); + return -1; + } + } + + if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr))) + { + if (!(UDF_I_EXTENDED_FE(inode))) + pos = sizeof(struct FileEntry) + UDF_I_LENEATTR(inode); + else + pos = sizeof(struct ExtendedFileEntry) + UDF_I_LENEATTR(inode); + alen = UDF_I_LENALLOC(inode) + pos; + } + else + { + struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data; + + pos = sizeof(struct AllocExtDesc); + alen = le32_to_cpu(aed->lengthAllocDescs) + pos; + } + + if (!(*extoffset)) + *extoffset = pos; + + switch (UDF_I_ALLOCTYPE(inode)) + { + case ICB_FLAG_AD_SHORT: + { + short_ad *sad; + + if (!(sad = udf_get_fileshortad((*bh)->b_data, alen, extoffset, inc))) + return -1; + + etype = le32_to_cpu(sad->extLength) >> 30; + eloc->logicalBlockNum = le32_to_cpu(sad->extPosition); + eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; + *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK; + break; + } + case ICB_FLAG_AD_LONG: + { + long_ad *lad; + + if (!(lad = udf_get_filelongad((*bh)->b_data, alen, extoffset, inc))) + return -1; + + etype = le32_to_cpu(lad->extLength) >> 30; + *eloc = lelb_to_cpu(lad->extLocation); + *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK; + break; + } + default: + { + udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode)); + return -1; + } + } + if (*elen) + return etype; + + udf_debug("Empty Extent!\n"); + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT) + *extoffset -= sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG) + *extoffset -= sizeof(long_ad); + return -1; +} + +int udf_insert_aext(struct inode *inode, lb_addr bloc, int extoffset, + lb_addr neloc, Uint32 nelen, struct buffer_head *bh) +{ + lb_addr oeloc; + Uint32 oelen; + int type; + + if (!bh) + { + if (!(bh = udf_tread(inode->i_sb, + udf_get_lb_pblock(inode->i_sb, bloc, 0), + inode->i_sb->s_blocksize))) + { + udf_debug("reading block %d failed!\n", + udf_get_lb_pblock(inode->i_sb, bloc, 0)); + return -1; + } + } + + while ((type = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1) + { + udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 1); + + neloc = oeloc; + nelen = (type << 30) | oelen; + } + udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1); + return (nelen >> 30); +} + +int udf_delete_aext(struct inode *inode, lb_addr nbloc, int nextoffset, + lb_addr eloc, Uint32 elen, struct buffer_head *nbh) +{ + struct buffer_head *obh; + lb_addr obloc; + int oextoffset, adsize; + char type; + struct AllocExtDesc *aed; + + if (!(nbh)) + { + if (!(nbh = udf_tread(inode->i_sb, + udf_get_lb_pblock(inode->i_sb, nbloc, 0), + inode->i_sb->s_blocksize))) + { + udf_debug("reading block %d failed!\n", + udf_get_lb_pblock(inode->i_sb, nbloc, 0)); + return -1; + } + } + else + atomic_inc(&nbh->b_count); + atomic_inc(&nbh->b_count); + + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT) + adsize = sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG) + adsize = sizeof(long_ad); + else + adsize = 0; + + obh = nbh; + obloc = nbloc; + oextoffset = nextoffset; + + if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1) + return -1; + + while ((type = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1) + { + udf_write_aext(inode, obloc, &oextoffset, eloc, (type << 30) | elen, &obh, 1); + if (memcmp(&nbloc, &obloc, sizeof(lb_addr))) + { + obloc = nbloc; + udf_release_data(obh); + atomic_inc(&nbh->b_count); + obh = nbh; + oextoffset = nextoffset - adsize; + } + } + memset(&eloc, 0x00, sizeof(lb_addr)); + elen = 0; + + if (memcmp(&nbloc, &obloc, sizeof(lb_addr))) + { + udf_free_blocks(inode, nbloc, 0, 1); + udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1); + udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1); + if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr))) + { + UDF_I_LENALLOC(inode) -= (adsize * 2); + mark_inode_dirty(inode); + } + else + { + aed = (struct AllocExtDesc *)(obh)->b_data; + aed->lengthAllocDescs = + cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize)); + udf_update_tag((obh)->b_data, oextoffset - (2*adsize)); + mark_buffer_dirty(obh, 1); + } + } + else + { + udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1); + if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr))) + { + UDF_I_LENALLOC(inode) -= adsize; + mark_inode_dirty(inode); + } + else + { + aed = (struct AllocExtDesc *)(obh)->b_data; + aed->lengthAllocDescs = + cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize); + udf_update_tag((obh)->b_data, oextoffset - adsize); + mark_buffer_dirty(obh, 1); + } + } + + udf_release_data(nbh); + udf_release_data(obh); + return (elen >> 30); +} + +int inode_bmap(struct inode *inode, int block, lb_addr *bloc, Uint32 *extoffset, + lb_addr *eloc, Uint32 *elen, Uint32 *offset, struct buffer_head **bh) +{ + int etype, lbcount = 0, b_off; + + if (block < 0) + { + printk(KERN_ERR "udf: inode_bmap: block < 0\n"); + return 0; + } + if (!inode) + { + printk(KERN_ERR "udf: inode_bmap: NULL inode\n"); + return 0; + } + + b_off = block << inode->i_sb->s_blocksize_bits; + *bloc = UDF_I_LOCATION(inode); + *eloc = UDF_I_EXT0LOC(inode); + *elen = UDF_I_EXT0LEN(inode) & UDF_EXTENT_LENGTH_MASK; + *extoffset = udf_file_entry_alloc_offset(inode); + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT) + *extoffset += sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG) + *extoffset += sizeof(long_ad); + etype = UDF_I_EXT0LEN(inode) >> 30; + + while (lbcount + *elen <= b_off) + { + lbcount += *elen; + if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1) + { + *offset = (b_off - lbcount) >> inode->i_sb->s_blocksize_bits; + return -1; + } + } + *offset = (b_off - lbcount) >> inode->i_sb->s_blocksize_bits; + + return etype; +} + +long udf_locked_block_map(struct inode *inode, long block) +{ + lb_addr eloc, bloc; + Uint32 offset, extoffset, elen; + struct buffer_head *bh = NULL; + int ret; + + if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED) + ret = udf_get_lb_pblock(inode->i_sb, eloc, offset); + else + ret = 0; + + if (bh) + udf_release_data(bh); + + if (UDF_SB(inode->i_sb)->s_flags & UDF_FLAG_VARCONV) + return udf_fixed_to_variable(ret); + else + return ret; +} + +long udf_block_map(struct inode *inode, long block) +{ + int ret; + + lock_kernel(); + ret = udf_locked_block_map(inode, block); + unlock_kernel(); + return ret; +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/lowlevel.c linux/fs/udf/lowlevel.c --- v2.3.16/linux/fs/udf/lowlevel.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/lowlevel.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,149 @@ +/* + * lowlevel.c + * + * PURPOSE + * Low Level Device Routines for the UDF filesystem + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1999 Ben Fennema + * + * HISTORY + * + * 03/26/99 blf Created. + */ + +#include "udfdecl.h" + +#include +#include +#include +#include + +typedef struct scsi_device Scsi_Device; +typedef struct scsi_cmnd Scsi_Cmnd; + +#include + +#include +#include "udf_sb.h" + +unsigned int +udf_get_last_session(kdev_t dev) +{ + struct cdrom_multisession ms_info; + unsigned int vol_desc_start; + struct inode inode_fake; + extern struct file_operations * get_blkfops(unsigned int); + int i; + + vol_desc_start=0; + if (get_blkfops(MAJOR(dev))->ioctl!=NULL) + { + /* Whoops. We must save the old FS, since otherwise + * we would destroy the kernels idea about FS on root + * mount in read_super... [chexum] + */ + mm_segment_t old_fs=get_fs(); + inode_fake.i_rdev=dev; + ms_info.addr_format=CDROM_LBA; + set_fs(KERNEL_DS); + i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake, + NULL, + CDROMMULTISESSION, + (unsigned long) &ms_info); + set_fs(old_fs); + +#define WE_OBEY_THE_WRITTEN_STANDARDS 1 + + if (i == 0) + { + udf_debug("XA disk: %s, vol_desc_start=%d\n", + (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba); +#if WE_OBEY_THE_WRITTEN_STANDARDS + if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */ +#endif + vol_desc_start = ms_info.addr.lba; + } + else + { + udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i); + } + } + else + { + udf_debug("Device doesn't know how to ioctl?\n"); + } + return vol_desc_start; +} + +unsigned int +udf_get_last_block(kdev_t dev, int *flags) +{ + extern int *blksize_size[]; + struct inode inode_fake; + extern struct file_operations * get_blkfops(unsigned int); + int ret; + unsigned long lblock; + unsigned int hbsize = get_hardblocksize(dev); + unsigned int mult = 0; + unsigned int div = 0; + + if (!hbsize) + hbsize = 512; + + if (hbsize > blksize_size[MAJOR(dev)][MINOR(dev)]) + mult = hbsize / blksize_size[MAJOR(dev)][MINOR(dev)]; + else if (blksize_size[MAJOR(dev)][MINOR(dev)] > hbsize) + div = blksize_size[MAJOR(dev)][MINOR(dev)] / hbsize; + + if (get_blkfops(MAJOR(dev))->ioctl!=NULL) + { + /* Whoops. We must save the old FS, since otherwise + * we would destroy the kernels idea about FS on root + * mount in read_super... [chexum] + */ + mm_segment_t old_fs=get_fs(); + inode_fake.i_rdev=dev; + set_fs(KERNEL_DS); + + lblock = 0; + ret = get_blkfops(MAJOR(dev))->ioctl(&inode_fake, + NULL, + BLKGETSIZE, + (unsigned long) &lblock); + + if (!ret) /* Hard Disk */ + { + if (mult) + lblock *= mult; + else if (div) + lblock /= div; + } + else /* CDROM */ + { + ret = get_blkfops(MAJOR(dev))->ioctl(&inode_fake, + NULL, + CDROM_LAST_WRITTEN, + (unsigned long) &lblock); + } + + set_fs(old_fs); + if (!ret) + return lblock - 1; + } + else + { + udf_debug("Device doesn't know how to ioctl?\n"); + } + return 0; +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/misc.c linux/fs/udf/misc.c --- v2.3.16/linux/fs/udf/misc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/misc.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,540 @@ +/* + * misc.c + * + * PURPOSE + * Miscellaneous routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1998 Dave Boynton + * (C) 1998-1999 Ben Fennema + * (C) 1999 Stelias Computing Inc + * + * HISTORY + * + * 04/19/99 blf partial support for reading/writing specific EA's + */ + + +#if defined(__linux__) && defined(__KERNEL__) + +#include "udfdecl.h" + +#include "udf_sb.h" +#include "udf_i.h" + +#include +#include +#include + +#else + +#include "udfdecl.h" +#include +#include +#include +#include + +int udf_blocksize=0; +int udf_errno=0; + +void +udf_setblocksize(int size) +{ + udf_blocksize=size; +} +#endif + +Uint32 +udf64_low32(Uint64 indat) +{ + return indat & 0x00000000FFFFFFFFULL; +} + +Uint32 +udf64_high32(Uint64 indat) +{ + return indat >> 32; +} + +/* + * udf_stamp_to_time + */ +time_t * +udf_stamp_to_time(time_t *dest, timestamp src) +{ + struct ktm tm; + + if ((!dest)) + return NULL; + + /* this is very rough. need to find source to mktime() */ + tm.tm_year=(src.year) - 1900; + tm.tm_mon=(src.month); + tm.tm_mday=(src.day); + tm.tm_hour=src.hour; + tm.tm_min=src.minute; + tm.tm_sec=src.second; + *dest = udf_converttime(&tm); + return dest; +} + +uid_t udf_convert_uid(int uidin) +{ + if ( uidin == -1 ) + return 0; + if ( uidin > (64*1024U - 1) ) /* 16 bit UID */ + return 0; + return uidin; +} + +gid_t udf_convert_gid(int gidin) +{ + if ( gidin == -1 ) + return 0; + if ( gidin > (64*1024U - 1) ) /* 16 bit GID */ + return 0; + return gidin; +} + +#if defined(__linux__) && defined(__KERNEL__) + +extern struct buffer_head * +udf_tread(struct super_block *sb, int block, int size) +{ + if (UDF_SB(sb)->s_flags & UDF_FLAG_VARCONV) + return bread(sb->s_dev, udf_fixed_to_variable(block), size); + else + return bread(sb->s_dev, block, size); +} + +extern struct GenericAttrFormat * +udf_add_extendedattr(struct inode * inode, Uint32 size, Uint32 type, + Uint8 loc, struct buffer_head **bh) +{ + Uint8 *ea = NULL, *ad = NULL; + long_ad eaicb; + int offset; + + *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize); + + if (UDF_I_EXTENDED_FE(inode) == 0) + { + struct FileEntry *fe; + + fe = (struct FileEntry *)(*bh)->b_data; + eaicb = fe->extendedAttrICB; + offset = sizeof(struct FileEntry); + } + else + { + struct ExtendedFileEntry *efe; + + efe = (struct ExtendedFileEntry *)(*bh)->b_data; + eaicb = efe->extendedAttrICB; + offset = sizeof(struct ExtendedFileEntry); + } + + ea = &(*bh)->b_data[offset]; + if (UDF_I_LENEATTR(inode)) + offset += UDF_I_LENEATTR(inode); + else + size += sizeof(struct ExtendedAttrHeaderDesc); + + ad = &(*bh)->b_data[offset]; + if (UDF_I_LENALLOC(inode)) + offset += UDF_I_LENALLOC(inode); + + offset = inode->i_sb->s_blocksize - offset; + + /* TODO - Check for FreeEASpace */ + + if (loc & 0x01 && offset >= size) + { + struct ExtendedAttrHeaderDesc *eahd; + eahd = (struct ExtendedAttrHeaderDesc *)ea; + + if (UDF_I_LENALLOC(inode)) + { + memmove(&ad[size], ad, UDF_I_LENALLOC(inode)); + UDF_I_EXT0OFFS(inode) += size; + } + + if (UDF_I_LENEATTR(inode)) + { + /* check checksum/crc */ + if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC || + le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) + { + udf_release_data(*bh); + return NULL; + } + } + else + { + size -= sizeof(struct ExtendedAttrHeaderDesc); + UDF_I_LENEATTR(inode) += sizeof(struct ExtendedAttrHeaderDesc); + eahd->descTag.tagIdent = cpu_to_le16(TID_EXTENDED_ATTRE_HEADER_DESC); + eahd->descTag.descVersion = cpu_to_le16(2); + eahd->descTag.tagSerialNum = cpu_to_le16(1); + eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum); + eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF); + eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF); + } + + offset = UDF_I_LENEATTR(inode); + if (type < 2048) + { + if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) + { + Uint32 aal = le32_to_cpu(eahd->appAttrLocation); + memmove(&ea[offset - aal + size], + &ea[aal], offset - aal); + offset -= aal; + eahd->appAttrLocation = cpu_to_le32(aal + size); + } + if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode)) + { + Uint32 ial = le32_to_cpu(eahd->impAttrLocation); + memmove(&ea[offset - ial + size], + &ea[ial], offset - ial); + offset -= ial; + eahd->impAttrLocation = cpu_to_le32(ial + size); + } + } + else if (type < 65536) + { + if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) + { + Uint32 aal = le32_to_cpu(eahd->appAttrLocation); + memmove(&ea[offset - aal + size], + &ea[aal], offset - aal); + offset -= aal; + eahd->appAttrLocation = cpu_to_le32(aal + size); + } + } + /* rewrite CRC + checksum of eahd */ + UDF_I_LENEATTR(inode) += size; + return (struct GenericAttrFormat *)&ea[offset]; + } + if (loc & 0x02) + { + } + udf_release_data(*bh); + return NULL; +} + +extern struct GenericAttrFormat * +udf_get_extendedattr(struct inode * inode, Uint32 type, Uint8 subtype, + struct buffer_head **bh) +{ + struct GenericAttrFormat *gaf; + Uint8 *ea = NULL; + long_ad eaicb; + Uint32 offset; + + *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize); + + if (UDF_I_EXTENDED_FE(inode) == 0) + { + struct FileEntry *fe; + + fe = (struct FileEntry *)(*bh)->b_data; + eaicb = fe->extendedAttrICB; + if (UDF_I_LENEATTR(inode)) + ea = fe->extendedAttr; + } + else + { + struct ExtendedFileEntry *efe; + + efe = (struct ExtendedFileEntry *)(*bh)->b_data; + eaicb = efe->extendedAttrICB; + if (UDF_I_LENEATTR(inode)) + ea = efe->extendedAttr; + } + + if (UDF_I_LENEATTR(inode)) + { + struct ExtendedAttrHeaderDesc *eahd; + eahd = (struct ExtendedAttrHeaderDesc *)ea; + + /* check checksum/crc */ + if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC || + le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) + { + udf_release_data(*bh); + return NULL; + } + + if (type < 2048) + offset = sizeof(struct ExtendedAttrHeaderDesc); + else if (type < 65536) + offset = le32_to_cpu(eahd->impAttrLocation); + else + offset = le32_to_cpu(eahd->appAttrLocation); + + while (offset < UDF_I_LENEATTR(inode)) + { + gaf = (struct GenericAttrFormat *)&ea[offset]; + if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype) + return gaf; + else + offset += le32_to_cpu(gaf->attrLength); + } + } + + udf_release_data(*bh); + if (eaicb.extLength) + { + /* TODO */ + } + return NULL; +} + +extern struct buffer_head * +udf_read_untagged(struct super_block *sb, Uint32 block, Uint32 offset) +{ + struct buffer_head *bh = NULL; + + /* Read the block */ + bh = udf_tread(sb, block+offset, sb->s_blocksize); + if (!bh) + { + printk(KERN_ERR "udf: udf_read_untagged(%p,%d,%d) failed\n", + sb, block, offset); + return NULL; + } + return bh; +} + +/* + * udf_read_tagged + * + * PURPOSE + * Read the first block of a tagged descriptor. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +extern struct buffer_head * +udf_read_tagged(struct super_block *sb, Uint32 block, Uint32 location, Uint16 *ident) +{ + tag *tag_p; + struct buffer_head *bh = NULL; + register Uint8 checksum; + register int i; + + /* Read the block */ + if (block == 0xFFFFFFFF) + return NULL; + + bh = udf_tread(sb, block, sb->s_blocksize); + if (!bh) + { + udf_debug("block=%d, location=%d: read failed\n", block, location); + return NULL; + } + + tag_p = (tag *)(bh->b_data); + + *ident = le16_to_cpu(tag_p->tagIdent); + + if ( location != le32_to_cpu(tag_p->tagLocation) ) + { + udf_debug("location mismatch block %d, tag %d != %d\n", + block, le32_to_cpu(tag_p->tagLocation), location); + goto error_out; + } + + /* Verify the tag checksum */ + checksum = 0U; + for (i = 0; i < 4; i++) + checksum += (Uint8)(bh->b_data[i]); + for (i = 5; i < 16; i++) + checksum += (Uint8)(bh->b_data[i]); + if (checksum != tag_p->tagChecksum) { + printk(KERN_ERR "udf: tag checksum failed block %d\n", block); + goto error_out; + } + + /* Verify the tag version */ + if (le16_to_cpu(tag_p->descVersion) != 0x0002U && + le16_to_cpu(tag_p->descVersion) != 0x0003U) + { + udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n", + le16_to_cpu(tag_p->descVersion), block); + goto error_out; + } + + /* Verify the descriptor CRC */ + if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize || + le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag), + le16_to_cpu(tag_p->descCRCLength), 0)) + { + return bh; + } + udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", + block, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); + +error_out: + brelse(bh); + return NULL; +} + +extern struct buffer_head * +udf_read_ptagged(struct super_block *sb, lb_addr loc, Uint32 offset, Uint16 *ident) +{ + return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset), + loc.logicalBlockNum + offset, ident); +} + +void udf_release_data(struct buffer_head *bh) +{ + if (bh) + brelse(bh); +} + +#endif + +void udf_update_tag(char *data, int length) +{ + tag *tptr = (tag *)data; + int i; + + length -= sizeof(tag); + + tptr->tagChecksum = 0; + tptr->descCRCLength = le16_to_cpu(length); + tptr->descCRC = le16_to_cpu(udf_crc(data + sizeof(tag), length, 0)); + + for (i=0; i<16; i++) + if (i != 4) + tptr->tagChecksum += (Uint8)(data[i]); +} + +void udf_new_tag(char *data, Uint16 ident, Uint16 version, Uint16 snum, + Uint32 loc, int length) +{ + tag *tptr = (tag *)data; + tptr->tagIdent = le16_to_cpu(ident); + tptr->descVersion = le16_to_cpu(version); + tptr->tagSerialNum = le16_to_cpu(snum); + tptr->tagLocation = le32_to_cpu(loc); + udf_update_tag(data, length); +} + +#ifndef __KERNEL__ +/* + * udf_read_tagged_data + * + * PURPOSE + * Read the first block of a tagged descriptor. + * Usable from user-land. + * + * HISTORY + * 10/4/98 dgb: written + */ +int +udf_read_tagged_data(char *buffer, int size, int fd, int block, int offset) +{ + tag *tag_p; + register Uint8 checksum; + register int i; + unsigned long offs; + + if (!buffer) + { + udf_errno = 1; + return -1; + } + + if ( !udf_blocksize ) + { + udf_errno = 2; + return -1; + } + + if ( size < udf_blocksize ) + { + udf_errno=3; + return -1; + } + udf_errno=0; + + offs=(long)block * udf_blocksize; + if ( lseek(fd, offs, SEEK_SET) != offs ) { + udf_errno=4; + return -1; + } + + i=read(fd, buffer, udf_blocksize); + if ( i < udf_blocksize ) { + udf_errno=5; + return -1; + } + + tag_p = (tag *)(buffer); + + /* Verify the tag location */ + if ((block-offset) != tag_p->tagLocation) { +#ifdef __KERNEL__ + printk(KERN_ERR "udf: location mismatch block %d, tag %d\n", + block, tag_p->tagLocation); +#else + udf_errno=6; +#endif + goto error_out; + } + + /* Verify the tag checksum */ + checksum = 0U; + for (i = 0; i < 4; i++) + checksum += (Uint8)(buffer[i]); + for (i = 5; i < 16; i++) + checksum += (Uint8)(buffer[i]); + if (checksum != tag_p->tagChecksum) { +#ifdef __KERNEL__ + printk(KERN_ERR "udf: tag checksum failed\n"); +#else + udf_errno=7; +#endif + goto error_out; + } + + /* Verify the tag version */ + if (tag_p->descVersion != 0x0002U) { +#ifdef __KERNEL__ + printk(KERN_ERR "udf: tag version 0x%04x != 0x0002U\n", + tag_p->descVersion); +#else + udf_errno=8; +#endif + goto error_out; + } + + /* Verify the descriptor CRC */ + if (tag_p->descCRC == udf_crc(buffer + 16, tag_p->descCRCLength, 0)) { + udf_errno=0; + return 0; + } +#ifdef __KERNEL__ + printk(KERN_ERR "udf: crc failure in udf_read_tagged\n"); +#else + udf_errno=9; +#endif + +error_out: + return -1; +} +#endif diff -u --recursive --new-file v2.3.16/linux/fs/udf/namei.c linux/fs/udf/namei.c --- v2.3.16/linux/fs/udf/namei.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/namei.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,1302 @@ +/* + * namei.c + * + * PURPOSE + * Inode name handling routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1998-1999 Ben Fennema + * (C) 1999 Stelias Computing Inc + * + * HISTORY + * + * 12/12/98 blf Created. Split out the lookup code from dir.c + * 04/19/99 blf link, mknod, symlink support + * + */ + +#if defined(__linux__) && defined(__KERNEL__) +#include +#include "udf_i.h" +#include "udf_sb.h" +#include +#include +#include +#include +#include +#endif + +#include "udfdecl.h" + +static inline int udf_match(int len, const char * const name, struct qstr *qs) +{ + if (len != qs->len) + return 0; + return !memcmp(name, qs->name, len); +} + +int udf_write_fi(struct FileIdentDesc *cfi, struct FileIdentDesc *sfi, + struct udf_fileident_bh *fibh, + Uint8 *impuse, Uint8 *fileident) +{ + struct FileIdentDesc *efi; + Uint16 crclen = fibh->eoffset - fibh->soffset - sizeof(tag); + Uint16 crc; + Uint8 checksum = 0; + int i; + int offset, len; + int padlen = fibh->eoffset - fibh->soffset - cfi->lengthOfImpUse - cfi->lengthFileIdent - + sizeof(struct FileIdentDesc); + + crc = udf_crc((Uint8 *)cfi + sizeof(tag), sizeof(struct FileIdentDesc) - + sizeof(tag), 0); + efi = (struct FileIdentDesc *)(fibh->ebh->b_data + fibh->soffset); + if (fibh->sbh == fibh->ebh || + (!fileident && + (sizeof(struct FileIdentDesc) + (impuse ? cfi->lengthOfImpUse : 0)) + <= -fibh->soffset)) + { + memcpy((Uint8 *)sfi, (Uint8 *)cfi, sizeof(struct FileIdentDesc)); + + if (impuse) + memcpy(sfi->impUse, impuse, cfi->lengthOfImpUse); + + if (fileident) + memcpy(sfi->fileIdent + cfi->lengthOfImpUse, fileident, + cfi->lengthFileIdent); + + /* Zero padding */ + memset(sfi->fileIdent + cfi->lengthOfImpUse + cfi->lengthFileIdent, 0, + padlen); + + if (fibh->sbh == fibh->ebh) + crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen, 0); + else + { + crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen - fibh->eoffset, 0); + crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc); + } + + sfi->descTag.descCRC = cpu_to_le32(crc); + sfi->descTag.descCRCLength = cpu_to_le16(crclen); + + for (i=0; i<16; i++) + if (i != 4) + checksum += ((Uint8 *)&sfi->descTag)[i]; + + sfi->descTag.tagChecksum = checksum; + + mark_buffer_dirty(fibh->sbh, 1); + } + else + { + offset = -fibh->soffset; + len = sizeof(struct FileIdentDesc); + + if (len <= offset) + memcpy((Uint8 *)sfi, (Uint8 *)cfi, len); + else + { + memcpy((Uint8 *)sfi, (Uint8 *)cfi, offset); + memcpy(fibh->ebh->b_data, (Uint8 *)cfi + offset, len - offset); + } + + offset -= len; + len = cfi->lengthOfImpUse; + + if (impuse) + { + if (offset <= 0) + memcpy(efi->impUse, impuse, len); + else if (sizeof(struct FileIdentDesc) + len <= -fibh->soffset) + memcpy(sfi->impUse, impuse, len); + else + { + memcpy(sfi->impUse, impuse, offset); + memcpy(efi->impUse + offset, impuse + offset, len - offset); + } + } + + offset -= len; + len = cfi->lengthFileIdent; + + if (fileident) + { + if (offset <= 0) + memcpy(efi->fileIdent + cfi->lengthOfImpUse, fileident, len); + else + { + memcpy(sfi->fileIdent + cfi->lengthOfImpUse, fileident, offset); + memcpy(efi->fileIdent + cfi->lengthOfImpUse + offset, + fileident + offset, len - offset); + } + } + + /* Zero padding */ + memset(efi->fileIdent + cfi->lengthOfImpUse + cfi->lengthFileIdent, 0x00, + padlen); + + if (sizeof(tag) < -fibh->soffset) + { + crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen - fibh->eoffset, 0); + crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc); + } + else + crc = udf_crc((Uint8 *)fibh->ebh->b_data + fibh->eoffset - crclen, crclen, 0); + + if (&(efi->descTag.descCRC) < (Uint16 *)fibh->ebh->b_data) + { + sfi->descTag.descCRC = cpu_to_le16(crc); + sfi->descTag.descCRCLength = cpu_to_le16(crclen); + } + else + { + efi->descTag.descCRC = cpu_to_le16(crc); + efi->descTag.descCRCLength = cpu_to_le16(crclen); + } + + for (i=0; i<16; i++) + { + if (i != 4) + { + if (&(((Uint8 *)&efi->descTag)[i]) < (Uint8 *)fibh->ebh->b_data) + checksum += ((Uint8 *)&sfi->descTag)[i]; + else + checksum += ((Uint8 *)&efi->descTag)[i]; + } + } + + if (&(cfi->descTag.tagChecksum) < (Uint8 *)fibh->ebh->b_data) + sfi->descTag.tagChecksum = checksum; + else + efi->descTag.tagChecksum = checksum; + + mark_buffer_dirty(fibh->sbh, 1); + mark_buffer_dirty(fibh->ebh, 1); + } + return 0; +} + +static struct FileIdentDesc * +udf_find_entry(struct inode *dir, struct dentry *dentry, + struct udf_fileident_bh *fibh, + struct FileIdentDesc *cfi) +{ + struct FileIdentDesc *fi=NULL; + int f_pos, block; + int flen; + char fname[255]; + char *nameptr; + Uint8 lfi; + Uint16 liu; + int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2; + lb_addr bloc, eloc; + Uint32 extoffset, elen, offset; + struct buffer_head *bh = NULL; + + if (!dir) + return NULL; + + f_pos = (UDF_I_EXT0OFFS(dir) >> 2); + + fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; + if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), + &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED) + { + block = udf_get_lb_pblock(dir->i_sb, eloc, offset); + if (++offset < (elen >> dir->i_sb->s_blocksize_bits)) + { + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT) + extoffset -= sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG) + extoffset -= sizeof(long_ad); + } + else + offset = 0; + } + else + { + udf_release_data(bh); + return NULL; + } + + if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize))) + { + udf_debug("udf_tread failed: block=%d\n", block); + udf_release_data(bh); + return NULL; + } + + while ( (f_pos < size) ) + { + fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &offset, &bh); + liu = le16_to_cpu(cfi->lengthOfImpUse); + lfi = cfi->lengthFileIdent; + + if (!fi) + { + if (fibh->sbh != fibh->ebh) + udf_release_data(fibh->ebh); + udf_release_data(fibh->sbh); + udf_release_data(bh); + return NULL; + } + + if (fibh->sbh == fibh->ebh) + { + nameptr = fi->fileIdent + liu; + } + else + { + int poffset; /* Unpaded ending offset */ + + poffset = fibh->soffset + sizeof(struct FileIdentDesc) + liu + lfi; + + if (poffset >= lfi) + nameptr = (Uint8 *)(fibh->ebh->b_data + poffset - lfi); + else + { + nameptr = fname; + memcpy(nameptr, fi->fileIdent + liu, lfi - poffset); + memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset); + } + } + + if ( (cfi->fileCharacteristics & FILE_DELETED) != 0 ) + { + if ( !IS_UNDELETE(dir->i_sb) ) + continue; + } + + if ( (cfi->fileCharacteristics & FILE_HIDDEN) != 0 ) + { + if ( !IS_UNHIDE(dir->i_sb) ) + continue; + } + + if (!lfi) + continue; + + if ((flen = udf_get_filename(nameptr, fname, lfi))) + { + if (udf_match(flen, fname, &(dentry->d_name))) + { + udf_release_data(bh); + return fi; + } + } + } + if (fibh->sbh != fibh->ebh) + udf_release_data(fibh->ebh); + udf_release_data(fibh->sbh); + udf_release_data(bh); + return NULL; +} + +/* + * udf_lookup + * + * PURPOSE + * Look-up the inode for a given name. + * + * DESCRIPTION + * Required - lookup_dentry() will return -ENOTDIR if this routine is not + * available for a directory. The filesystem is useless if this routine is + * not available for at least the filesystem's root directory. + * + * This routine is passed an incomplete dentry - it must be completed by + * calling d_add(dentry, inode). If the name does not exist, then the + * specified inode must be set to null. An error should only be returned + * when the lookup fails for a reason other than the name not existing. + * Note that the directory inode semaphore is held during the call. + * + * Refer to lookup_dentry() in fs/namei.c + * lookup_dentry() -> lookup() -> real_lookup() -> . + * + * PRE-CONDITIONS + * dir Pointer to inode of parent directory. + * dentry Pointer to dentry to complete. + * + * POST-CONDITIONS + * Zero on success. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ + +struct dentry * +udf_lookup(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = NULL; + struct FileIdentDesc cfi, *fi; + struct udf_fileident_bh fibh; + +#ifdef UDF_RECOVERY + /* temporary shorthand for specifying files by inode number */ + if (!strncmp(dentry->d_name.name, ".B=", 3) ) + { + lb_addr lb = { 0, simple_strtoul(dentry->d_name.name+3, NULL, 0) }; + inode = udf_iget(dir->i_sb, lb); + if (!inode) + return ERR_PTR(-EACCES); + } + else +#endif /* UDF_RECOVERY */ + + if ((fi = udf_find_entry(dir, dentry, &fibh, &cfi))) + { + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + + inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation)); + if ( !inode ) + return ERR_PTR(-EACCES); + } + d_add(dentry, inode); + return NULL; +} + +static struct FileIdentDesc * +udf_add_entry(struct inode *dir, struct dentry *dentry, + struct udf_fileident_bh *fibh, + struct FileIdentDesc *cfi, int *err) +{ + struct super_block *sb; + struct FileIdentDesc *fi=NULL; + struct ustr unifilename; + char name[UDF_NAME_LEN], fname[UDF_NAME_LEN]; + int namelen; + int f_pos; + int flen; + char *nameptr; + int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2; + int nfidlen; + Uint8 lfi; + Uint16 liu; + int block; + lb_addr bloc, eloc; + Uint32 extoffset, elen, offset; + struct buffer_head *bh = NULL; + + *err = -EINVAL; + if (!dir || !dir->i_nlink) + return NULL; + sb = dir->i_sb; + + if (!dentry->d_name.len) + return NULL; + + if (dir->i_size == 0) + { + *err = -ENOENT; + return NULL; + } + + if ( !(udf_char_to_ustr(&unifilename, dentry->d_name.name, dentry->d_name.len)) ) + { + *err = -ENAMETOOLONG; + return NULL; + } + + if ( !(namelen = udf_UTF8toCS0(name, &unifilename, UDF_NAME_LEN)) ) + return 0; + + nfidlen = (sizeof(struct FileIdentDesc) + 0 + namelen + 3) & ~3; + + f_pos = (UDF_I_EXT0OFFS(dir) >> 2); + + fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; + if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), + &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED) + { + block = udf_get_lb_pblock(dir->i_sb, eloc, offset); + if (++offset < (elen >> dir->i_sb->s_blocksize_bits)) + { + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT) + extoffset -= sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG) + extoffset -= sizeof(long_ad); + } + else + offset = 0; + } + else + { + udf_release_data(bh); + return NULL; + } + + if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize))) + return NULL; + + block = UDF_I_LOCATION(dir).logicalBlockNum; + + while ( (f_pos < size) ) + { + fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &offset, &bh); + liu = le16_to_cpu(cfi->lengthOfImpUse); + lfi = cfi->lengthFileIdent; + + if (!fi) + { + if (fibh->sbh != fibh->ebh) + udf_release_data(fibh->ebh); + udf_release_data(fibh->sbh); + udf_release_data(bh); + return NULL; + } + + if (fibh->sbh == fibh->ebh) + nameptr = fi->fileIdent + liu; + else + { + int poffset; /* Unpaded ending offset */ + + poffset = fibh->soffset + sizeof(struct FileIdentDesc) + liu + lfi; + + if (poffset >= lfi) + nameptr = (char *)(fibh->ebh->b_data + poffset - lfi); + else + { + nameptr = fname; + memcpy(nameptr, fi->fileIdent + liu, lfi - poffset); + memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset); + } + } + + if ( (cfi->fileCharacteristics & FILE_DELETED) != 0 ) + { + if (((sizeof(struct FileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) + { + udf_release_data(bh); + cfi->descTag.tagSerialNum = cpu_to_le16(1); + cfi->fileVersionNum = cpu_to_le16(1); + cfi->fileCharacteristics = 0; + cfi->lengthFileIdent = namelen; + cfi->lengthOfImpUse = cpu_to_le16(0); + if (!udf_write_fi(cfi, fi, fibh, NULL, name)) + return fi; + else + return NULL; + } + } + + if (!lfi) + continue; + + if ((flen = udf_get_filename(nameptr, fname, lfi))) + { + if (udf_match(flen, fname, &(dentry->d_name))) + { + if (fibh->sbh != fibh->ebh) + udf_release_data(fibh->ebh); + udf_release_data(fibh->sbh); + udf_release_data(bh); + *err = -EEXIST; + return NULL; + } + } + } + + f_pos += nfidlen; + + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB && + sb->s_blocksize - fibh->eoffset < nfidlen) + { + udf_release_data(bh); + bh = NULL; + fibh->soffset -= UDF_I_EXT0OFFS(dir); + fibh->eoffset -= UDF_I_EXT0OFFS(dir); + f_pos -= (UDF_I_EXT0OFFS(dir) >> 2); + udf_release_data(fibh->sbh); + if (!(fibh->sbh = fibh->ebh = udf_expand_adinicb(dir, &block, 1, err))) + return NULL; + bloc = UDF_I_LOCATION(dir); + extoffset = udf_file_entry_alloc_offset(dir); + } + else + { + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT) + extoffset -= sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG) + extoffset -= sizeof(long_ad); + } + + dir->i_size += nfidlen; + if (sb->s_blocksize - fibh->eoffset >= nfidlen) + { + fibh->soffset = fibh->eoffset; + fibh->eoffset += nfidlen; + if (fibh->sbh != fibh->ebh) + { + udf_release_data(fibh->sbh); + fibh->sbh = fibh->ebh; + } + + if (UDF_I_ALLOCTYPE(dir) != ICB_FLAG_AD_IN_ICB) + { + Uint32 lextoffset = extoffset; + if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) != + EXTENT_RECORDED_ALLOCATED) + { + udf_release_data(bh); + udf_release_data(fibh->sbh); + return NULL; + } + else + { + elen += nfidlen; + elen = (EXTENT_RECORDED_ALLOCATED << 30) | elen; + udf_write_aext(dir, bloc, &lextoffset, eloc, elen, &bh, 1); + block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits); + } + } + else + block = UDF_I_LOCATION(dir).logicalBlockNum; + + fi = (struct FileIdentDesc *)(fibh->sbh->b_data + fibh->soffset); + } + else + { + Uint32 lextoffset = extoffset; + + fibh->soffset = fibh->eoffset - sb->s_blocksize; + fibh->eoffset += nfidlen - sb->s_blocksize; + if (fibh->sbh != fibh->ebh) + { + udf_release_data(fibh->sbh); + fibh->sbh = fibh->ebh; + } + + if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) != + EXTENT_RECORDED_ALLOCATED) + { + udf_release_data(bh); + udf_release_data(fibh->sbh); + return NULL; + } + else + block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits); + + *err = -ENOSPC; + if (!(fibh->ebh = udf_getblk(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err))) + { + udf_release_data(bh); + udf_release_data(fibh->sbh); + return NULL; + } + if (!(fibh->soffset)) + { + if (udf_next_aext(dir, &bloc, &lextoffset, &eloc, &elen, &bh, 1) == + EXTENT_RECORDED_ALLOCATED) + { + block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits); + } + else + block ++; + } + + fi = (struct FileIdentDesc *)(fibh->sbh->b_data + sb->s_blocksize + fibh->soffset); + } + + memset(cfi, 0, sizeof(struct FileIdentDesc)); + udf_new_tag((char *)cfi, TID_FILE_IDENT_DESC, 2, 1, block, sizeof(tag)); + cfi->fileVersionNum = cpu_to_le16(1); + cfi->lengthFileIdent = namelen; + cfi->lengthOfImpUse = cpu_to_le16(0); + if (!udf_write_fi(cfi, fi, fibh, NULL, name)) + { + udf_release_data(bh); + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) + UDF_I_LENALLOC(dir) += nfidlen; + dir->i_version = ++event; + mark_inode_dirty(dir); + return fi; + } + else + { + udf_release_data(bh); + dir->i_size -= nfidlen; + if (fibh->sbh != fibh->ebh) + udf_release_data(fibh->ebh); + udf_release_data(fibh->sbh); + return NULL; + } +} + +static int udf_delete_entry(struct FileIdentDesc *fi, + struct udf_fileident_bh *fibh, + struct FileIdentDesc *cfi) +{ + cfi->fileCharacteristics |= FILE_DELETED; + return udf_write_fi(cfi, fi, fibh, NULL, NULL); +} + +int udf_create(struct inode *dir, struct dentry *dentry, int mode) +{ + struct udf_fileident_bh fibh; + struct inode *inode; + struct FileIdentDesc cfi, *fi; + int err; + + inode = udf_new_inode(dir, mode, &err); + if (!inode) + return err; + + inode->i_op = &udf_file_inode_operations; + inode->i_mode = mode; + mark_inode_dirty(inode); + + if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) + { + udf_debug("udf_add_entry failure!\n"); + inode->i_nlink --; + mark_inode_dirty(inode); + iput(inode); + return err; + } + cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); + cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); + *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse = + cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL); + udf_write_fi(&cfi, fi, &fibh, NULL, NULL); + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) + { + mark_inode_dirty(dir); + dir->i_version = ++event; + } + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + d_instantiate(dentry, inode); + return 0; +} + +int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev) +{ + struct inode * inode; + struct udf_fileident_bh fibh; + int err; + struct FileIdentDesc cfi, *fi; + + err = -EIO; + inode = udf_new_inode(dir, mode, &err); + if (!inode) + goto out; + + inode->i_uid = current->fsuid; + inode->i_mode = mode; + inode->i_op = NULL; + if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) + { + udf_debug("udf_add_entry failure!\n"); + inode->i_nlink --; + mark_inode_dirty(inode); + iput(inode); + return err; + } + cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); + cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); + *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse = + cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL); + udf_write_fi(&cfi, fi, &fibh, NULL, NULL); + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) + { + mark_inode_dirty(dir); + dir->i_version = ++event; + } + if (S_ISREG(inode->i_mode)) + { + inode->i_op = &udf_file_inode_operations; + } + else if (S_ISCHR(inode->i_mode)) + { + inode->i_op = &chrdev_inode_operations; + } + else if (S_ISBLK(inode->i_mode)) + { + inode->i_op = &blkdev_inode_operations; + } + else if (S_ISFIFO(inode->i_mode)) + { + init_fifo(inode); + } + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_rdev = to_kdev_t(rdev); + mark_inode_dirty(inode); + + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + d_instantiate(dentry, inode); + err = 0; +out: + return err; +} + +int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode) +{ + struct inode * inode; + struct udf_fileident_bh fibh; + int err; + struct FileEntry *fe; + struct FileIdentDesc cfi, *fi; + Uint32 loc; + + err = -EMLINK; + if (dir->i_nlink >= (256<i_nlink))-1) + goto out; + + err = -EIO; + inode = udf_new_inode(dir, S_IFDIR, &err); + if (!inode) + goto out; + + inode->i_op = &udf_dir_inode_operations; + inode->i_size = (sizeof(struct FileIdentDesc) + 3) & ~3; + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) + { + UDF_I_EXT0LEN(inode) = inode->i_size; + UDF_I_EXT0LOC(inode) = UDF_I_LOCATION(inode); + UDF_I_LENALLOC(inode) = inode->i_size; + loc = UDF_I_LOCATION(inode).logicalBlockNum; + fibh.sbh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize); + } + else + { + fibh.sbh = udf_bread (inode, 0, 1, &err); + loc = UDF_I_EXT0LOC(inode).logicalBlockNum; + } + + if (!fibh.sbh) + { + inode->i_nlink--; + mark_inode_dirty(inode); + iput(inode); + goto out; + } + inode->i_nlink = 2; + fe = (struct FileEntry *)fibh.sbh->b_data; + fi = (struct FileIdentDesc *)&(fe->extendedAttr[UDF_I_LENEATTR(inode)]); + udf_new_tag((char *)&cfi, TID_FILE_IDENT_DESC, 2, 1, loc, + sizeof(struct FileIdentDesc)); + cfi.fileVersionNum = cpu_to_le16(1); + cfi.fileCharacteristics = FILE_DIRECTORY | FILE_PARENT; + cfi.lengthFileIdent = 0; + cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); + cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(dir)); + *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse = + cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL); + cfi.lengthOfImpUse = cpu_to_le16(0); + fibh.ebh = fibh.sbh; + fibh.soffset = sizeof(struct FileEntry); + fibh.eoffset = sizeof(struct FileEntry) + inode->i_size; + udf_write_fi(&cfi, fi, &fibh, NULL, NULL); + udf_release_data(fibh.sbh); + inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask); + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + mark_inode_dirty(inode); + + if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) + { + udf_debug("udf_add_entry failure!\n"); + inode->i_nlink = 0; + mark_inode_dirty(inode); + iput(inode); + goto out; + } + cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); + cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); + *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse = + cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL); + cfi.fileCharacteristics |= FILE_DIRECTORY; + udf_write_fi(&cfi, fi, &fibh, NULL, NULL); + dir->i_version = ++event; + dir->i_nlink++; + mark_inode_dirty(dir); + d_instantiate(dentry, inode); + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + err = 0; +out: + return err; +} + +static int empty_dir(struct inode *dir) +{ + struct FileIdentDesc *fi, cfi; + struct udf_fileident_bh fibh; + int f_pos; + int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2; + int block; + lb_addr bloc, eloc; + Uint32 extoffset, elen, offset; + struct buffer_head *bh = NULL; + + f_pos = (UDF_I_EXT0OFFS(dir) >> 2); + + fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; + if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), + &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED) + { + block = udf_get_lb_pblock(dir->i_sb, eloc, offset); + if (++offset < (elen >> dir->i_sb->s_blocksize_bits)) + { + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT) + extoffset -= sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG) + extoffset -= sizeof(long_ad); + } + else + offset = 0; + } + else + { + udf_release_data(bh); + return 0; + } + + if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize))) + return 0; + + while ( (f_pos < size) ) + { + fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &bloc, &extoffset, &offset, &bh); + + if (!fi) + { + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + udf_release_data(bh); + return 0; + } + + if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FILE_DELETED) == 0) + { + udf_release_data(bh); + return 0; + } + } + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + udf_release_data(bh); + return 1; +} + +int udf_rmdir(struct inode * dir, struct dentry * dentry) +{ + int retval; + struct inode * inode; + struct udf_fileident_bh fibh; + struct FileIdentDesc *fi, cfi; + + retval = -ENOENT; + fi = udf_find_entry(dir, dentry, &fibh, &cfi); + if (!fi) + goto out; + + inode = dentry->d_inode; + + retval = -EIO; + if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) != inode->i_ino) + goto end_rmdir; + retval = -ENOTEMPTY; + if (!empty_dir(inode)) + goto end_rmdir; + retval = udf_delete_entry(fi, &fibh, &cfi); + dir->i_version = ++event; + if (retval) + goto end_rmdir; + if (inode->i_nlink != 2) + udf_warning(inode->i_sb, "udf_rmdir", + "empty directory has nlink != 2 (%d)", + inode->i_nlink); + inode->i_version = ++event; + inode->i_nlink = 0; + inode->i_size = 0; + mark_inode_dirty(inode); + dir->i_nlink --; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + UDF_I_UCTIME(inode) = UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME; + mark_inode_dirty(dir); + d_delete(dentry); + +end_rmdir: + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); +out: + return retval; +} + +int udf_unlink(struct inode * dir, struct dentry * dentry) +{ + int retval; + struct inode * inode; + struct udf_fileident_bh fibh; + struct FileIdentDesc *fi; + struct FileIdentDesc cfi; + + retval = -ENOENT; + fi = udf_find_entry(dir, dentry, &fibh, &cfi); + if (!fi) + goto out; + + inode = dentry->d_inode; + + retval = -EIO; + + if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) != + inode->i_ino) + { + goto end_unlink; + } + + if (!inode->i_nlink) + { + udf_debug("Deleting nonexistent file (%lu), %d\n", + inode->i_ino, inode->i_nlink); + inode->i_nlink = 1; + } + retval = udf_delete_entry(fi, &fibh, &cfi); + if (retval) + goto end_unlink; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME; + mark_inode_dirty(dir); + inode->i_nlink--; + mark_inode_dirty(inode); + inode->i_ctime = dir->i_ctime; + retval = 0; + d_delete(dentry); /* This also frees the inode */ + +end_unlink: + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); +out: + return retval; +} + +int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname) +{ + struct inode * inode; + struct PathComponent *pc; + struct udf_fileident_bh fibh; + struct buffer_head *bh = NULL; + int eoffset, elen = 0; + struct FileIdentDesc *fi; + struct FileIdentDesc cfi; + char *ea; + int err; + + if (!(inode = udf_new_inode(dir, S_IFLNK, &err))) + goto out; + + inode->i_mode = S_IFLNK | S_IRWXUGO; + inode->i_op = &udf_symlink_inode_operations; + + bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize); + ea = bh->b_data + udf_file_entry_alloc_offset(inode); + + eoffset = inode->i_sb->s_blocksize - (ea - bh->b_data); + pc = (struct PathComponent *)ea; + + if (*symname == '/') + { + do + { + symname++; + } while (*symname == '/'); + + pc->componentType = 1; + pc->lengthComponentIdent = 0; + pc->componentFileVersionNum = 0; + pc += sizeof(struct PathComponent); + elen += sizeof(struct PathComponent); + } + + while (*symname && eoffset > elen + sizeof(struct PathComponent)) + { + char *compstart; + pc = (struct PathComponent *)(ea + elen); + + compstart = (char *)symname; + + do + { + symname++; + } while (*symname && *symname != '/'); + + pc->componentType = 5; + pc->lengthComponentIdent = 0; + pc->componentFileVersionNum = 0; + if (pc->componentIdent[0] == '.') + { + if (pc->lengthComponentIdent == 1) + pc->componentType = 4; + else if (pc->lengthComponentIdent == 2 && pc->componentIdent[1] == '.') + pc->componentType = 3; + } + + if (pc->componentType == 5) + { + if (elen + sizeof(struct PathComponent) + symname - compstart > eoffset) + pc->lengthComponentIdent = eoffset - elen - sizeof(struct PathComponent); + else + pc->lengthComponentIdent = symname - compstart; + + memcpy(pc->componentIdent, compstart, pc->lengthComponentIdent); + } + + elen += sizeof(struct PathComponent) + pc->lengthComponentIdent; + + if (*symname) + { + do + { + symname++; + } while (*symname == '/'); + } + } + + udf_release_data(bh); + UDF_I_LENALLOC(inode) = inode->i_size = elen; + mark_inode_dirty(inode); + + if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) + goto out; + cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); + cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); + if (UDF_SB_LVIDBH(inode->i_sb)) + { + struct LogicalVolHeaderDesc *lvhd; + Uint64 uniqueID; + lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse); + uniqueID = le64_to_cpu(lvhd->uniqueID); + *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse = + le32_to_cpu(uniqueID & 0x00000000FFFFFFFFUL); + if (!(++uniqueID & 0x00000000FFFFFFFFUL)) + uniqueID += 16; + lvhd->uniqueID = cpu_to_le64(uniqueID); + mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1); + } + udf_write_fi(&cfi, fi, &fibh, NULL, NULL); + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) + { + mark_inode_dirty(dir); + dir->i_version = ++event; + } + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + d_instantiate(dentry, inode); + err = 0; + +out: + return err; +} + +int udf_link(struct dentry * old_dentry, struct inode * dir, + struct dentry *dentry) +{ + struct inode *inode = old_dentry->d_inode; + struct udf_fileident_bh fibh; + int err; + struct FileIdentDesc cfi, *fi; + + if (S_ISDIR(inode->i_mode)) + return -EPERM; + + if (inode->i_nlink >= (256<i_nlink))-1) + return -EMLINK; + + if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) + return err; + cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); + cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); + if (UDF_SB_LVIDBH(inode->i_sb)) + { + struct LogicalVolHeaderDesc *lvhd; + Uint64 uniqueID; + lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse); + uniqueID = le64_to_cpu(lvhd->uniqueID); + *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse = + cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL); + if (!(++uniqueID & 0x00000000FFFFFFFFUL)) + uniqueID += 16; + lvhd->uniqueID = cpu_to_le64(uniqueID); + mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1); + } + udf_write_fi(&cfi, fi, &fibh, NULL, NULL); + if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) + { + mark_inode_dirty(dir); + dir->i_version = ++event; + } + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); + inode->i_nlink ++; + inode->i_ctime = CURRENT_TIME; + UDF_I_UCTIME(inode) = CURRENT_UTIME; + mark_inode_dirty(inode); + inode->i_count ++; + d_instantiate(dentry, inode); + return 0; +} + +/* Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +int udf_rename (struct inode * old_dir, struct dentry * old_dentry, + struct inode * new_dir, struct dentry * new_dentry) +{ + struct inode * old_inode, * new_inode; + struct udf_fileident_bh ofibh, nfibh; + struct FileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi; + struct buffer_head *dir_bh = NULL; + int retval = -ENOENT; + + old_inode = old_dentry->d_inode; + ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi); + if (!ofi || udf_get_lb_pblock(old_dir->i_sb, lelb_to_cpu(ocfi.icb.extLocation), 0) != + old_inode->i_ino) + { + goto end_rename; + } + + new_inode = new_dentry->d_inode; + nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi); + if (nfi) + { + if (!new_inode) + { + if (nfibh.sbh != nfibh.ebh) + udf_release_data(nfibh.ebh); + udf_release_data(nfibh.sbh); + nfi = NULL; + } + else + { +/* + DQUOT_INIT(new_inode); +*/ + } + } + if (S_ISDIR(old_inode->i_mode)) + { + Uint32 offset = UDF_I_EXT0OFFS(old_inode); + + if (new_inode) + { + retval = -ENOTEMPTY; + if (!empty_dir(new_inode)) + goto end_rename; + } + retval = -EIO; + dir_bh = udf_bread(old_inode, 0, 0, &retval); + if (!dir_bh) + goto end_rename; + dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset); + if (!dir_fi) + goto end_rename; + if (udf_get_lb_pblock(old_inode->i_sb, cpu_to_lelb(dir_fi->icb.extLocation), 0) != + old_dir->i_ino) + { + goto end_rename; + } + retval = -EMLINK; + if (!new_inode && new_dir->i_nlink >= (256<i_nlink))-1) + goto end_rename; + } + if (!nfi) + { + nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval); + if (!nfi) + goto end_rename; + } + new_dir->i_version = ++event; + + /* + * ok, that's it + */ + ncfi.fileVersionNum = ocfi.fileVersionNum; + ncfi.fileCharacteristics = ocfi.fileCharacteristics; + memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad)); + udf_write_fi(&ncfi, nfi, &nfibh, NULL, NULL); + + udf_delete_entry(ofi, &ofibh, &ocfi); + + old_dir->i_version = ++event; + if (new_inode) + { + new_inode->i_nlink--; + new_inode->i_ctime = CURRENT_TIME; + UDF_I_UCTIME(new_inode) = CURRENT_UTIME; + mark_inode_dirty(new_inode); + } + old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; + UDF_I_UCTIME(old_dir) = UDF_I_UMTIME(old_dir) = CURRENT_UTIME; + mark_inode_dirty(old_dir); + + if (dir_bh) + { + dir_fi->icb.extLocation = lelb_to_cpu(UDF_I_LOCATION(new_dir)); + udf_update_tag((char *)dir_fi, sizeof(struct FileIdentDesc) + + cpu_to_le16(dir_fi->lengthOfImpUse)); + if (UDF_I_ALLOCTYPE(old_inode) == ICB_FLAG_AD_IN_ICB) + { + mark_inode_dirty(old_inode); + old_inode->i_version = ++event; + } + else + mark_buffer_dirty(dir_bh, 1); + old_dir->i_nlink --; + mark_inode_dirty(old_dir); + if (new_inode) + { + new_inode->i_nlink --; + mark_inode_dirty(new_inode); + } + else + { + new_dir->i_nlink ++; + mark_inode_dirty(new_dir); + } + } + + retval = 0; + +end_rename: + udf_release_data(dir_bh); + if (ofi) + { + if (ofibh.sbh != ofibh.ebh) + udf_release_data(ofibh.ebh); + udf_release_data(ofibh.sbh); + } + if (nfi) + { + if (nfibh.sbh != nfibh.ebh) + udf_release_data(nfibh.ebh); + udf_release_data(nfibh.sbh); + } + return retval; +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/partition.c linux/fs/udf/partition.c --- v2.3.16/linux/fs/udf/partition.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/partition.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,190 @@ +/* + * partition.c + * + * PURPOSE + * Partition handling routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1998-1999 Ben Fennema + * + * HISTORY + * + * 12/06/98 blf Created file. + * + */ + +#include "udfdecl.h" +#include "udf_sb.h" +#include "udf_i.h" + +#include +#include +#include + +extern Uint32 udf_get_pblock(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset) +{ + Uint16 ident; + + if (partition >= UDF_SB_NUMPARTS(sb)) + { + udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n", + block, partition, offset); + return 0xFFFFFFFF; + } + switch (UDF_SB_PARTTYPE(sb, partition)) + { + case UDF_TYPE1_MAP15: + { + return UDF_SB_PARTROOT(sb, partition) + block + offset; + } + case UDF_VIRTUAL_MAP15: + case UDF_VIRTUAL_MAP20: + { + struct buffer_head *bh = NULL; + Uint32 newblock; + Uint32 index; + Uint32 loc; + + index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(Uint32); + + + if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries) + { + udf_debug("Trying to access block beyond end of VAT (%d max %d)\n", + block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries); + return 0xFFFFFFFF; + } + + if (block >= index) + { + block -= index; + newblock = 1 + (block / (sb->s_blocksize / sizeof(Uint32))); + index = block % (sb->s_blocksize / sizeof(Uint32)); + } + else + { + newblock = 0; + index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(Uint32) + block; + } + + loc = udf_locked_block_map(UDF_SB_VAT(sb), newblock); + + if (!(bh = bread(sb->s_dev, loc, sb->s_blocksize))) + { + udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n", + sb, block, partition, loc, index); + return 0xFFFFFFFF; + } + + loc = le32_to_cpu(((Uint32 *)bh->b_data)[index]); + + udf_release_data(bh); + + if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition) + { + udf_debug("recursive call to udf_get_pblock!\n"); + return 0xFFFFFFFF; + } + + return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset); + } + case UDF_SPARABLE_MAP15: + { + Uint32 newblock = UDF_SB_PARTROOT(sb, partition) + block + offset; + Uint32 spartable = UDF_SB_TYPESPAR(sb, partition).s_spar_loc; + Uint32 plength = UDF_SB_TYPESPAR(sb,partition).s_spar_plen; + Uint32 packet = (block + offset) & (~(plength-1)); + struct buffer_head *bh = NULL; + struct SparingTable *st; + SparingEntry *se; + + bh = udf_read_tagged(sb, spartable, spartable, &ident); + + if (!bh) + { + printk(KERN_ERR "udf: udf_read_tagged(%p,%d,%d)\n", + sb, spartable, spartable); + return 0xFFFFFFFF; + } + + st = (struct SparingTable *)bh->b_data; + if (ident == 0) + { + if (!strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING))) + { + Uint16 rtl = le16_to_cpu(st->reallocationTableLen); + Uint16 index; + + /* If the sparing table span multiple blocks, find out which block we are on */ + + se = &(st->mapEntry[0]); + + if (rtl * sizeof(SparingEntry) + sizeof(struct SparingTable) > sb->s_blocksize) + { + index = (sb->s_blocksize - sizeof(struct SparingTable)) / sizeof(SparingEntry); + if (le32_to_cpu(se[index-1].origLocation) == packet) + { + udf_release_data(bh); + return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1)); + } + else if (le32_to_cpu(se[index-1].origLocation) < packet) + { + do + { + udf_release_data(bh); + bh = udf_tread(sb, spartable, sb->s_blocksize); + if (!bh) + return 0xFFFFFFFF; + se = (SparingEntry *)bh->b_data; + spartable ++; + rtl -= index; + index = sb->s_blocksize / sizeof(SparingEntry); + + if (le32_to_cpu(se[index].origLocation) == packet) + { + udf_release_data(bh); + return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1)); + } + } while (rtl * sizeof(SparingEntry) > sb->s_blocksize && + le32_to_cpu(se[index-1].origLocation) < packet); + } + } + + for (index=0; index packet) + { + udf_release_data(bh); + return newblock; + } + } + + udf_release_data(bh); + return newblock; + } + } + udf_release_data(bh); + } + } + return 0xFFFFFFFF; +} + +extern Uint32 udf_get_lb_pblock(struct super_block *sb, lb_addr loc, Uint32 offset) +{ + return udf_get_pblock(sb, loc.logicalBlockNum, loc.partitionReferenceNum, offset); +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/super.c linux/fs/udf/super.c --- v2.3.16/linux/fs/udf/super.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/super.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,1623 @@ +/* + * super.c + * + * PURPOSE + * Super block routines for the OSTA-UDF(tm) filesystem. + * + * DESCRIPTION + * OSTA-UDF(tm) = Optical Storage Technology Association + * Universal Disk Format. + * + * This code is based on version 2.00 of the UDF specification, + * and revision 3 of the ECMA 167 standard [equivalent to ISO 13346]. + * http://www.osta.org/ + * http://www.ecma.ch/ + * http://www.iso.org/ + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1998 Dave Boynton + * (C) 1998-1999 Ben Fennema + * + * HISTORY + * + * 09/24/98 dgb changed to allow compiling outside of kernel, and + * added some debugging. + * 10/01/98 dgb updated to allow (some) possibility of compiling w/2.0.34 + * 10/16/98 attempting some multi-session support + * 10/17/98 added freespace count for "df" + * 11/11/98 gr added novrs option + * 11/26/98 dgb added fileset,anchor mount options + * 12/06/98 blf really hosed things royally. vat/sparing support. sequenced vol descs + * rewrote option handling based on isofs + * 12/20/98 find the free space bitmap (if it exists) + */ + +#ifndef LINUX_VERSION_CODE +#include +#endif + +#include "udfdecl.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "udf_sb.h" +#include "udf_i.h" + +#include +#include + +static char error_buf[1024]; + +/* These are the "meat" - everything else is stuffing */ +static struct super_block *udf_read_super(struct super_block *, void *, int); +static void udf_put_super(struct super_block *); +static int udf_remount_fs(struct super_block *, int *, char *); +static int udf_check_valid(struct super_block *, int, int); +static int udf_vrs(struct super_block *sb, int silent); +static int udf_load_partition(struct super_block *, lb_addr *); +static int udf_load_logicalvol(struct super_block *, struct buffer_head *, lb_addr *); +static void udf_load_logicalvolint(struct super_block *, extent_ad); +static int udf_find_anchor(struct super_block *, int, int); +static int udf_find_fileset(struct super_block *, lb_addr *, lb_addr *); +static void udf_load_pvoldesc(struct super_block *, struct buffer_head *); +static void udf_load_fileset(struct super_block *, struct buffer_head *, lb_addr *); +static void udf_load_partdesc(struct super_block *, struct buffer_head *); +static void udf_open_lvid(struct super_block *); +static void udf_close_lvid(struct super_block *); +static unsigned int udf_count_free(struct super_block *); + +/* version specific functions */ +static int udf_statfs(struct super_block *, struct statfs *, int); + +/* UDF filesystem type */ +static struct file_system_type udf_fstype = { + "udf", /* name */ + FS_REQUIRES_DEV, /* fs_flags */ + udf_read_super, /* read_super */ + NULL /* next */ +}; + +/* Superblock operations */ +static struct super_operations udf_sb_ops = +{ + udf_read_inode, /* read_inode */ +#ifdef CONFIG_UDF_RW + udf_write_inode, /* write_inode */ +#else + NULL, /* write_inode */ +#endif + udf_put_inode, /* put_inode */ +#ifdef CONFIG_UDF_RW + udf_delete_inode, /* delete_inode */ +#else + NULL, /* delete_inode */ +#endif + NULL, /* notify_change */ + udf_put_super, /* put_super */ + NULL, /* write_super */ + udf_statfs, /* statfs */ + udf_remount_fs, /* remount_fs */ + NULL, /* clear_inode */ + NULL, /* umount_begin */ +}; + +struct udf_options +{ + unsigned char novrs; + unsigned char utf8; + unsigned int blocksize; + unsigned int session; + unsigned int lastblock; + unsigned int anchor; + unsigned int volume; + unsigned short partition; + unsigned int fileset; + unsigned int rootdir; + unsigned int flags; + mode_t umask; + gid_t gid; + uid_t uid; + char *iocharset; +}; + +#if defined(MODULE) + +/* + * cleanup_module + * + * PURPOSE + * Unregister the UDF filesystem type. + * + * DESCRIPTION + * Clean-up before the module is unloaded. + * This routine only applies when compiled as a module. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +int +cleanup_module(void) +{ + printk(KERN_NOTICE "udf: unregistering filesystem\n"); + return unregister_filesystem(&udf_fstype); +} + +/* + * init_module / init_udf_fs + * + * PURPOSE + * Register the UDF filesystem type. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +int init_module(void) +#else /* if !defined(MODULE) */ +int __init init_udf_fs(void) +#endif +{ + printk(KERN_NOTICE "udf: registering filesystem\n"); + { + struct super_block sb; + int size; + + size = sizeof(struct super_block) + + (int)&sb.u - (int)&sb; + if ( size < sizeof(struct udf_sb_info) ) + { + printk(KERN_ERR "udf: Danger! Kernel was compiled without enough room for udf_sb_info\n"); + printk(KERN_ERR "udf: Kernel has room for %u bytes, udf needs %u\n", + size, sizeof(struct udf_sb_info)); + return 0; + } + } + return register_filesystem(&udf_fstype); +} + +/* + * udf_parse_options + * + * PURPOSE + * Parse mount options. + * + * DESCRIPTION + * The following mount options are supported: + * + * gid= Set the default group. + * umask= Set the default umask. + * uid= Set the default user. + * unhide Show otherwise hidden files. + * undelete Show deleted files in lists. + * strict Set strict conformance (unused) + * utf8 (unused) + * iocharset (unused) + * + * The remaining are for debugging and disaster recovery: + * + * bs= Set the block size. (may not work unless 2048) + * novrs Skip volume sequence recognition + * + * The following expect a offset from 0. + * + * session= Set the CDROM session (default= last session) + * anchor= Override standard anchor location. (default= 256) + * volume= Override the VolumeDesc location. (unused) + * partition= Override the PartitionDesc location. (unused) + * lastblock= Set the last block of the filesystem/ + * + * The following expect a offset from the partition root. + * + * fileset= Override the fileset block location. (unused) + * rootdir= Override the root directory location. (unused) + * WARNING: overriding the rootdir to a non-directory may + * yield highly unpredictable results. + * + * PRE-CONDITIONS + * options Pointer to mount options string. + * uopts Pointer to mount options variable. + * + * POST-CONDITIONS + * 0 Mount options parsed okay. + * -1 Error parsing mount options. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ + +static int +udf_parse_options(char *options, struct udf_options *uopt) +{ + char *opt, *val; + + uopt->novrs = 0; + uopt->blocksize = 2048; + uopt->partition = 0xFFFF; + uopt->session = 0xFFFFFFFF; + uopt->lastblock = 0xFFFFFFFF; + uopt->anchor = 0xFFFFFFFF; + uopt->volume = 0xFFFFFFFF; + uopt->rootdir = 0xFFFFFFFF; + uopt->fileset = 0xFFFFFFFF; + uopt->iocharset = NULL; + + if (!options) + return 1; + + for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) + { + /* Make "opt=val" into two strings */ + val = strchr(opt, '='); + if (val) + *(val++) = 0; + if (!strcmp(opt, "novrs") && !val) + uopt->novrs = 1; + else if (!strcmp(opt, "utf8") && !val) + uopt->utf8 = 1; + else if (!strcmp(opt, "bs") && val) + uopt->blocksize = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "unhide") && !val) + uopt->flags |= UDF_FLAG_UNHIDE; + else if (!strcmp(opt, "undelete") && !val) + uopt->flags |= UDF_FLAG_UNDELETE; + else if (!strcmp(opt, "gid") && val) + uopt->gid = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "umask") && val) + uopt->umask = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "strict") && !val) + uopt->flags |= UDF_FLAG_STRICT; + else if (!strcmp(opt, "uid") && val) + uopt->uid = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "session") && val) + uopt->session = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "lastblock") && val) + uopt->lastblock = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "anchor") && val) + uopt->anchor = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "volume") && val) + uopt->volume = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "partition") && val) + uopt->partition = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "fileset") && val) + uopt->fileset = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "rootdir") && val) + uopt->rootdir = simple_strtoul(val, NULL, 0); + else if (!strcmp(opt, "iocharset") && val) + { + uopt->iocharset = val; + while (*val && *val != ',') + val ++; + if (val == uopt->iocharset) + return 0; + *val = 0; + } + else if (val) + { + printk(KERN_ERR "udf: bad mount option \"%s=%s\"\n", + opt, val); + return 0; + } + else + { + printk(KERN_ERR "udf: bad mount option \"%s\"\n", + opt); + return 0; + } + } + return 1; +} + +static int +udf_remount_fs(struct super_block *sb, int *flags, char *options) +{ + struct udf_options uopt; + + uopt.flags = UDF_SB(sb)->s_flags ; + uopt.uid = UDF_SB(sb)->s_uid ; + uopt.gid = UDF_SB(sb)->s_gid ; + uopt.umask = UDF_SB(sb)->s_umask ; + uopt.utf8 = UDF_SB(sb)->s_utf8 ; + + if ( !udf_parse_options(options, &uopt) ) + return -EINVAL; + + UDF_SB(sb)->s_flags = uopt.flags; + UDF_SB(sb)->s_uid = uopt.uid; + UDF_SB(sb)->s_gid = uopt.gid; + UDF_SB(sb)->s_umask = uopt.umask; + UDF_SB(sb)->s_utf8 = uopt.utf8; + + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + return 0; + if (*flags & MS_RDONLY) + udf_close_lvid(sb); + else + udf_open_lvid(sb); + + return 0; +} + +/* + * udf_set_blocksize + * + * PURPOSE + * Set the block size to be used in all transfers. + * + * DESCRIPTION + * To allow room for a DMA transfer, it is best to guess big when unsure. + * This routine picks 2048 bytes as the blocksize when guessing. This + * should be adequate until devices with larger block sizes become common. + * + * Note that the Linux kernel can currently only deal with blocksizes of + * 512, 1024, 2048, 4096, and 8192 bytes. + * + * PRE-CONDITIONS + * sb Pointer to _locked_ superblock. + * + * POST-CONDITIONS + * sb->s_blocksize Blocksize. + * sb->s_blocksize_bits log2 of blocksize. + * 0 Blocksize is valid. + * 1 Blocksize is invalid. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +static int +udf_set_blocksize(struct super_block *sb, int bsize) +{ + /* Use specified block size if specified */ + sb->s_blocksize = get_hardblocksize(sb->s_dev); + sb->s_blocksize = sb->s_blocksize ? sb->s_blocksize : 2048; + if (bsize > sb->s_blocksize) + sb->s_blocksize = bsize; + + /* Block size must be an even multiple of 512 */ + switch (sb->s_blocksize) { + case 512: sb->s_blocksize_bits = 9; break; + case 1024: sb->s_blocksize_bits = 10; break; + case 2048: sb->s_blocksize_bits = 11; break; + case 4096: sb->s_blocksize_bits = 12; break; + case 8192: sb->s_blocksize_bits = 13; break; + default: + { + udf_debug("Bad block size (%ld)\n", sb->s_blocksize); + printk(KERN_ERR "udf: bad block size (%ld)\n", sb->s_blocksize); + return 0; + } + } + + /* Set the block size */ + set_blocksize(sb->s_dev, sb->s_blocksize); + return sb->s_blocksize; +} + +static int +udf_vrs(struct super_block *sb, int silent) +{ + struct VolStructDesc *vsd = NULL; + int sector = 32768; + struct buffer_head *bh = NULL; + int iso9660=0; + int nsr02=0; + int nsr03=0; + + /* Block size must be a multiple of 512 */ + if (sb->s_blocksize & 511) + return sector; + + sector += (UDF_SB_SESSION(sb) << sb->s_blocksize_bits); + + udf_debug("Starting at sector %u (%ld byte sectors)\n", + (sector >> sb->s_blocksize_bits), sb->s_blocksize); + /* Process the sequence (if applicable) */ + for (;!nsr02 && !nsr03; sector += 2048) + { + /* Read a block */ + bh = udf_tread(sb, sector >> sb->s_blocksize_bits, 2048); + if (!bh) + break; + + /* Look for ISO descriptors */ + vsd = (struct VolStructDesc *)(bh->b_data + + (sector & (sb->s_blocksize - 1))); + + if (vsd->stdIdent[0] == 0) + { + udf_release_data(bh); + break; + } + else if (!strncmp(vsd->stdIdent, STD_ID_CD001, STD_ID_LEN)) + { + iso9660 = sector; + switch (vsd->structType) + { + case 0: + udf_debug("ISO9660 Boot Record found\n"); + break; + case 1: + udf_debug("ISO9660 Primary Volume Descriptor found\n"); + break; + case 2: + udf_debug("ISO9660 Supplementary Volume Descriptor found\n"); + break; + case 3: + udf_debug("ISO9660 Volume Partition Descriptor found\n"); + break; + case 255: + udf_debug("ISO9660 Volume Descriptor Set Terminator found\n"); + break; + default: + udf_debug("ISO9660 VRS (%u) found\n", vsd->structType); + break; + } + } + else if (!strncmp(vsd->stdIdent, STD_ID_BEA01, STD_ID_LEN)) + { + } + else if (!strncmp(vsd->stdIdent, STD_ID_TEA01, STD_ID_LEN)) + { + udf_release_data(bh); + break; + } + else if (!strncmp(vsd->stdIdent, STD_ID_NSR02, STD_ID_LEN)) + { + nsr02 = sector; + } + else if (!strncmp(vsd->stdIdent, STD_ID_NSR03, STD_ID_LEN)) + { + nsr03 = sector; + } + udf_release_data(bh); + } + + if (nsr03) + return nsr03; + else if (nsr02) + return nsr02; + else if (sector - (UDF_SB_SESSION(sb) << sb->s_blocksize_bits) == 32768) + return -1; + else + return 0; +} + +/* + * udf_find_anchor + * + * PURPOSE + * Find an anchor volume descriptor. + * + * PRE-CONDITIONS + * sb Pointer to _locked_ superblock. + * lastblock Last block on media. + * + * POST-CONDITIONS + * 1 if not found, 0 if ok + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +static int +udf_find_anchor(struct super_block *sb, int useranchor, int lastblock) +{ + int varlastblock = udf_variable_to_fixed(lastblock); + int last[] = { lastblock, lastblock - 2, + lastblock - 150, lastblock - 152, + varlastblock, varlastblock - 2, + varlastblock - 150, varlastblock - 152 }; + struct buffer_head *bh = NULL; + Uint16 ident; + Uint32 location; + int i; + + UDF_SB_ANCHOR(sb)[0] = 0; + UDF_SB_ANCHOR(sb)[1] = 0; + UDF_SB_ANCHOR(sb)[2] = 0; + UDF_SB_ANCHOR(sb)[3] = 256 + UDF_SB_SESSION(sb); + + lastblock = 0; + + /* Search for an anchor volume descriptor pointer */ + + /* according to spec, anchor is in either: + * block 256 + * lastblock-256 + * lastblock + * however, if the disc isn't closed, it could be 512 */ + + for (i=0; (!lastblock && is_dev, last[i], sb->s_blocksize))) + { + ident = location = 0; + } + else + { + ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); + location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); + udf_release_data(bh); + } + + if (ident == TID_ANCHOR_VOL_DESC_PTR) + { + if (location == last[i] - UDF_SB_SESSION(sb)) + { + lastblock = UDF_SB_ANCHOR(sb)[0] = last[i]; + UDF_SB_ANCHOR(sb)[1] = last[i] - 256; + } + else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb)) + { + UDF_SB(sb)->s_flags |= UDF_FLAG_VARCONV; + lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]); + UDF_SB_ANCHOR(sb)[1] = lastblock - 256; + } + else + udf_debug("Anchor found at block %d, location mismatch %d.\n", + last[i], location); + } + else if (ident == TID_FILE_ENTRY || ident == TID_EXTENDED_FILE_ENTRY) + { + lastblock = last[i]; + UDF_SB_ANCHOR(sb)[2] = 512 + UDF_SB_SESSION(sb); + } + else + { + if (!(bh = bread(sb->s_dev, last[i] - 256, sb->s_blocksize))) + { + ident = location = 0; + } + else + { + ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); + location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); + udf_release_data(bh); + } + + if (ident == TID_ANCHOR_VOL_DESC_PTR && + location == last[i] - 256 - UDF_SB_SESSION(sb)) + { + lastblock = last[i]; + UDF_SB_ANCHOR(sb)[1] = last[i] - 256; + } + else + { + if (!(bh = bread(sb->s_dev, last[i] - 312 - UDF_SB_SESSION(sb), + sb->s_blocksize))) + { + ident = location = 0; + } + else + { + ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); + location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); + udf_release_data(bh); + } + + if (ident == TID_ANCHOR_VOL_DESC_PTR && + location == udf_variable_to_fixed(last[i]) - 256) + { + UDF_SB(sb)->s_flags |= UDF_FLAG_VARCONV; + lastblock = udf_variable_to_fixed(last[i]); + UDF_SB_ANCHOR(sb)[1] = lastblock - 256; + } + } + } + } + + if (!lastblock) + { + /* We havn't found the lastblock. check 312 */ + if ((bh = bread(sb->s_dev, 312 + UDF_SB_SESSION(sb), sb->s_blocksize))) + { + ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); + location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); + udf_release_data(bh); + + if (ident == TID_ANCHOR_VOL_DESC_PTR && location == 256) + UDF_SB(sb)->s_flags |= UDF_FLAG_VARCONV; + } + } + + for (i=0; ilogicalBlockNum != 0xFFFFFFFF || + fileset->partitionReferenceNum != 0xFFFF) + { + bh = udf_read_ptagged(sb, *fileset, 0, &ident); + + if (!bh) + return 1; + else if (ident != TID_FILE_SET_DESC) + { + udf_release_data(bh); + return 1; + } + + } + + if (!bh) /* Search backwards through the partitions */ + { + lb_addr newfileset; + + return 1; + + for (newfileset.partitionReferenceNum=UDF_SB_NUMPARTS(sb)-1; + (newfileset.partitionReferenceNum != 0xFFFF && + fileset->logicalBlockNum == 0xFFFFFFFF && + fileset->partitionReferenceNum == 0xFFFF); + newfileset.partitionReferenceNum--) + { + lastblock = UDF_SB_PARTLEN(sb, newfileset.partitionReferenceNum); + newfileset.logicalBlockNum = 0; + + do + { + bh = udf_read_ptagged(sb, newfileset, 0, &ident); + if (!bh) + { + newfileset.logicalBlockNum ++; + continue; + } + + switch (ident) + { + case TID_SPACE_BITMAP_DESC: + { + struct SpaceBitmapDesc *sp; + sp = (struct SpaceBitmapDesc *)bh->b_data; + newfileset.logicalBlockNum += 1 + + ((le32_to_cpu(sp->numOfBytes) + sizeof(struct SpaceBitmapDesc) - 1) + >> sb->s_blocksize_bits); + udf_release_data(bh); + break; + } + case TID_FILE_SET_DESC: + { + *fileset = newfileset; + break; + } + default: + { + newfileset.logicalBlockNum ++; + udf_release_data(bh); + bh = NULL; + break; + } + } + } + while (newfileset.logicalBlockNum < lastblock && + fileset->logicalBlockNum == 0xFFFFFFFF && + fileset->partitionReferenceNum == 0xFFFF); + } + } + + if ((fileset->logicalBlockNum != 0xFFFFFFFF || + fileset->partitionReferenceNum != 0xFFFF) && bh) + { + udf_debug("Fileset at block=%d, partition=%d\n", + fileset->logicalBlockNum, fileset->partitionReferenceNum); + + UDF_SB_PARTITION(sb) = fileset->partitionReferenceNum; + udf_load_fileset(sb, bh, root); + udf_release_data(bh); + return 0; + } + return 1; +} + +static void +udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) +{ + struct PrimaryVolDesc *pvoldesc; + time_t recording; + struct ustr instr; + struct ustr outstr; + + pvoldesc = (struct PrimaryVolDesc *)bh->b_data; + + if ( udf_stamp_to_time(&recording, lets_to_cpu(pvoldesc->recordingDateAndTime)) ) + { + timestamp ts; + ts = lets_to_cpu(pvoldesc->recordingDateAndTime); + udf_debug("recording time %ld, %u/%u/%u %u:%u (%x)\n", + recording, ts.year, ts.month, ts.day, ts.hour, ts.minute, + ts.typeAndTimezone); + UDF_SB_RECORDTIME(sb) = recording; + } + + if ( !udf_build_ustr(&instr, pvoldesc->volIdent, 32) ) + { + if (!udf_CS0toUTF8(&outstr, &instr)) + { + udf_debug("volIdent[] = '%s'\n", outstr.u_name); + strncpy( UDF_SB_VOLIDENT(sb), outstr.u_name, outstr.u_len); + } + } + + if ( !udf_build_ustr(&instr, pvoldesc->volSetIdent, 128) ) + { + if (!udf_CS0toUTF8(&outstr, &instr)) + udf_debug("volSetIdent[] = '%s'\n", outstr.u_name); + } +} + +static void +udf_load_fileset(struct super_block *sb, struct buffer_head *bh, lb_addr *root) +{ + struct FileSetDesc *fset; + + fset = (struct FileSetDesc *)bh->b_data; + + *root = lelb_to_cpu(fset->rootDirectoryICB.extLocation); + + UDF_SB_SERIALNUM(sb) = le16_to_cpu(fset->descTag.tagSerialNum); + + udf_debug("Rootdir at block=%d, partition=%d\n", + root->logicalBlockNum, root->partitionReferenceNum); +} + +static void +udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) +{ + struct PartitionDesc *p; + int i; + + p=(struct PartitionDesc *)bh->b_data; + + for (i=0; ipartitionNumber)); + if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber)) + { + UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */ + UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation) + UDF_SB_SESSION(sb); + UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap = 0xFFFFFFFF; + + if (!strcmp(p->partitionContents.ident, PARTITION_CONTENTS_NSR02) || + !strcmp(p->partitionContents.ident, PARTITION_CONTENTS_NSR03)) + { + struct PartitionHeaderDesc *phd; + + phd = (struct PartitionHeaderDesc *)(p->partitionContentsUse); + if (phd->unallocatedSpaceTable.extLength) + udf_debug("unallocatedSpaceTable (part %d)\n", i); + if (phd->unallocatedSpaceBitmap.extLength) + { + UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap = + le32_to_cpu(phd->unallocatedSpaceBitmap.extPosition); + udf_debug("unallocatedSpaceBitmap (part %d) @ %d\n", + i, UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap); + } + if (phd->partitionIntegrityTable.extLength) + udf_debug("partitionIntegrityTable (part %d)\n", i); + if (phd->freedSpaceTable.extLength) + udf_debug("freedSpaceTable (part %d)\n", i); + if (phd->freedSpaceBitmap.extLength) + udf_debug("freedSpaceBitmap (part %d\n", i); + } + break; + } + } + if (i == UDF_SB_NUMPARTS(sb)) + { + udf_debug("Partition (%d) not found in partition map\n", le16_to_cpu(p->partitionNumber)); + } + else + { + udf_debug("Partition (%d:%d type %x) starts at physical %d, block length %d\n", + le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i), + UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i)); + } +} + +static int +udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, lb_addr *fileset) +{ + struct LogicalVolDesc *lvd; + int i, offset; + Uint8 type; + + lvd = (struct LogicalVolDesc *)bh->b_data; + + UDF_SB_NUMPARTS(sb) = le32_to_cpu(lvd->numPartitionMaps); + UDF_SB_ALLOC_PARTMAPS(sb, UDF_SB_NUMPARTS(sb)); + + for (i=0,offset=0; + imapTableLength); + i++,offset+=((struct GenericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength) + { + type = ((struct GenericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapType; + udf_debug("Partition (%d) type %d\n", i, type); + if (type == 1) + { + struct GenericPartitionMap1 *gpm1 = (struct GenericPartitionMap1 *)&(lvd->partitionMaps[offset]); + UDF_SB_PARTTYPE(sb,i) = UDF_TYPE1_MAP15; + UDF_SB_PARTVSN(sb,i) = le16_to_cpu(gpm1->volSeqNum); + UDF_SB_PARTNUM(sb,i) = le16_to_cpu(gpm1->partitionNum); + } + else if (type == 2) + { + struct UdfPartitionMap2 *upm2 = (struct UdfPartitionMap2 *)&(lvd->partitionMaps[offset]); + if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL))) + { + if (le16_to_cpu(((Uint16 *)upm2->partIdent.identSuffix)[0]) == 0x0150) + UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP15; + else if (le16_to_cpu(((Uint16 *)upm2->partIdent.identSuffix)[0]) == 0x0200) + UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP20; + } + else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) + { + struct SparablePartitionMap *spm = (struct SparablePartitionMap *)&(lvd->partitionMaps[offset]); + UDF_SB_PARTTYPE(sb,i) = UDF_SPARABLE_MAP15; + UDF_SB_TYPESPAR(sb,i).s_spar_plen = le16_to_cpu(spm->packetLength); + UDF_SB_TYPESPAR(sb,i).s_spar_loc = le32_to_cpu(spm->locSparingTable[0]); + } + else + { + udf_debug("Unknown ident: %s\n", upm2->partIdent.ident); + continue; + } + UDF_SB_PARTVSN(sb,i) = le16_to_cpu(upm2->volSeqNum); + UDF_SB_PARTNUM(sb,i) = le16_to_cpu(upm2->partitionNum); + } + } + + if (fileset) + { + long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]); + + *fileset = lelb_to_cpu(la->extLocation); + udf_debug("FileSet found in LogicalVolDesc at block=%d, partition=%d\n", + fileset->logicalBlockNum, + fileset->partitionReferenceNum); + } + if (lvd->integritySeqExt.extLength) + udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); + return 0; +} + +/* + * udf_load_logicalvolint + * + */ +static void +udf_load_logicalvolint(struct super_block *sb, extent_ad loc) +{ + struct buffer_head *bh = NULL; + Uint16 ident; + + while ((bh = udf_read_tagged(sb, loc.extLocation, loc.extLocation, &ident)) && + ident == TID_LOGICAL_VOL_INTEGRITY_DESC && loc.extLength > 0) + { + UDF_SB_LVIDBH(sb) = bh; + + if (UDF_SB_LVID(sb)->nextIntegrityExt.extLength) + udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt)); + + if (UDF_SB_LVIDBH(sb) != bh) + udf_release_data(bh); + loc.extLength -= sb->s_blocksize; + loc.extLocation ++; + } + if (UDF_SB_LVIDBH(sb) != bh) + udf_release_data(bh); +} + +/* + * udf_process_sequence + * + * PURPOSE + * Process a main/reserve volume descriptor sequence. + * + * PRE-CONDITIONS + * sb Pointer to _locked_ superblock. + * block First block of first extent of the sequence. + * lastblock Lastblock of first extent of the sequence. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +static int +udf_process_sequence(struct super_block *sb, long block, long lastblock, lb_addr *fileset) +{ + struct buffer_head *bh = NULL; + struct udf_vds_record vds[VDS_POS_LENGTH]; + struct GenericDesc *gd; + int done=0; + int i,j; + Uint32 vdsn; + Uint16 ident; + + memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); + + /* Read the main descriptor sequence */ + for (;(!done && block <= lastblock); block++) + { + + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) + break; + + /* Process each descriptor (ISO 13346 3/8.3-8.4) */ + gd = (struct GenericDesc *)bh->b_data; + vdsn = le32_to_cpu(gd->volDescSeqNum); + switch (ident) + { + case TID_PRIMARY_VOL_DESC: /* ISO 13346 3/10.1 */ + if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum) + { + vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn; + vds[VDS_POS_PRIMARY_VOL_DESC].block = block; + } + break; + case TID_VOL_DESC_PTR: /* ISO 13346 3/10.3 */ + if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum) + { + vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn; + vds[VDS_POS_VOL_DESC_PTR].block = block; + } + break; + case TID_IMP_USE_VOL_DESC: /* ISO 13346 3/10.4 */ + if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum) + { + vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn; + vds[VDS_POS_IMP_USE_VOL_DESC].block = block; + } + break; + case TID_PARTITION_DESC: /* ISO 13346 3/10.5 */ + if (!vds[VDS_POS_PARTITION_DESC].block) + vds[VDS_POS_PARTITION_DESC].block = block; + break; + case TID_LOGICAL_VOL_DESC: /* ISO 13346 3/10.6 */ + if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum) + { + vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn; + vds[VDS_POS_LOGICAL_VOL_DESC].block = block; + } + break; + case TID_UNALLOC_SPACE_DESC: /* ISO 13346 3/10.8 */ + if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum) + { + vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn; + vds[VDS_POS_UNALLOC_SPACE_DESC].block = block; + } + break; + case TID_TERMINATING_DESC: /* ISO 13346 3/10.9 */ + vds[VDS_POS_TERMINATING_DESC].block = block; + done = 1; + break; + } + udf_release_data(bh); + } + for (i=0; ib_data; + if (ident == TID_PARTITION_DESC) + udf_load_partdesc(sb, bh2); + udf_release_data(bh2); + } + } + udf_release_data(bh); + } + } + + return 0; +} + +/* + * udf_check_valid() + */ +static int +udf_check_valid(struct super_block *sb, int novrs, int silent) +{ + long block; + + if (novrs) + { + udf_debug("Validity check skipped because of novrs option\n"); + return 0; + } + /* Check that it is NSR02 compliant */ + /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ + else if ((block = udf_vrs(sb, silent)) == -1) + { + udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n"); + return 0; + } + else + return !block; +} + +static int +udf_load_partition(struct super_block *sb, lb_addr *fileset) +{ + struct AnchorVolDescPtr *anchor; + Uint16 ident; + struct buffer_head *bh; + long main_s, main_e, reserve_s, reserve_e; + int i; + + if (!sb) + return 1; + + for (i=0; ib_data; + + /* Locate the main sequence */ + main_s = le32_to_cpu( anchor->mainVolDescSeqExt.extLocation ); + main_e = le32_to_cpu( anchor->mainVolDescSeqExt.extLength ); + main_e = main_e >> sb->s_blocksize_bits; + main_e += main_s; + + /* Locate the reserve sequence */ + reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation); + reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength); + reserve_e = reserve_e >> sb->s_blocksize_bits; + reserve_e += reserve_s; + + udf_release_data(bh); + + /* Process the main & reserve sequences */ + /* responsible for finding the PartitionDesc(s) */ + if (!(udf_process_sequence(sb, main_s, main_e, fileset) && + udf_process_sequence(sb, reserve_s, reserve_e, fileset))) + { + break; + } + } + } + + if (i == sizeof(UDF_SB_ANCHOR(sb))/sizeof(int)) + { + udf_debug("No Anchor block found\n"); + return 1; + } + else + udf_debug("Using anchor in block %d\n", UDF_SB_ANCHOR(sb)[i]); + + for (i=0; ii_size - 36) / sizeof(Uint32); + } + else if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP20) + { + struct buffer_head *bh = NULL; + Uint32 pos; + + pos = udf_block_map(UDF_SB_VAT(sb), 0); + bh = bread(sb->s_dev, pos, sb->s_blocksize); + UDF_SB_TYPEVIRT(sb,i).s_start_offset = + le16_to_cpu(((struct VirtualAllocationTable20 *)bh->b_data + UDF_I_EXT0OFFS(UDF_SB_VAT(sb)))->lengthHeader) + + UDF_I_EXT0OFFS(UDF_SB_VAT(sb)); + UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - + UDF_SB_TYPEVIRT(sb,i).s_start_offset) / sizeof(Uint32); + udf_release_data(bh); + } + UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0); + UDF_SB_PARTLEN(sb,i) = UDF_SB_PARTLEN(sb,ino.partitionReferenceNum); + UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap = 0xFFFFFFFF; + } + } + } + return 0; +} + +static void udf_open_lvid(struct super_block *sb) +{ +#ifdef CONFIG_UDF_RW + if (UDF_SB_LVIDBH(sb)) + { + int i; + timestamp cpu_time; + + UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; + UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; + if (udf_time_to_stamp(&cpu_time, CURRENT_TIME, CURRENT_UTIME)) + UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time); + UDF_SB_LVID(sb)->integrityType = INTEGRITY_TYPE_OPEN; + + UDF_SB_LVID(sb)->descTag.descCRC = + cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag), + le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0)); + + UDF_SB_LVID(sb)->descTag.tagChecksum = 0; + for (i=0; i<16; i++) + if (i != 4) + UDF_SB_LVID(sb)->descTag.tagChecksum += + ((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i]; + + mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + } +#endif +} + +static void udf_close_lvid(struct super_block *sb) +{ +#ifdef CONFIG_UDF_RW + if (UDF_SB_LVIDBH(sb) && + UDF_SB_LVID(sb)->integrityType == INTEGRITY_TYPE_OPEN) + { + int i; + timestamp cpu_time; + + UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; + UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; + if (udf_time_to_stamp(&cpu_time, CURRENT_TIME, CURRENT_UTIME)) + UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time); + + UDF_SB_LVID(sb)->integrityType = INTEGRITY_TYPE_CLOSE; + + UDF_SB_LVID(sb)->descTag.descCRC = + cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag), + le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0)); + + UDF_SB_LVID(sb)->descTag.tagChecksum = 0; + for (i=0; i<16; i++) + if (i != 4) + UDF_SB_LVID(sb)->descTag.tagChecksum += + ((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i]; + + mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1); + } +#endif +} + +/* + * udf_read_super + * + * PURPOSE + * Complete the specified super block. + * + * PRE-CONDITIONS + * sb Pointer to superblock to complete - never NULL. + * sb->s_dev Device to read suberblock from. + * options Pointer to mount options. + * silent Silent flag. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +static struct super_block * +udf_read_super(struct super_block *sb, void *options, int silent) +{ + struct inode *inode=NULL; + struct udf_options uopt; + lb_addr rootdir, fileset; + int i; + + uopt.flags = 0; + uopt.uid = 0; + uopt.gid = 0; + uopt.umask = 0; + uopt.utf8 = 0; + + /* Lock the module in memory (if applicable) */ + MOD_INC_USE_COUNT; + + lock_super(sb); + + UDF_SB_PARTMAPS(sb) = NULL; + UDF_SB_LVIDBH(sb) = NULL; + UDF_SB_VAT(sb) = NULL; + + if (!udf_parse_options((char *)options, &uopt)) + goto error_out; + + memset(UDF_SB_ANCHOR(sb), 0x00, sizeof(UDF_SB_ANCHOR(sb))); + fileset.logicalBlockNum = 0xFFFFFFFF; + fileset.partitionReferenceNum = 0xFFFF; + UDF_SB_RECORDTIME(sb)=0; + UDF_SB_VOLIDENT(sb)[0]=0; + + UDF_SB(sb)->s_flags = uopt.flags; + UDF_SB(sb)->s_uid = uopt.uid; + UDF_SB(sb)->s_gid = uopt.gid; + UDF_SB(sb)->s_umask = uopt.umask; + UDF_SB(sb)->s_utf8 = uopt.utf8; + + /* Set the block size for all transfers */ + if (!udf_set_blocksize(sb, uopt.blocksize)) + goto error_out; + + if ( uopt.session == 0xFFFFFFFF ) + UDF_SB_SESSION(sb) = udf_get_last_session(sb->s_dev); + else + UDF_SB_SESSION(sb) = uopt.session; + + udf_debug("Multi-session=%d\n", UDF_SB_SESSION(sb)); + + if ( uopt.lastblock == 0xFFFFFFFF ) + UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb->s_dev, &(UDF_SB(sb)->s_flags)); + else + UDF_SB_LASTBLOCK(sb) = uopt.lastblock; + + UDF_SB_LASTBLOCK(sb) = udf_find_anchor(sb, uopt.anchor, UDF_SB_LASTBLOCK(sb)); + + udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb)); + + if (udf_check_valid(sb, uopt.novrs, silent)) /* read volume recognition sequences */ + { + udf_debug("No VRS found\n"); + goto error_out; + } + + UDF_SB_CHARSET(sb) = NULL; + +#ifdef CONFIG_NLS + if (uopt.utf8 == 0) + { + char *p = uopt.iocharset ? uopt.iocharset : "iso8859-1"; + UDF_SB_CHARSET(sb) = load_nls(p); + if (!UDF_SB_CHARSET(sb)) + if (uopt.iocharset) + goto error_out; + UDF_SB_CHARSET(sb) = load_nls_default(); + } +#endif + + /* Fill in the rest of the superblock */ + sb->s_op = &udf_sb_ops; + sb->s_time = 0; + sb->dq_op = NULL; + sb->s_dirt = 0; + sb->s_magic = UDF_SUPER_MAGIC; + + for (i=0; is_flags & MS_RDONLY)) + udf_open_lvid(sb); + unlock_super(sb); + + /* Assign the root inode */ + /* assign inodes by physical block number */ + /* perhaps it's not extensible enough, but for now ... */ + inode = udf_iget(sb, rootdir); + if (!inode) + { + udf_debug("Error in udf_iget, block=%d, partition=%d\n", + rootdir.logicalBlockNum, rootdir.partitionReferenceNum); + goto error_out; + } + + /* Allocate a dentry for the root inode */ + sb->s_root = d_alloc_root(inode); + if (!sb->s_root) + { + iput(inode); + udf_debug("Couldn't allocate root dentry\n"); + goto error_out; + } + + return sb; + +error_out: + sb->s_dev = NODEV; + if (UDF_SB_VAT(sb)) + iput(UDF_SB_VAT(sb)); + if (!(sb->s_flags & MS_RDONLY)) + udf_close_lvid(sb); + udf_release_data(UDF_SB_LVIDBH(sb)); + UDF_SB_FREE(sb); + unlock_super(sb); + MOD_DEC_USE_COUNT; + return NULL; +} + +void udf_error(struct super_block *sb, const char *function, + const char *fmt, ...) +{ + va_list args; + + if (!(sb->s_flags & MS_RDONLY)) + { + /* mark sb error */ + sb->s_dirt = 1; + } + va_start(args, fmt); + vsprintf(error_buf, fmt, args); + va_end(args); + printk (KERN_CRIT "UDF-fs error (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); +} + +void udf_warning(struct super_block *sb, const char *function, + const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vsprintf(error_buf, fmt, args); + va_end(args); + printk(KERN_WARNING "UDF-fs warning (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); +} + +/* + * udf_put_super + * + * PURPOSE + * Prepare for destruction of the superblock. + * + * DESCRIPTION + * Called before the filesystem is unmounted. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +static void +udf_put_super(struct super_block *sb) +{ + int i; + + if (UDF_SB_VAT(sb)) + iput(UDF_SB_VAT(sb)); + if (!(sb->s_flags & MS_RDONLY)) + udf_close_lvid(sb); + udf_release_data(UDF_SB_LVIDBH(sb)); + for (i=0; is_blocksize; + tmp.f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)); + tmp.f_bfree = udf_count_free(sb); + tmp.f_bavail = tmp.f_bfree; + tmp.f_files = (UDF_SB_LVIDBH(sb) ? + (le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) + + le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + tmp.f_bfree; + tmp.f_ffree = tmp.f_bfree; + /* __kernel_fsid_t f_fsid */ + tmp.f_namelen = UDF_NAME_LEN; + + rc= copy_to_user(buf, &tmp, size) ? -EFAULT: 0; + return rc; +} + +static unsigned char udf_bitmap_lookup[16] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 +}; + +static unsigned int +udf_count_free(struct super_block *sb) +{ + struct buffer_head *bh = NULL; + unsigned int accum=0; + int index; + int block=0, newblock; + lb_addr loc; + Uint32 bytes; + Uint8 value; + Uint8 * ptr; + Uint16 ident; + + if (UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap == 0xFFFFFFFF) + { + if (UDF_SB_LVIDBH(sb)) + { + if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb)) + accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]); + + if (accum == 0xFFFFFFFF) + accum = 0; + + return accum; + } + else + return 0; + } + else + { + struct SpaceBitmapDesc *bm; + loc.logicalBlockNum = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap; + loc.partitionReferenceNum = UDF_SB_PARTITION(sb); + bh = udf_read_ptagged(sb, loc, 0, &ident); + + if (!bh) + { + printk(KERN_ERR "udf: udf_count_free failed\n"); + return 0; + } + else if (ident != TID_SPACE_BITMAP_DESC) + { + udf_release_data(bh); + printk(KERN_ERR "udf: udf_count_free failed\n"); + return 0; + } + + bm = (struct SpaceBitmapDesc *)bh->b_data; + bytes = bm->numOfBytes; + index = sizeof(struct SpaceBitmapDesc); /* offset in first block only */ + ptr = (Uint8 *)bh->b_data; + + while ( bytes > 0 ) + { + while ((bytes > 0) && (index < sb->s_blocksize)) + { + value = ptr[index]; + accum += udf_bitmap_lookup[ value & 0x0f ]; + accum += udf_bitmap_lookup[ value >> 4 ]; + index++; + bytes--; + } + if ( bytes ) + { + udf_release_data(bh); + newblock = udf_get_lb_pblock(sb, loc, ++block); + bh = udf_tread(sb, newblock, sb->s_blocksize); + if (!bh) + { + udf_debug("read failed\n"); + return accum; + } + index = 0; + ptr = (Uint8 *)bh->b_data; + } + } + udf_release_data(bh); + return accum; + } +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/symlink.c linux/fs/udf/symlink.c --- v2.3.16/linux/fs/udf/symlink.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/symlink.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,189 @@ +/* + * symlink.c + * + * PURPOSE + * Symlink handling routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1998-1999 Ben Fennema + * (C) 1999 Stelias Computing Inc + * + * HISTORY + * + * 04/16/99 blf Created. + * + */ + +#include "udfdecl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "udf_i.h" + +static int udf_readlink(struct dentry *, char *, int); +static struct dentry * udf_follow_link(struct dentry * dentry, + struct dentry * base, unsigned int follow); + +/* + * symlinks can't do much... + */ +struct inode_operations udf_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + udf_readlink, /* readlink */ + udf_follow_link,/* follow_link */ + NULL, /* get_block */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* flushpage */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +int udf_pc_to_char(char *from, int fromlen, char **to) +{ + struct PathComponent *pc; + int elen = 0, len = 0; + + *to = (char *)kmalloc(fromlen, GFP_KERNEL); + + if (!(*to)) + return -1; + + while (elen < fromlen) + { + pc = (struct PathComponent *)(from + elen); + if (pc->componentType == 1 && pc->lengthComponentIdent == 0) + { + (*to)[0] = '/'; + len = 1; + } + else if (pc->componentType == 3) + { + memcpy(&(*to)[len], "../", 3); + len += 3; + } + else if (pc->componentType == 4) + { + memcpy(&(*to)[len], "./", 2); + len += 2; + } + else if (pc->componentType == 5) + { + memcpy(&(*to)[len], pc->componentIdent, pc->lengthComponentIdent); + len += pc->lengthComponentIdent + 1; + (*to)[len-1] = '/'; + } + elen += sizeof(struct PathComponent) + pc->lengthComponentIdent; + } + + if (len) + { + len --; + (*to)[len] = '\0'; + } + return len; +} + +static struct dentry * udf_follow_link(struct dentry * dentry, + struct dentry * base, unsigned int follow) +{ + struct inode *inode = dentry->d_inode; + struct buffer_head *bh = NULL; + char *symlink, *tmpbuf; + int len; + + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) + { + bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize); + + if (!bh) + return 0; + + symlink = bh->b_data + udf_file_entry_alloc_offset(inode); + } + else + { + bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize); + + if (!bh) + return 0; + + symlink = bh->b_data; + } + + if ((len = udf_pc_to_char(symlink, inode->i_size, &tmpbuf)) >= 0) + { + base = lookup_dentry(tmpbuf, base, follow); + kfree(tmpbuf); + return base; + } + else + return ERR_PTR(-ENOMEM); +} + +static int udf_readlink(struct dentry * dentry, char * buffer, int buflen) +{ + struct inode *inode = dentry->d_inode; + struct buffer_head *bh = NULL; + char *symlink, *tmpbuf; + int len; + + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) + { + bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize); + + if (!bh) + return 0; + + symlink = bh->b_data + udf_file_entry_alloc_offset(inode); + } + else + { + bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize); + + if (!bh) + return 0; + + symlink = bh->b_data; + } + + if ((len = udf_pc_to_char(symlink, inode->i_size, &tmpbuf)) >= 0) + { + if (copy_to_user(buffer, tmpbuf, len > buflen ? buflen : len)) + len = -EFAULT; + kfree(tmpbuf); + } + else + len = -ENOMEM; + + UPDATE_ATIME(inode); + if (bh) + udf_release_data(bh); + return len; +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/truncate.c linux/fs/udf/truncate.c --- v2.3.16/linux/fs/udf/truncate.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/truncate.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,229 @@ +/* + * truncate.c + * + * PURPOSE + * Truncate handling routines for the OSTA-UDF(tm) filesystem. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * (C) 1999 Ben Fennema + * (C) 1999 Stelias Computing Inc + * + * HISTORY + * + * 02/24/99 blf Created. + * + */ + +#include "udfdecl.h" +#include +#include +#include + +#include "udf_i.h" +#include "udf_sb.h" + +static void extent_trunc(struct inode * inode, lb_addr bloc, int *extoffset, + lb_addr eloc, Uint32 elen, struct buffer_head **bh, Uint32 offset) +{ + lb_addr neloc = { 0, 0 }; + int nelen = 0; + int blocks = inode->i_sb->s_blocksize / 512; + int last_block = (elen + inode->i_sb->s_blocksize - 1) / inode->i_sb->s_blocksize; + + + if (offset) + { + nelen = ((offset - 1) << inode->i_sb->s_blocksize_bits) + + (inode->i_size & (inode->i_sb->s_blocksize - 1)); + neloc = eloc; + } + + inode->i_blocks -= (blocks * (last_block - offset)); + udf_write_aext(inode, bloc, extoffset, neloc, nelen, bh, 1); + if (!memcmp(&UDF_I_EXT0LOC(inode), &eloc, sizeof(lb_addr))) + { + UDF_I_EXT0LOC(inode) = neloc; + UDF_I_EXT0LEN(inode) = nelen; + } + mark_inode_dirty(inode); + udf_free_blocks(inode, eloc, offset, last_block - offset); +} + +static void trunc(struct inode * inode) +{ + lb_addr bloc, eloc, neloc = { 0, 0 }; + Uint32 extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc; + int etype; + int first_block = (inode->i_size + inode->i_sb->s_blocksize - 1) / inode->i_sb->s_blocksize; + struct buffer_head *bh = NULL; + int adsize; + + if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT) + adsize = sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG) + adsize = sizeof(long_ad); + else + adsize = 0; + + if ((etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh)) != -1) + { + extoffset -= adsize; + extent_trunc(inode, bloc, &extoffset, eloc, elen, &bh, offset); + + if (offset) + lenalloc = extoffset; + else + lenalloc = extoffset - adsize; + + if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) + lenalloc -= udf_file_entry_alloc_offset(inode); + else + lenalloc -= sizeof(struct AllocExtDesc); + + while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1) + { + if (etype == EXTENT_NEXT_EXTENT_ALLOCDECS) + { + udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 0); + extoffset = 0; + if (lelen) + { + if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) + memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode)); + else + memset(bh->b_data, 0x00, sizeof(struct AllocExtDesc)); + udf_free_blocks(inode, bloc, 0, lelen); + } + else + { + if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) + UDF_I_LENALLOC(inode) = lenalloc; + else + { + struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh->b_data); + aed->lengthAllocDescs = cpu_to_le32(lenalloc); + } + } + + udf_release_data(bh); + bh = NULL; + + bloc = eloc; + if (elen) + lelen = (elen + inode->i_sb->s_blocksize - 1) >> + inode->i_sb->s_blocksize_bits; + else + lelen = 1; + } + else if (etype != EXTENT_NOT_RECORDED_NOT_ALLOCATED) + extent_trunc(inode, bloc, &extoffset, eloc, elen, &bh, 0); + else + udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 1); + } + + if (lelen) + { + if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) + memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode)); + else + memset(bh->b_data, 0x00, sizeof(struct AllocExtDesc)); + udf_free_blocks(inode, bloc, 0, lelen); + } + else + { + if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) + UDF_I_LENALLOC(inode) = lenalloc; + else + { + struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh->b_data); + aed->lengthAllocDescs = cpu_to_le32(lenalloc); + } + } + } + else if (inode->i_size) + { + lb_addr e0loc = UDF_I_LOCATION(inode); + Uint32 ext0offset = udf_file_entry_alloc_offset(inode); + char tetype; + + if (offset) + { + extoffset -= adsize; + tetype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1); + if (tetype == EXTENT_NOT_RECORDED_NOT_ALLOCATED) + { + extoffset -= adsize; + elen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) | + (elen + (offset << inode->i_sb->s_blocksize_bits)); + if (ext0offset == extoffset && !memcmp(&e0loc, &bloc, sizeof(lb_addr))) + UDF_I_EXT0LEN(inode) = elen; + udf_write_aext(inode, bloc, &extoffset, eloc, elen, &bh, 0); + } + else + { + if (elen & (inode->i_sb->s_blocksize - 1)) + { + extoffset -= adsize; + elen = (EXTENT_RECORDED_ALLOCATED << 30) | + ((elen + inode->i_sb->s_blocksize - 1) & + ~(inode->i_sb->s_blocksize - 1)); + if (ext0offset == extoffset && !memcmp(&e0loc, &bloc, sizeof(lb_addr))) + UDF_I_EXT0LEN(inode) = elen; + udf_write_aext(inode, bloc, &extoffset, eloc, elen, &bh, 1); + } + memset(&eloc, 0x00, sizeof(lb_addr)); + elen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) | + (offset << inode->i_sb->s_blocksize_bits); + if (ext0offset == extoffset && !memcmp(&e0loc, &bloc, sizeof(lb_addr))) + { + UDF_I_EXT0LOC(inode) = eloc; + UDF_I_EXT0LEN(inode) = elen; + } + udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1); + } + } + } + + udf_release_data(bh); +} + +void udf_truncate(struct inode * inode) +{ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + + if (!UDF_I_EXT0OFFS(inode)) + { + udf_discard_prealloc(inode); + + trunc(inode); + } + + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); +} + +void udf_truncate_adinicb(struct inode * inode) +{ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); +} diff -u --recursive --new-file v2.3.16/linux/fs/udf/udf_i.h linux/fs/udf/udf_i.h --- v2.3.16/linux/fs/udf/udf_i.h Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/udf_i.h Sat Sep 4 12:42:30 1999 @@ -0,0 +1,24 @@ +#ifndef __LINUX_UDF_I_H +#define __LINUX_UDF_I_H + +#define UDF_I(X) (&((X)->u.udf_i)) + +#define UDF_I_EXT0LOC(X) ( UDF_I(X)->i_ext0Location ) +#define UDF_I_EXT0LEN(X) ( UDF_I(X)->i_ext0Length ) +#define UDF_I_EXT0OFFS(X) ( UDF_I(X)->i_ext0Offset ) +#define UDF_I_LOCATION(X) ( UDF_I(X)->i_location ) +#define UDF_I_LENEATTR(X) ( UDF_I(X)->i_lenEAttr ) +#define UDF_I_LENALLOC(X) ( UDF_I(X)->i_lenAlloc ) +#define UDF_I_UNIQUE(X) ( UDF_I(X)->i_unique ) +#define UDF_I_ALLOCTYPE(X) ( UDF_I(X)->i_alloc_type ) +#define UDF_I_EXTENDED_FE(X)( UDF_I(X)->i_extended_fe ) +#define UDF_I_STRAT4096(X) ( UDF_I(X)->i_strat_4096 ) +#define UDF_I_PREALLOC_COUNT(X) ( UDF_I(X)->i_prealloc_count ) +#define UDF_I_PREALLOC_BLOCK(X) ( UDF_I(X)->i_prealloc_block ) +#define UDF_I_NEXT_ALLOC_BLOCK(X) ( UDF_I(X)->i_next_alloc_block ) +#define UDF_I_NEXT_ALLOC_GOAL(X) ( UDF_I(X)->i_next_alloc_goal ) +#define UDF_I_UATIME(X) ( UDF_I(X)->i_uatime ) +#define UDF_I_UMTIME(X) ( UDF_I(X)->i_umtime ) +#define UDF_I_UCTIME(X) ( UDF_I(X)->i_uctime ) + +#endif /* !defined(_LINUX_UDF_I_H) */ diff -u --recursive --new-file v2.3.16/linux/fs/udf/udf_sb.h linux/fs/udf/udf_sb.h --- v2.3.16/linux/fs/udf/udf_sb.h Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/udf_sb.h Sat Sep 4 12:42:30 1999 @@ -0,0 +1,66 @@ +#ifndef __LINUX_UDF_SB_H +#define __LINUX_UDF_SB_H + +#include +#include + +/* Since UDF 1.50 is ISO 13346 based... */ +#define UDF_SUPER_MAGIC 0x15013346 + +#define UDF_FLAG_STRICT 0x00000001U +#define UDF_FLAG_UNDELETE 0x00000002U +#define UDF_FLAG_UNHIDE 0x00000004U +#define UDF_FLAG_VARCONV 0x00000008U + +#define UDF_SB_FREE(X)\ +{\ + if (UDF_SB(X))\ + {\ + if (UDF_SB_PARTMAPS(X))\ + kfree(UDF_SB_PARTMAPS(X));\ + UDF_SB_PARTMAPS(X) = NULL;\ + }\ +} +#define UDF_SB(X) (&((X)->u.udf_sb)) + +#define UDF_SB_ALLOC_PARTMAPS(X,Y)\ +{\ + UDF_SB_NUMPARTS(X) = Y;\ + UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\ +} + +#define IS_STRICT(X) ( UDF_SB(X)->s_flags & UDF_FLAG_STRICT ) +#define IS_UNDELETE(X) ( UDF_SB(X)->s_flags & UDF_FLAG_UNDELETE ) +#define IS_UNHIDE(X) ( UDF_SB(X)->s_flags & UDF_FLAG_UNHIDE ) + +#define UDF_SB_SESSION(X) ( UDF_SB(X)->s_session ) +#define UDF_SB_ANCHOR(X) ( UDF_SB(X)->s_anchor ) +#define UDF_SB_NUMPARTS(X) ( UDF_SB(X)->s_partitions ) +#define UDF_SB_VOLUME(X) ( UDF_SB(X)->s_thisvolume ) +#define UDF_SB_LASTBLOCK(X) ( UDF_SB(X)->s_lastblock ) +#define UDF_SB_VOLDESC(X) ( UDF_SB(X)->s_voldesc ) +#define UDF_SB_LVIDBH(X) ( UDF_SB(X)->s_lvidbh ) +#define UDF_SB_LVID(X) ( (struct LogicalVolIntegrityDesc *)UDF_SB_LVIDBH(X)->b_data ) +#define UDF_SB_LVIDIU(X) ( (struct LogicalVolIntegrityDescImpUse *)&(UDF_SB_LVID(sb)->impUse[UDF_SB_LVID(sb)->numOfPartitions * 2 * sizeof(Uint32)/sizeof(Uint8)]) ) +#define UDF_SB_PARTITION(X) ( UDF_SB(X)->s_partition ) +#define UDF_SB_RECORDTIME(X) ( UDF_SB(X)->s_recordtime ) +#define UDF_SB_VOLIDENT(X) ( UDF_SB(X)->s_volident ) +#define UDF_SB_PARTMAPS(X) ( UDF_SB(X)->s_partmaps ) +#define UDF_SB_LOCATION(X) ( UDF_SB(X)->s_location ) +#define UDF_SB_SERIALNUM(X) ( UDF_SB(X)->s_serialnum ) +#define UDF_SB_CHARSET(X) ( UDF_SB(X)->s_nls_iocharset ) +#define UDF_SB_VAT(X) ( UDF_SB(X)->s_vat ) + +#define UDF_SB_BLOCK_BITMAP_NUMBER(X,Y) ( UDF_SB(X)->s_block_bitmap_number[Y] ) +#define UDF_SB_BLOCK_BITMAP(X,Y) ( UDF_SB(X)->s_block_bitmap[Y] ) +#define UDF_SB_LOADED_BLOCK_BITMAPS(X) ( UDF_SB(X)->s_loaded_block_bitmaps ) + +#define UDF_SB_PARTTYPE(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_partition_type ) +#define UDF_SB_PARTROOT(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_partition_root ) +#define UDF_SB_PARTLEN(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_partition_len ) +#define UDF_SB_PARTVSN(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_volumeseqnum ) +#define UDF_SB_PARTNUM(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_partition_num ) +#define UDF_SB_TYPESPAR(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_type_specific.s_sparing ) +#define UDF_SB_TYPEVIRT(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_type_specific.s_virtual ) + +#endif /* __LINUX_UDF_SB_H */ diff -u --recursive --new-file v2.3.16/linux/fs/udf/udfdecl.h linux/fs/udf/udfdecl.h --- v2.3.16/linux/fs/udf/udfdecl.h Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/udfdecl.h Sat Sep 4 12:42:30 1999 @@ -0,0 +1,278 @@ +#ifndef __UDF_DECL_H +#define __UDF_DECL_H + +#define UDF_VERSION_NOTICE "v0.8.9" + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +#ifndef LINUX_VERSION_CODE +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,7) +#error "The UDF Module Current Requires Kernel Version 2.3.7 or greater" +#endif + +/* if we're not defined, we must be compiling outside of the kernel tree */ +#if !defined(CONFIG_UDF_FS) && !defined(CONFIG_UDF_FS_MODULE) +/* ... so override config */ +#define CONFIG_UDF_FS_MODULE +#include +/* explicitly include udf_fs_sb.h and udf_fs_i.h */ +#include +#include +#else +#include /* also gets udf_fs_i.h and udf_fs_sb.h */ +#endif + +struct dentry; +struct inode; +struct task_struct; +struct buffer_head; +struct super_block; + +extern struct inode_operations udf_dir_inode_operations; +extern struct inode_operations udf_file_inode_operations; +extern struct inode_operations udf_file_inode_operations_adinicb; +extern struct inode_operations udf_symlink_inode_operations; + +struct udf_fileident_bh +{ + struct buffer_head *sbh; + struct buffer_head *ebh; + int soffset; + int eoffset; +}; + +extern void udf_error(struct super_block *, const char *, const char *, ...); +extern void udf_warning(struct super_block *, const char *, const char *, ...); +extern int udf_write_fi(struct FileIdentDesc *, struct FileIdentDesc *, struct udf_fileident_bh *, Uint8 *, Uint8 *); +extern struct dentry * udf_lookup(struct inode *, struct dentry *); +extern int udf_create(struct inode *, struct dentry *, int); +extern int udf_mknod(struct inode *, struct dentry *, int, int); +extern int udf_mkdir(struct inode *, struct dentry *, int); +extern int udf_rmdir(struct inode *, struct dentry *); +extern int udf_unlink(struct inode *, struct dentry *); +extern int udf_symlink(struct inode *, struct dentry *, const char *); +extern int udf_link(struct dentry *, struct inode *, struct dentry *); +extern int udf_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); +extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +extern struct inode *udf_iget(struct super_block *, lb_addr); +extern int udf_sync_inode(struct inode *); +extern struct buffer_head * udf_expand_adinicb(struct inode *, int *, int, int *); +extern struct buffer_head * udf_getblk(struct inode *, long, int, int *); +extern int udf_get_block(struct inode *, long, struct buffer_head *, int); +extern struct buffer_head * udf_bread(struct inode *, int, int, int *); +extern void udf_read_inode(struct inode *); +extern void udf_put_inode(struct inode *); +extern void udf_delete_inode(struct inode *); +extern void udf_write_inode(struct inode *); +extern long udf_locked_block_map(struct inode *, long); +extern long udf_block_map(struct inode *, long); +extern int inode_bmap(struct inode *, int, lb_addr *, Uint32 *, lb_addr *, Uint32 *, Uint32 *, struct buffer_head **); +extern int udf_add_aext(struct inode *, lb_addr *, int *, lb_addr, Uint32, struct buffer_head **, int); +extern int udf_write_aext(struct inode *, lb_addr, int *, lb_addr, Uint32, struct buffer_head **, int); +extern int udf_insert_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *); +extern int udf_delete_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *); +extern int udf_next_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int); +extern int udf_current_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int); + +extern int udf_read_tagged_data(char *, int size, int fd, int block, int partref); + +extern struct buffer_head *udf_tread(struct super_block *, int, int); +extern struct GenericAttrFormat *udf_add_extendedattr(struct inode *, Uint32, Uint32, Uint8, struct buffer_head **); +extern struct GenericAttrFormat *udf_get_extendedattr(struct inode *, Uint32, Uint8, struct buffer_head **); +extern struct buffer_head *udf_read_tagged(struct super_block *, Uint32, Uint32, Uint16 *); +extern struct buffer_head *udf_read_ptagged(struct super_block *, lb_addr, Uint32, Uint16 *); +extern struct buffer_head *udf_read_untagged(struct super_block *, Uint32, Uint32); +extern void udf_release_data(struct buffer_head *); + +extern unsigned int udf_get_last_session(kdev_t); +extern unsigned int udf_get_last_block(kdev_t, int *); + +extern Uint32 udf_get_pblock(struct super_block *, Uint32, Uint16, Uint32); +extern Uint32 udf_get_lb_pblock(struct super_block *, lb_addr, Uint32); + +extern int udf_get_filename(Uint8 *, Uint8 *, int); + +extern void udf_free_inode(struct inode *); +extern struct inode * udf_new_inode (const struct inode *, int, int *); +extern void udf_discard_prealloc(struct inode *); +extern void udf_truncate(struct inode *); +extern void udf_truncate_adinicb(struct inode *); +extern void udf_free_blocks(const struct inode *, lb_addr, Uint32, Uint32); +extern int udf_alloc_blocks(const struct inode *, Uint16, Uint32, Uint32); +extern int udf_new_block(const struct inode *, Uint16, Uint32, int *); +extern int udf_sync_file(struct file *, struct dentry *); + +#else + +#include +#include + +#endif /* __KERNEL__ */ + +#include "udfend.h" + +/* structures */ +struct udf_directory_record +{ + Uint32 d_parent; + Uint32 d_inode; + Uint32 d_name[255]; +}; + +#define VDS_POS_PRIMARY_VOL_DESC 0 +#define VDS_POS_UNALLOC_SPACE_DESC 1 +#define VDS_POS_LOGICAL_VOL_DESC 2 +#define VDS_POS_PARTITION_DESC 3 +#define VDS_POS_IMP_USE_VOL_DESC 4 +#define VDS_POS_VOL_DESC_PTR 5 +#define VDS_POS_TERMINATING_DESC 6 +#define VDS_POS_LENGTH 7 + +struct udf_vds_record +{ + Uint32 block; + Uint32 volDescSeqNum; +}; + +struct ktm +{ + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_isdst; +}; + +struct ustr +{ + Uint8 u_cmpID; + Uint8 u_name[UDF_NAME_LEN-1]; + Uint8 u_len; + Uint8 padding; + unsigned long u_hash; +}; + + +#define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) ) +#define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) ) + +#ifdef __KERNEL__ + +#define CURRENT_UTIME (xtime.tv_usec) + +#define udf_file_entry_alloc_offset(inode)\ + ((UDF_I_EXTENDED_FE(inode) ?\ + sizeof(struct ExtendedFileEntry) :\ + sizeof(struct FileEntry)) + UDF_I_LENEATTR(inode)) + +#define udf_clear_bit(nr,addr) ext2_clear_bit(nr,addr) +#define udf_set_bit(nr,addr) ext2_set_bit(nr,addr) +#define udf_test_bit(nr, addr) ext2_test_bit(nr, addr) +#define udf_find_first_one_bit(addr, size) find_first_one_bit(addr, size) +#define udf_find_next_one_bit(addr, size, offset) find_next_one_bit(addr, size, offset) + +#define leBPL_to_cpup(x) leNUM_to_cpup(BITS_PER_LONG, x) +#define leNUM_to_cpup(x,y) xleNUM_to_cpup(x,y) +#define xleNUM_to_cpup(x,y) (le ## x ## _to_cpup(y)) + +extern inline int find_next_one_bit (void * addr, int size, int offset) +{ + unsigned long * p = ((unsigned long *) addr) + (offset / BITS_PER_LONG); + unsigned long result = offset & ~(BITS_PER_LONG-1); + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= (BITS_PER_LONG-1); + if (offset) + { + tmp = leBPL_to_cpup(p++); + tmp &= ~0UL << offset; + if (size < BITS_PER_LONG) + goto found_first; + if (tmp) + goto found_middle; + size -= BITS_PER_LONG; + result += BITS_PER_LONG; + } + while (size & ~(BITS_PER_LONG-1)) + { + if ((tmp = leBPL_to_cpup(p++))) + goto found_middle; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; + } + if (!size) + return result; + tmp = leBPL_to_cpup(p); +found_first: + tmp &= ~0UL >> (BITS_PER_LONG-size); +found_middle: + return result + ffz(~tmp); +} + +#define find_first_one_bit(addr, size)\ + find_next_one_bit((addr), (size), 0) + +#endif + +/* Miscellaneous UDF Prototypes */ + +extern int udf_ustr_to_dchars(Uint8 *, const struct ustr *, int); +extern int udf_ustr_to_char(Uint8 *, const struct ustr *, int); +extern int udf_ustr_to_dstring(dstring *, const struct ustr *, int); +extern int udf_dchars_to_ustr(struct ustr *, const Uint8 *, int); +extern int udf_char_to_ustr(struct ustr *, const Uint8 *, int); +extern int udf_dstring_to_ustr(struct ustr *, const dstring *, int); + +extern Uint16 udf_crc(Uint8 *, Uint32, Uint16); +extern int udf_translate_to_linux(Uint8 *, Uint8 *, int, Uint8 *, int); +extern int udf_build_ustr(struct ustr *, dstring *, int); +extern int udf_build_ustr_exact(struct ustr *, dstring *, int); +extern int udf_CS0toUTF8(struct ustr *, struct ustr *); +extern int udf_UTF8toCS0(dstring *, struct ustr *, int); + +extern uid_t udf_convert_uid(int); +extern gid_t udf_convert_gid(int); +extern Uint32 udf64_low32(Uint64); +extern Uint32 udf64_high32(Uint64); + + +extern time_t *udf_stamp_to_time(time_t *, timestamp); +extern timestamp *udf_time_to_stamp(timestamp *, time_t, long); +extern time_t udf_converttime (struct ktm *); + +#ifdef __KERNEL__ +extern Uint8 * +udf_filead_read(struct inode *, Uint8 *, Uint8, lb_addr, int *, int *, + struct buffer_head **, int *); + +extern struct FileIdentDesc * +udf_fileident_read(struct inode *, int *, + struct udf_fileident_bh *, + struct FileIdentDesc *, + lb_addr *, Uint32 *, + Uint32 *, struct buffer_head **); +#endif +extern struct FileIdentDesc * +udf_get_fileident(void * buffer, int bufsize, int * offset); +extern extent_ad * udf_get_fileextent(void * buffer, int bufsize, int * offset); +extern long_ad * udf_get_filelongad(void * buffer, int bufsize, int * offset, int); +extern short_ad * udf_get_fileshortad(void * buffer, int bufsize, int * offset, int); +extern Uint8 * udf_get_filead(struct FileEntry *, Uint8 *, int, int, int, int *); + +extern void udf_update_tag(char *, int); +extern void udf_new_tag(char *, Uint16, Uint16, Uint16, Uint32, int); + +#endif diff -u --recursive --new-file v2.3.16/linux/fs/udf/udfend.h linux/fs/udf/udfend.h --- v2.3.16/linux/fs/udf/udfend.h Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/udfend.h Sat Sep 4 12:42:30 1999 @@ -0,0 +1,107 @@ +#ifndef __UDF_ENDIAN_H +#define __UDF_ENDIAN_H + +#ifndef __KERNEL__ + +#if __BYTE_ORDER == 0 + +#error "__BYTE_ORDER must be defined" + +#elif __BYTE_ORDER == __BIG_ENDIAN + +#define le16_to_cpu(x) \ + ((Uint16)((((Uint16)(x) & 0x00FFU) << 8) | \ + (((Uint16)(x) & 0xFF00U) >> 8))) + +#define le32_to_cpu(x) \ + ((Uint32)((((Uint32)(x) & 0x000000FFU) << 24) | \ + (((Uint32)(x) & 0x0000FF00U) << 8) | \ + (((Uint32)(x) & 0x00FF0000U) >> 8) | \ + (((Uint32)(x) & 0xFF000000U) >> 24))) + +#define le64_to_cpu(x) \ + ((Uint64)((((Uint64)(x) & 0x00000000000000FFULL) << 56) | \ + (((Uint64)(x) & 0x000000000000FF00ULL) << 40) | \ + (((Uint64)(x) & 0x0000000000FF0000ULL) << 24) | \ + (((Uint64)(x) & 0x00000000FF000000ULL) << 8) | \ + (((Uint64)(x) & 0x000000FF00000000ULL) >> 8) | \ + (((Uint64)(x) & 0x0000FF0000000000ULL) >> 24) | \ + (((Uint64)(x) & 0x00FF000000000000ULL) >> 40) | \ + (((Uint64)(x) & 0xFF00000000000000ULL) >> 56))) + +#define cpu_to_le16(x) (le16_to_cpu(x)) +#define cpu_to_le32(x) (le32_to_cpu(x)) +#define cpu_to_le64(x) (le64_to_cpu(x)) + +#else /* __BYTE_ORDER == __LITTLE_ENDIAN */ + +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define le64_to_cpu(x) (x) +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_le64(x) (x) + +#endif + +#endif + +static inline lb_addr lelb_to_cpu(lb_addr in) +{ + lb_addr out; + out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum); + out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum); + return out; +} + +static inline lb_addr cpu_to_lelb(lb_addr in) +{ + lb_addr out; + out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum); + out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum); + return out; +} + +static inline timestamp lets_to_cpu(timestamp in) +{ + timestamp out; + memcpy(&out, &in, sizeof(timestamp)); + out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone); + out.year = le16_to_cpu(in.year); + return out; +} + +static inline long_ad lela_to_cpu(long_ad in) +{ + long_ad out; + out.extLength = le32_to_cpu(in.extLength); + out.extLocation = lelb_to_cpu(in.extLocation); + return out; +} + +static inline long_ad cpu_to_lela(long_ad in) +{ + long_ad out; + out.extLength = cpu_to_le32(in.extLength); + out.extLocation = cpu_to_lelb(in.extLocation); + return out; +} + +static inline extent_ad leea_to_cpu(extent_ad in) +{ + extent_ad out; + out.extLength = le32_to_cpu(in.extLength); + out.extLocation = le32_to_cpu(in.extLocation); + return out; +} + +static inline timestamp cpu_to_lets(timestamp in) +{ + timestamp out; + memcpy(&out, &in, sizeof(timestamp)); + out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone); + out.year = cpu_to_le16(in.year); + return out; +} + +#endif /* __UDF_ENDIAN_H */ diff -u --recursive --new-file v2.3.16/linux/fs/udf/udftime.c linux/fs/udf/udftime.c --- v2.3.16/linux/fs/udf/udftime.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/udftime.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,373 @@ +/* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Eggert (eggert@twinsun.com). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* + * dgb 10/2/98: ripped this from glibc source to help convert timestamps to unix time + * 10/4/98: added new table-based lookup after seeing how ugly the gnu code is + */ + +/* Assume that leap seconds are possible, unless told otherwise. + If the host has a `zic' command with a `-L leapsecondfilename' option, + then it supports leap seconds; otherwise it probably doesn't. */ +#ifndef LEAP_SECONDS_POSSIBLE +#define LEAP_SECONDS_POSSIBLE 1 +#endif + +#if defined(__linux__) && defined(__KERNEL__) +#include +#include +#else +#include +#include +#endif + +#include "udfdecl.h" + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#ifndef INT_MIN +#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1)) +#endif +#ifndef INT_MAX +#define INT_MAX (~0 - INT_MIN) +#endif + +#ifndef TIME_T_MIN +#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \ + : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)) +#endif +#ifndef TIME_T_MAX +#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN) +#endif + +#define TM_YEAR_BASE 1900 +#define EPOCH_YEAR 1970 + +#ifndef __isleap +/* Nonzero if YEAR is a leap year (every 4 years, + except every 100th isn't, and every 400th is). */ +#define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) +#endif + +/* How many days come before each month (0-12). */ +const unsigned short int __mon_yday[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + +time_t udf_converttime (struct ktm *); +#ifndef USE_GNU_MKTIME_METHOD + +#define MAX_YEAR_SECONDS 68 + +time_t year_seconds[MAX_YEAR_SECONDS]= { + 0, + /*1971:*/ 31554000, /*1972:*/ 63090000, /*1973:*/ 94712400, + /*1974:*/ 126248400, /*1975:*/ 157784400, /*1976:*/ 189320400, + /*1977:*/ 220942800, /*1978:*/ 252478800, /*1979:*/ 284014800, + /*1980:*/ 315550800, /*1981:*/ 347173200, /*1982:*/ 378709200, + /*1983:*/ 410245200, /*1984:*/ 441781200, /*1985:*/ 473403600, + /*1986:*/ 504939600, /*1987:*/ 536475600, /*1988:*/ 568011600, + /*1989:*/ 599634000, /*1990:*/ 631170000, /*1991:*/ 662706000, + /*1992:*/ 694242000, /*1993:*/ 725864400, /*1994:*/ 757400400, + /*1995:*/ 788936400, /*1996:*/ 820472400, /*1997:*/ 852094800, + /*1998:*/ 883630800, /*1999:*/ 915166800, /*2000:*/ 946702800, + /*2001:*/ 978325200, /*2002:*/ 1009861200, /*2003:*/ 1041397200, + /*2004:*/ 1072933200, /*2005:*/ 1104555600, /*2006:*/ 1136091600, + /*2007:*/ 1167627600, /*2008:*/ 1199163600, /*2009:*/ 1230786000, + /*2010:*/ 1262322000, /*2011:*/ 1293858000, /*2012:*/ 1325394000, + /*2013:*/ 1357016400, /*2014:*/ 1388552400, /*2015:*/ 1420088400, + /*2016:*/ 1451624400, /*2017:*/ 1483246800, /*2018:*/ 1514782800, + /*2019:*/ 1546318800, /*2020:*/ 1577854800, /*2021:*/ 1609477200, + /*2022:*/ 1641013200, /*2023:*/ 1672549200, /*2024:*/ 1704085200, + /*2025:*/ 1735707600, /*2026:*/ 1767243600, /*2027:*/ 1798779600, + /*2028:*/ 1830315600, /*2029:*/ 1861938000, /*2030:*/ 1893474000, + /*2031:*/ 1925010000, /*2032:*/ 1956546000, /*2033:*/ 1988168400, + /*2034:*/ 2019704400, /*2035:*/ 2051240400, /*2036:*/ 2082776400, + /*2037:*/ 2114398800 +}; + +time_t udf_converttime (struct ktm *tm) +{ + time_t r; + int yday; + + if ( !tm ) + return -1; + if ( (tm->tm_year+TM_YEAR_BASE < EPOCH_YEAR) || + (tm->tm_year+TM_YEAR_BASE > EPOCH_YEAR+MAX_YEAR_SECONDS) ) + return -1; + r = year_seconds[tm->tm_year-70]; + + yday = ((__mon_yday[__isleap (tm->tm_year + TM_YEAR_BASE)] + [tm->tm_mon-1]) + + tm->tm_mday - 1); + r += ( ( (yday* 24) + (tm->tm_hour-1) ) * 60 + tm->tm_min ) * 60 + tm->tm_sec; + return r; +} + +#ifdef __KERNEL__ + +extern struct timezone sys_tz; + +#define SECS_PER_HOUR (60 * 60) +#define SECS_PER_DAY (SECS_PER_HOUR * 24) + +timestamp * +udf_time_to_stamp(timestamp *dest, time_t tv_sec, long tv_usec) +{ + long int days, rem, y; + const unsigned short int *ip; + int offset = (-sys_tz.tz_minuteswest + (sys_tz.tz_dsttime ? 60 : 0)); + + if (!dest) + return NULL; + + dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF); + + tv_sec += offset * 60; + days = tv_sec / SECS_PER_DAY; + rem = tv_sec % SECS_PER_DAY; + dest->hour = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + dest->minute = rem / 60; + dest->second = rem % 60; + y = 1970; + +#define DIV(a,b) ((a) / (b) - ((a) % (b) < 0)) +#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) + + while (days < 0 || days >= (__isleap(y) ? 366 : 365)) + { + long int yg = y + days / 365 - (days % 365 < 0); + + /* Adjust DAYS and Y to match the guessed year. */ + days -= ((yg - y) * 365 + + LEAPS_THRU_END_OF (yg - 1) + - LEAPS_THRU_END_OF (y - 1)); + y = yg; + } + dest->year = y; + ip = __mon_yday[__isleap(y)]; + for (y = 11; days < (long int) ip[y]; --y) + continue; + days -= ip[y]; + dest->month = y + 1; + dest->day = days + 1; + + dest->centiseconds = tv_usec / 10000; + dest->hundredsOfMicroseconds = (tv_usec - dest->centiseconds * 10000) / 100; + dest->microseconds = (tv_usec - dest->centiseconds * 10000 - + dest->hundredsOfMicroseconds * 100); + return dest; +} +#endif + +#else + +static time_t ydhms_tm_diff (int, int, int, int, int, const struct ktm *); + + +/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP), + measured in seconds, ignoring leap seconds. + YEAR uses the same numbering as TM->tm_year. + All values are in range, except possibly YEAR. + If overflow occurs, yield the low order bits of the correct answer. */ +static time_t +ydhms_tm_diff (int year, int yday, int hour, int min, int sec, const struct ktm *tp) +{ + time_t result; + + /* Compute intervening leap days correctly even if year is negative. + Take care to avoid int overflow. time_t overflow is OK, since + only the low order bits of the correct time_t answer are needed. + Don't convert to time_t until after all divisions are done, since + time_t might be unsigned. */ + int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3); + int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3); + int a100 = a4 / 25 - (a4 % 25 < 0); + int b100 = b4 / 25 - (b4 % 25 < 0); + int a400 = a100 >> 2; + int b400 = b100 >> 2; + int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); + time_t years = year - (time_t) tp->tm_year; + time_t days = (365 * years + intervening_leap_days); + result= (60 * (60 * (24 * days + (hour - tp->tm_hour)) + + (min - tp->tm_min)) + + (sec - tp->tm_sec)); +#ifdef __KERNEL__ + printk(KERN_ERR "udf: ydhms_tm_diff(%d,%d,%d,%d,%d,) returning %ld\n", + year, yday, hour, min, sec, result); +#endif + return result; +} + + +/* Convert *TP to a time_t value, inverting + the monotonic and mostly-unit-linear conversion function CONVERT. + Use *OFFSET to keep track of a guess at the offset of the result, + compared to what the result would be for UTC without leap seconds. + If *OFFSET's guess is correct, only one CONVERT call is needed. */ +time_t +udf_converttime (struct ktm *tp) +{ + time_t t, dt, t0; + struct ktm tm; + + /* The maximum number of probes (calls to CONVERT) should be enough + to handle any combinations of time zone rule changes, solar time, + and leap seconds. Posix.1 prohibits leap seconds, but some hosts + have them anyway. */ + int remaining_probes = 4; + + /* Time requested. Copy it in case CONVERT modifies *TP; this can + occur if TP is localtime's returned value and CONVERT is localtime. */ + int sec = tp->tm_sec; + int min = tp->tm_min; + int hour = tp->tm_hour; + int mday = tp->tm_mday; + int mon = tp->tm_mon; + int year_requested = tp->tm_year; + int isdst = tp->tm_isdst; + + /* Ensure that mon is in range, and set year accordingly. */ + int mon_remainder = mon % 12; + int negative_mon_remainder = mon_remainder < 0; + int mon_years = mon / 12 - negative_mon_remainder; + int year = year_requested + mon_years; + + /* The other values need not be in range: + the remaining code handles minor overflows correctly, + assuming int and time_t arithmetic wraps around. + Major overflows are caught at the end. */ + + /* Calculate day of year from year, month, and day of month. + The result need not be in range. */ + int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)] + [mon_remainder + 12 * negative_mon_remainder]) + + mday - 1); + +#if LEAP_SECONDS_POSSIBLE + /* Handle out-of-range seconds specially, + since ydhms_tm_diff assumes every minute has 60 seconds. */ + int sec_requested = sec; + if (sec < 0) + sec = 0; + if (59 < sec) + sec = 59; +#endif + + /* Invert CONVERT by probing. First assume the same offset as last time. + Then repeatedly use the error to improve the guess. */ + + tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE; + tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + /* + t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm); + + for (t = t0; + (dt = ydhms_tm_diff (year, yday, hour, min, sec, &tm)); + t += dt) + if (--remaining_probes == 0) + return -1; + */ + + /* Check whether tm.tm_isdst has the requested value, if any. */ + if (0 <= isdst && 0 <= tm.tm_isdst) + { + int dst_diff = (isdst != 0) - (tm.tm_isdst != 0); + if (dst_diff) + { + /* Move two hours in the direction indicated by the disagreement, + probe some more, and switch to a new time if found. + The largest known fallback due to daylight savings is two hours: + once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */ + time_t ot = t - 2 * 60 * 60 * dst_diff; + while (--remaining_probes != 0) + { + struct ktm otm; + if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec, + &otm))) + { + t = ot; + tm = otm; + break; + } + if ((ot += dt) == t) + break; /* Avoid a redundant probe. */ + } + } + } + + +#if LEAP_SECONDS_POSSIBLE + if (sec_requested != tm.tm_sec) + { + /* Adjust time to reflect the tm_sec requested, not the normalized value. + Also, repair any damage from a false match due to a leap second. */ + t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60); + } +#endif + + if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3) + { + /* time_t isn't large enough to rule out overflows in ydhms_tm_diff, + so check for major overflows. A gross check suffices, + since if t has overflowed, it is off by a multiple of + TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of + the difference that is bounded by a small value. */ + + double dyear = (double) year_requested + mon_years - tm.tm_year; + double dday = 366 * dyear + mday; + double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested; + + if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec)) + return -1; + } + + *tp = tm; +#ifdef __KERNEL__ + udf_debug("returning %ld\n", t); +#endif + return t; +} +#endif + +#ifdef INCLUDE_PRINT_KTM +static void +print_ktm (struct ktm *tp) +{ +#ifdef __KERNEL__ + udf_debug( +#else + printf( +#endif + "%04d-%02d-%02d %02d:%02d:%02d isdst %d", + tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec, tp->tm_isdst); +} +#endif + +/* EOF */ diff -u --recursive --new-file v2.3.16/linux/fs/udf/unicode.c linux/fs/udf/unicode.c --- v2.3.16/linux/fs/udf/unicode.c Wed Dec 31 16:00:00 1969 +++ linux/fs/udf/unicode.c Sat Sep 4 12:42:30 1999 @@ -0,0 +1,447 @@ +/* + * unicode.c + * + * PURPOSE + * Routines for converting between UTF-8 and OSTA Compressed Unicode. + * Also handles filename mangling + * + * DESCRIPTION + * OSTA Compressed Unicode is explained in the OSTA UDF specification. + * http://www.osta.org/ + * UTF-8 is explained in the IETF RFC XXXX. + * ftp://ftp.internic.net/rfc/rfcxxxx.txt + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team's mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + */ + + +#ifdef __KERNEL__ +#include +#include /* for memset */ +#include +#else +#include +#endif + +#include "udfdecl.h" + +int udf_ustr_to_dchars(Uint8 *dest, const struct ustr *src, int strlen) +{ + if ( (!dest) || (!src) || (!strlen) || (src->u_len > strlen) ) + return 0; + memcpy(dest+1, src->u_name, src->u_len-1); + dest[0] = src->u_cmpID; + return src->u_len; +} + +int udf_ustr_to_char(Uint8 *dest, const struct ustr *src, int strlen) +{ + if ( (!dest) || (!src) || (!strlen) || (src->u_len >= strlen) ) + return 0; + memcpy(dest, src->u_name, src->u_len-1); + return src->u_len - 1; +} + +int udf_ustr_to_dstring(dstring *dest, const struct ustr *src, int dlength) +{ + if ( udf_ustr_to_dchars(dest, src, dlength-1) ) + { + dest[dlength-1] = src->u_len; + return dlength; + } + else + return 0; +} + +int udf_dchars_to_ustr(struct ustr *dest, const Uint8 *src, int strlen) +{ + if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN) ) + return 0; + memset(dest, 0, sizeof(struct ustr)); + memcpy(dest->u_name, src+1, strlen-1); + dest->u_cmpID = src[0]; + dest->u_len = strlen; + return strlen; +} + +int udf_char_to_ustr(struct ustr *dest, const Uint8 *src, int strlen) +{ + if ( (!dest) || (!src) || (!strlen) || (strlen >= UDF_NAME_LEN) ) + return 0; + memset(dest, 0, sizeof(struct ustr)); + memcpy(dest->u_name, src, strlen); + dest->u_cmpID = 0x08; + dest->u_len = strlen + 1; + return strlen + 1; +} + + +int udf_dstring_to_ustr(struct ustr *dest, const dstring *src, int dlength) +{ + if ( dlength && udf_dchars_to_ustr(dest, src, src[dlength-1]) ) + return dlength; + else + return 0; +} + +/* + * udf_build_ustr + */ +int udf_build_ustr(struct ustr *dest, dstring *ptr, int size) +{ + int usesize; + + if ( (!dest) || (!ptr) || (!size) ) + return -1; + + memset(dest, 0, sizeof(struct ustr)); + usesize= (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size; + dest->u_cmpID=ptr[0]; + dest->u_len=ptr[size-1]; + memcpy(dest->u_name, ptr+1, usesize-1); + return 0; +} + +/* + * udf_build_ustr_exact + */ +int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) +{ + if ( (!dest) || (!ptr) || (!exactsize) ) + return -1; + + memset(dest, 0, sizeof(struct ustr)); + dest->u_cmpID=ptr[0]; + dest->u_len=exactsize-1; + memcpy(dest->u_name, ptr+1, exactsize-1); + return 0; +} + +/* + * udf_ocu_to_udf8 + * + * PURPOSE + * Convert OSTA Compressed Unicode to the UTF-8 equivalent. + * + * DESCRIPTION + * This routine is only called by udf_filldir(). + * + * PRE-CONDITIONS + * utf Pointer to UTF-8 output buffer. + * ocu Pointer to OSTA Compressed Unicode input buffer + * of size UDF_NAME_LEN bytes. + * both of type "struct ustr *" + * + * POST-CONDITIONS + * Zero on success. + * + * HISTORY + * November 12, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i) +{ + Uint8 *ocu; + Uint32 c; + Uint8 cmp_id, ocu_len; + int i; + + ocu = ocu_i->u_name; + + ocu_len = ocu_i->u_len; + cmp_id = ocu_i->u_cmpID; + utf_o->u_len = 0; + + if (ocu_len == 0) + { + memset(utf_o, 0, sizeof(struct ustr)); + utf_o->u_cmpID = 0; + utf_o->u_len = 0; + return 0; + } + + if ((cmp_id != 8) && (cmp_id != 16)) + { +#ifdef __KERNEL__ + printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); +#endif + return 0; + } + + for (i = 0; (i < ocu_len) && (utf_o->u_len < UDF_NAME_LEN) ;) { + + /* Expand OSTA compressed Unicode to Unicode */ + c = ocu[i++]; + if (cmp_id == 16) + { + c = (c << 8) | ocu[i++]; +#ifdef __KERNEL__ + if (c & 0xFF00) + udf_debug("cmd_id == 16 (0x%2x%2x)\n", + ((c >> 8) & 0xFF), (c & 0xFF)); +#endif + } + + /* Compress Unicode to UTF-8 */ + if (c < 0x80U) + utf_o->u_name[utf_o->u_len++] = (Uint8)c; + else if (c < 0x800U) { + utf_o->u_name[utf_o->u_len++] = (Uint8)(0xc0 | (c >> 6)); + utf_o->u_name[utf_o->u_len++] = (Uint8)(0x80 | (c & 0x3f)); +#ifdef __KERNEL__ + udf_debug("(0x%2x%2x) -> (%2x) (%2x)\n", + ((c >> 8) & 0xFF), (c & 0xFF), + utf_o->u_name[utf_o->u_len-2], + utf_o->u_name[utf_o->u_len-1]); +#endif + } else { + utf_o->u_name[utf_o->u_len++] = (Uint8)(0xe0 | (c >> 12)); + utf_o->u_name[utf_o->u_len++] = (Uint8)(0x80 | ((c >> 6) & 0x3f)); + utf_o->u_name[utf_o->u_len++] = (Uint8)(0x80 | (c & 0x3f)); +#ifdef __KERNEL__ + udf_debug("(0x%2x%2x) -> (%2x) (%2x) (%2x)\n", + ((c >> 8) & 0xFF), (c & 0xFF), + utf_o->u_name[utf_o->u_len-3], + utf_o->u_name[utf_o->u_len-2], + utf_o->u_name[utf_o->u_len-1]); +#endif + } + } + utf_o->u_cmpID=8; + utf_o->u_hash=0L; + utf_o->padding=0; + + return utf_o->u_len; +} + +/* + * + * udf_utf8_to_ocu + * + * PURPOSE + * Convert UTF-8 to the OSTA Compressed Unicode equivalent. + * + * DESCRIPTION + * This routine is only called by udf_lookup(). + * + * PRE-CONDITIONS + * ocu Pointer to OSTA Compressed Unicode output + * buffer of size UDF_NAME_LEN bytes. + * utf Pointer to UTF-8 input buffer. + * utf_len Length of UTF-8 input buffer in bytes. + * + * POST-CONDITIONS + * Zero on success. + * + * HISTORY + * November 12, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) +{ + unsigned c, i, max_val, utf_char; + int utf_cnt; + int u_len = 0; + + memset(ocu, 0, sizeof(dstring) * length); + ocu[0] = 8; + max_val = 0xffU; + +try_again: + utf_char = 0U; + utf_cnt = 0U; + for (i = 0U; i < utf->u_len; i++) { + c = (unsigned)utf->u_name[i]; + + /* Complete a multi-byte UTF-8 character */ + if (utf_cnt) { + utf_char = (utf_char << 6) | (c & 0x3fU); + if (--utf_cnt) + continue; + } else { + /* Check for a multi-byte UTF-8 character */ + if (c & 0x80U) { + /* Start a multi-byte UTF-8 character */ + if ((c & 0xe0U) == 0xc0U) { + utf_char = c & 0x1fU; + utf_cnt = 1; + } else if ((c & 0xf0U) == 0xe0U) { + utf_char = c & 0x0fU; + utf_cnt = 2; + } else if ((c & 0xf8U) == 0xf0U) { + utf_char = c & 0x07U; + utf_cnt = 3; + } else if ((c & 0xfcU) == 0xf8U) { + utf_char = c & 0x03U; + utf_cnt = 4; + } else if ((c & 0xfeU) == 0xfcU) { + utf_char = c & 0x01U; + utf_cnt = 5; + } else + goto error_out; + continue; + } else + /* Single byte UTF-8 character (most common) */ + utf_char = c; + } + + /* Choose no compression if necessary */ + if (utf_char > max_val) { + if ( 0xffU == max_val ) { + max_val = 0xffffU; + ocu[0] = (Uint8)0x10U; + goto try_again; + } + goto error_out; + } + + if (max_val == 0xffffU) + ocu[++u_len] = (Uint8)(utf_char >> 8); + ocu[++u_len] = (Uint8)(utf_char & 0xffU); + } + + if (utf_cnt) { +error_out: +#ifdef __KERNEL__ + printk(KERN_ERR "udf: bad UTF-8 character\n"); +#endif + return 0; + } + + ocu[length - 1] = (Uint8)u_len; + return u_len; +} + +#ifdef __KERNEL__ +int udf_get_filename(Uint8 *sname, Uint8 *dname, int flen) +{ + struct ustr filename, unifilename; + int len; + + if (udf_build_ustr_exact(&unifilename, sname, flen)) + { + return 0; + } + + if (!udf_CS0toUTF8(&filename, &unifilename) ) + { + udf_debug("Failed in udf_get_filename: sname = %s\n", sname); + return 0; + } + + if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len, + unifilename.u_name, unifilename.u_len))) + { + return len; + } + return 0; +} +#endif + +#define ILLEGAL_CHAR_MARK '_' +#define EXT_MARK '.' +#define CRC_MARK '#' +#define EXT_SIZE 5 + +int udf_translate_to_linux(Uint8 *newName, Uint8 *udfName, int udfLen, Uint8 *fidName, int fidNameLen) +{ + int index, newIndex = 0, needsCRC = 0; + int extIndex = 0, newExtIndex = 0, hasExt = 0; + unsigned short valueCRC; + Uint8 curr; + const Uint8 hexChar[] = "0123456789ABCDEF"; + + if (udfName[0] == '.' && (udfLen == 1 || + (udfLen == 2 && udfName[1] == '.'))) + { + needsCRC = 1; + newIndex = udfLen; + memcpy(newName, udfName, udfLen); + } + else + { + for (index = 0; index < udfLen; index++) + { + curr = udfName[index]; + if (curr == '/' || curr == 0) + { + needsCRC = 1; + curr = ILLEGAL_CHAR_MARK; + while (index+1 < udfLen && (udfName[index+1] == '/' || + udfName[index+1] == 0)) + index++; + } + if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE) + { + if (udfLen == index + 1) + hasExt = 0; + else + { + hasExt = 1; + extIndex = index; + newExtIndex = newIndex; + } + } + if (newIndex < 256) + newName[newIndex++] = curr; + else + needsCRC = 1; + } + } + if (needsCRC) + { + Uint8 ext[EXT_SIZE]; + int localExtIndex = 0; + + if (hasExt) + { + int maxFilenameLen; + for(index = 0; index maxFilenameLen) + newIndex = maxFilenameLen; + else + newIndex = newExtIndex; + } + else if (newIndex > 250) + newIndex = 250; + newName[newIndex++] = CRC_MARK; + valueCRC = udf_crc(fidName, fidNameLen, 0); + newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; + newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; + newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; + newName[newIndex++] = hexChar[(valueCRC & 0x000f)]; + + if (hasExt) + { + newName[newIndex++] = EXT_MARK; + for (index = 0;index < localExtIndex ;index++ ) + newName[newIndex++] = ext[index]; + } + } + return newIndex; +} diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_cia.h linux/include/asm-alpha/core_cia.h --- v2.3.16/linux/include/asm-alpha/core_cia.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-alpha/core_cia.h Wed Sep 1 15:34:01 1999 @@ -4,7 +4,6 @@ /* Define to experiment with fitting everything into one 512MB HAE window. */ #define CIA_ONE_HAE_WINDOW 1 -#include #include #include diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_lca.h linux/include/asm-alpha/core_lca.h --- v2.3.16/linux/include/asm-alpha/core_lca.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-alpha/core_lca.h Wed Sep 1 15:34:01 1999 @@ -1,7 +1,6 @@ #ifndef __ALPHA_LCA__H__ #define __ALPHA_LCA__H__ -#include #include #include diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_mcpcia.h linux/include/asm-alpha/core_mcpcia.h --- v2.3.16/linux/include/asm-alpha/core_mcpcia.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-alpha/core_mcpcia.h Wed Sep 1 15:34:01 1999 @@ -5,7 +5,6 @@ One window per bus, that is. */ #define MCPCIA_ONE_HAE_WINDOW 1 -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_polaris.h linux/include/asm-alpha/core_polaris.h --- v2.3.16/linux/include/asm-alpha/core_polaris.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-alpha/core_polaris.h Wed Sep 1 15:34:01 1999 @@ -1,7 +1,6 @@ #ifndef __ALPHA_POLARIS__H__ #define __ALPHA_POLARIS__H__ -#include #include #include diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_pyxis.h linux/include/asm-alpha/core_pyxis.h --- v2.3.16/linux/include/asm-alpha/core_pyxis.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-alpha/core_pyxis.h Wed Sep 1 15:34:01 1999 @@ -1,7 +1,6 @@ #ifndef __ALPHA_PYXIS__H__ #define __ALPHA_PYXIS__H__ -#include #include #include diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_tsunami.h linux/include/asm-alpha/core_tsunami.h --- v2.3.16/linux/include/asm-alpha/core_tsunami.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-alpha/core_tsunami.h Wed Sep 1 15:34:01 1999 @@ -1,7 +1,6 @@ #ifndef __ALPHA_TSUNAMI__H__ #define __ALPHA_TSUNAMI__H__ -#include #include #include diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/serial.h linux/include/asm-alpha/serial.h --- v2.3.16/linux/include/asm-alpha/serial.h Sat Jul 18 11:30:24 1998 +++ linux/include/asm-alpha/serial.h Wed Sep 1 14:37:25 1999 @@ -26,6 +26,9 @@ #define FOURPORT_FLAGS ASYNC_FOURPORT #define ACCENT_FLAGS 0 #define BOCA_FLAGS 0 +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 4 #endif #define STD_SERIAL_PORT_DEFNS \ diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h --- v2.3.16/linux/include/asm-alpha/smp.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-alpha/smp.h Wed Sep 1 14:12:09 1999 @@ -19,7 +19,7 @@ #ifdef __SMP__ -#include +#include struct cpuinfo_alpha { unsigned long loops_per_sec; diff -u --recursive --new-file v2.3.16/linux/include/asm-arm/hardirq.h linux/include/asm-arm/hardirq.h --- v2.3.16/linux/include/asm-arm/hardirq.h Mon Jul 19 13:12:47 1999 +++ linux/include/asm-arm/hardirq.h Wed Sep 1 14:12:09 1999 @@ -1,7 +1,7 @@ #ifndef __ASM_HARDIRQ_H #define __ASM_HARDIRQ_H -#include +#include extern unsigned int local_irq_count[NR_CPUS]; diff -u --recursive --new-file v2.3.16/linux/include/asm-arm/iomd.h linux/include/asm-arm/iomd.h --- v2.3.16/linux/include/asm-arm/iomd.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-arm/iomd.h Wed Sep 1 15:34:01 1999 @@ -1,3 +1,4 @@ +#include #ifndef __ASSEMBLER__ #define __IOMD(offset) (IO_IOMD_BASE + (offset >> 2)) diff -u --recursive --new-file v2.3.16/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h --- v2.3.16/linux/include/asm-i386/bugs.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-i386/bugs.h Tue Sep 7 11:47:26 1999 @@ -53,7 +53,7 @@ static void __init copro_timeout(void) { fpu_error = 1; - timer_table[COPRO_TIMER].expires = jiffies+100; + timer_table[COPRO_TIMER].expires = jiffies+HZ; timer_active |= 1< #include #ifdef CONFIG_BIGMEM -#include +#include #include #endif diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/dvma.h linux/include/asm-m68k/dvma.h --- v2.3.16/linux/include/asm-m68k/dvma.h Tue May 11 09:57:14 1999 +++ linux/include/asm-m68k/dvma.h Sat Sep 4 13:06:41 1999 @@ -9,6 +9,23 @@ #ifndef __M68K_DVMA_H #define __M68K_DVMA_H +#ifdef CONFIG_SUN3 +/* sun3 dvma page support */ + +/* memory and pmegs reserved for dvma */ +#define DVMA_PMEG_START 10 +#define DVMA_PMEG_END 16 +#define DVMA_START 0xff00000 +#define DVMA_END 0xffe0000 +#define DVMA_SIZE (DVMA_END-DVMA_START) + +/* virt <-> phys conversions */ +#define sun3_dvma_vtop(x) ((unsigned long)(x) & 0xffffff) +#define sun3_dvma_ptov(x) ((unsigned long)(x) | 0xf000000) + +void *sun3_dvma_malloc(int len); +#else /* Sun3x */ + /* Structure to describe the current status of DMA registers on the Sparc */ struct sparc_dma_registers { __volatile__ unsigned long cond_reg; /* DMA condition register */ @@ -161,5 +178,5 @@ extern unsigned long dvma_alloc (unsigned long, unsigned long); extern void dvma_free (unsigned long, unsigned long); - +#endif /* !CONFIG_SUN3 */ #endif /* !(__M68K_DVMA_H) */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/elf.h linux/include/asm-m68k/elf.h --- v2.3.16/linux/include/asm-m68k/elf.h Fri Feb 6 10:06:56 1998 +++ linux/include/asm-m68k/elf.h Sat Sep 4 13:06:41 1999 @@ -33,14 +33,22 @@ #define ELF_PLAT_INIT(_r) _r->a1 = 0 #define USE_ELF_CORE_DUMP +#ifndef CONFIG_SUN3 #define ELF_EXEC_PAGESIZE 4096 +#else +#define ELF_EXEC_PAGESIZE 8192 +#endif /* This is the location that an ET_DYN program is loaded if exec'ed. Typical use of this is to invoke "./ld.so someprog" to test out a new version of the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ +#ifndef CONFIG_SUN3 #define ELF_ET_DYN_BASE 0xD0000000UL +#else +#define ELF_ET_DYN_BASE 0x0D800000UL +#endif #define ELF_CORE_COPY_REGS(pr_reg, regs) \ /* Bleech. */ \ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/entry.h linux/include/asm-m68k/entry.h --- v2.3.16/linux/include/asm-m68k/entry.h Tue Jan 19 10:58:34 1999 +++ linux/include/asm-m68k/entry.h Sat Sep 4 13:06:41 1999 @@ -3,6 +3,7 @@ #include #include +#include #ifdef CONFIG_KGDB #include #endif @@ -132,7 +133,7 @@ .macro get_current reg=%d0 movel %sp,\reg - andw #-8192,\reg + andw #-KTHREAD_SIZE,\reg movel \reg,%curptr .endm @@ -161,7 +162,7 @@ #endif #define GET_CURRENT(tmp) \ "movel %%sp,"#tmp"\n\t" \ - "andw #-8192,"#tmp"\n\t" \ + "andw #-KTHREAD_SIZE,"#tmp"\n\t" \ "movel "#tmp",%%a2" #endif diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h --- v2.3.16/linux/include/asm-m68k/ide.h Thu May 13 11:00:09 1999 +++ linux/include/asm-m68k/ide.h Sat Sep 4 13:06:41 1999 @@ -38,6 +38,7 @@ #include #ifdef CONFIG_ATARI +#include #include #endif @@ -63,7 +64,7 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index) { if (MACH_IS_Q40) - return q40ide_default_io_base(index); + return (ide_ioreg_t)q40ide_default_io_base(index); else return 0; } @@ -82,7 +83,8 @@ if (MACH_IS_Q40) return q40_ide_init_hwif_ports(hw, (q40ide_ioreg_t) data_port, (q40ide_ioreg_t) ctrl_port, irq); #endif - printk("ide_init_hwif_ports: must not be called\n"); + if (data_port || ctrl_port) + printk("ide_init_hwif_ports: must not be called\n"); } /* @@ -104,10 +106,6 @@ } b; } select_t; -#ifdef CONFIG_MAC /* MSch: Hack; wrapper for ide_intr */ -void mac_ide_intr(int irq, void *dev_id, struct pt_regs *regs); -#endif - static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *device, void *dev_id) { @@ -121,11 +119,7 @@ #endif /* CONFIG_Q40*/ #ifdef CONFIG_MAC if (MACH_IS_MAC) -#if 0 /* MSch Hack: maybe later we'll call ide_intr without a wrapper */ - return nubus_request_irq(12, dev_id, handler); -#else - return nubus_request_irq(12, dev_id, mac_ide_intr); -#endif + return request_irq(irq, handler, 0, device, dev_id); #endif /* CONFIG_MAC */ return 0; } @@ -142,7 +136,7 @@ #endif /* CONFIG_Q40*/ #ifdef CONFIG_MAC if (MACH_IS_MAC) - nubus_free_irq(12); + free_irq(irq, dev_id); #endif /* CONFIG_MAC */ } diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/init.h linux/include/asm-m68k/init.h --- v2.3.16/linux/include/asm-m68k/init.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-m68k/init.h Sat Sep 4 13:06:41 1999 @@ -12,9 +12,6 @@ #define __FINIT .previous #define __INITDATA .section ".data.init",#alloc,#write -#define __cacheline_aligned __attribute__ \ - ((__aligned__(16), __section__ (".data.cacheline_aligned"))) - #else /* gdb doesn't like it all if the code for one source file isn't together in @@ -26,7 +23,6 @@ #define __INIT #define __FINIT #define __INITDATA -#define __cacheline_aligned __attribute__ ((__aligned__(16))) #endif /* CONFIG_KGDB */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/intersil.h linux/include/asm-m68k/intersil.h --- v2.3.16/linux/include/asm-m68k/intersil.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/intersil.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,48 @@ +#ifndef _SUN3_INTERSIL_H +#define _SUN3_INTERSIL_H +/* bits 0 and 1 */ +#define INTERSIL_FREQ_32K 0x00 +#define INTERSIL_FREQ_1M 0x01 +#define INTERSIL_FREQ_2M 0x02 +#define INTERSIL_FREQ_4M 0x03 + +/* bit 2 */ +#define INTERSIL_12H_MODE 0x00 +#define INTERSIL_24H_MODE 0x04 + +/* bit 3 */ +#define INTESIL_STOP 0x00 +#define INTERSIL_RUN 0x08 + +/* bit 4 */ +#define INTERSIL_INT_ENABLE 0x10 +#define INTERSIL_INT_DISABLE 0x00 + +/* bit 5 */ +#define INTERSIL_MODE_NORMAL 0x00 +#define INTERSIL_MODE_TEST 0x20 + +#define INTERSIL_HZ_100_MASK 0x02 + +struct intersil_dt { + u_char csec; + u_char hour; + u_char minute; + u_char second; + u_char month; + u_char day; + u_char year; + u_char weekday; +}; + +struct intersil_7170 { + struct intersil_dt counter; + struct intersil_dt alarm; + u_char int_reg; + u_char cmd_reg; +}; + +extern volatile char* clock_va; +#define intersil_clock ((volatile struct intersil_7170 *) clock_va) +#define intersil_clear() (void)intersil_clock->int_reg +#endif diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/io.h linux/include/asm-m68k/io.h --- v2.3.16/linux/include/asm-m68k/io.h Thu May 13 11:00:09 1999 +++ linux/include/asm-m68k/io.h Sat Sep 4 13:06:41 1999 @@ -14,6 +14,10 @@ #include /* + * These are for ISA/PCI shared memory _only_ and should never be used + * on any other type of memory, including Zorro memory. They are meant to + * access the bus in the bus byte order which is little-endian!. + * * readX/writeX() are used to access memory mapped devices. On some * architectures the memory mapped IO stuff needs to be accessed * differently. On the m68k architecture, we just read/write the diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/mac_iop.h linux/include/asm-m68k/mac_iop.h --- v2.3.16/linux/include/asm-m68k/mac_iop.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/mac_iop.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,162 @@ +/* + * I/O Processor (IOP) defines and structures, mostly snagged from A/UX + * header files. + * + * The original header from which this was taken is copyrighted. I've done some + * rewriting (in fact my changes make this a bit more readable, IMHO) but some + * more should be done. + */ + +/* + * This is the base address of the IOPs. Use this as the address of + * a "struct iop" (see below) to see where the actual registers fall. + */ + +#define SCC_IOP_BASE_IIFX (0x50F04000) +#define ISM_IOP_BASE_IIFX (0x50F12000) + +#define SCC_IOP_BASE_QUADRA (0x50F0C000) +#define ISM_IOP_BASE_QUADRA (0x50F1E000) + +/* IOP status/control register bits: */ + +#define IOP_BYPASS 0x01 /* bypass-mode hardware access */ +#define IOP_AUTOINC 0x02 /* allow autoincrement of ramhi/lo */ +#define IOP_RUN 0x04 /* set to 0 to reset IOP chip */ +#define IOP_IRQ 0x08 /* generate IRQ to IOP if 1 */ +#define IOP_INT0 0x10 /* intr priority from IOP to host */ +#define IOP_INT1 0x20 /* intr priority from IOP to host */ +#define IOP_HWINT 0x40 /* IRQ from hardware; bypass mode only */ +#define IOP_DMAINACTIVE 0x80 /* no DMA request active; bypass mode only */ + +#define NUM_IOPS 2 +#define NUM_IOP_CHAN 7 +#define NUM_IOP_MSGS NUM_IOP_CHAN*8 +#define IOP_MSG_LEN 32 + +/* IOP reference numbers, used by the globally-visible iop_xxx functions */ + +#define IOP_NUM_SCC 0 +#define IOP_NUM_ISM 1 + +/* IOP channel states */ + +#define IOP_MSG_IDLE 0 /* idle */ +#define IOP_MSG_NEW 1 /* new message sent */ +#define IOP_MSG_RCVD 2 /* message received; processing */ +#define IOP_MSG_COMPLETE 3 /* message processing complete */ + +/* IOP message status codes */ + +#define IOP_MSGSTATUS_UNUSED 0 /* Unusued message structure */ +#define IOP_MSGSTATUS_WAITING 1 /* waiting for channel */ +#define IOP_MSGSTATUS_SENT 2 /* message sent, awaiting reply */ +#define IOP_MSGSTATUS_COMPLETE 3 /* message complete and reply rcvd */ +#define IOP_MSGSTATUS_UNSOL 6 /* message is unsolicited */ + +/* IOP memory addresses of the members of the the mac_iop_kernel structure. */ + +#define IOP_ADDR_MAX_SEND_CHAN 0x0200 +#define IOP_ADDR_SEND_STATE 0x0201 +#define IOP_ADDR_PATCH_CTRL 0x021F +#define IOP_ADDR_SEND_MSG 0x0220 +#define IOP_ADDR_MAX_RECV_CHAN 0x0300 +#define IOP_ADDR_RECV_STATE 0x0301 +#define IOP_ADDR_ALIVE 0x031F +#define IOP_ADDR_RECV_MSG 0x0320 + +#ifndef __ASSEMBLY__ + +/* + * IOP Control registers, staggered because in usual Apple style they were + * too lazy to decode the A0 bit. This structure is assumed to begin at + * one of the xxx_IOP_BASE addresses given above. + */ + +struct mac_iop { + __u8 ram_addr_hi; /* shared RAM address hi byte */ + __u8 pad0; + __u8 ram_addr_lo; /* shared RAM address lo byte */ + __u8 pad1; + __u8 status_ctrl; /* status/control register */ + __u8 pad2[3]; + __u8 ram_data; /* RAM data byte at ramhi/lo */ + + __u8 pad3[23]; + + /* Bypass-mode hardware access registers */ + + union { + struct { /* SCC registers */ + __u8 sccb_cmd; /* SCC B command reg */ + __u8 pad4; + __u8 scca_cmd; /* SCC A command reg */ + __u8 pad5; + __u8 sccb_data; /* SCC B data */ + __u8 pad6; + __u8 scca_data; /* SCC A data */ + } scc_regs; + + struct { /* ISM registers */ + __u8 wdata; /* write a data byte */ + __u8 pad7; + __u8 wmark; /* write a mark byte */ + __u8 pad8; + __u8 wcrc; /* write 2-byte crc to disk */ + __u8 pad9; + __u8 wparams; /* write the param regs */ + __u8 pad10; + __u8 wphase; /* write the phase states & dirs */ + __u8 pad11; + __u8 wsetup; /* write the setup register */ + __u8 pad12; + __u8 wzeroes; /* mode reg: 1's clr bits, 0's are x */ + __u8 pad13; + __u8 wones; /* mode reg: 1's set bits, 0's are x */ + __u8 pad14; + __u8 rdata; /* read a data byte */ + __u8 pad15; + __u8 rmark; /* read a mark byte */ + __u8 pad16; + __u8 rerror; /* read the error register */ + __u8 pad17; + __u8 rparams; /* read the param regs */ + __u8 pad18; + __u8 rphase; /* read the phase states & dirs */ + __u8 pad19; + __u8 rsetup; /* read the setup register */ + __u8 pad20; + __u8 rmode; /* read the mode register */ + __u8 pad21; + __u8 rhandshake; /* read the handshake register */ + } ism_regs; + } b; +}; + +/* This structure is used to track IOP messages in the Linux kernel */ + +struct iop_msg { + struct iop_msg *next; /* next message in queue or NULL */ + uint iop_num; /* IOP number */ + uint channel; /* channel number */ + void *caller_priv; /* caller private data */ + int status; /* status of this message */ + __u8 message[IOP_MSG_LEN]; /* the message being sent/received */ + __u8 reply[IOP_MSG_LEN]; /* the reply to the message */ + void (*handler)(struct iop_msg *, struct pt_regs *); + /* function to call when reply recvd */ +}; + +extern int iop_scc_present,iop_ism_present; + +extern int iop_listen(uint, uint, + void (*handler)(struct iop_msg *, struct pt_regs *), + const char *); +extern int iop_send_message(uint, uint, void *, uint, __u8 *, + void (*)(struct iop_msg *, struct pt_regs *)); +extern void iop_complete_message(struct iop_msg *); +extern void iop_upload_code(uint, __u8 *, uint, __u16); +extern void iop_download_code(uint, __u8 *, uint, __u16); +extern __u8 *iop_compare_code(uint, __u8 *, uint, __u16); + +#endif /* __ASSEMBLY__ */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/mac_oss.h linux/include/asm-m68k/mac_oss.h --- v2.3.16/linux/include/asm-m68k/mac_oss.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/mac_oss.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,94 @@ +/* + * OSS + * + * This is used in place of VIA2 on the IIfx. + */ + +#define OSS_BASE (0x50f1a000) + +/* + * Interrupt level offsets for mac_oss->irq_level + */ + +#define OSS_NUBUS0 0 +#define OSS_NUBUS1 1 +#define OSS_NUBUS2 2 +#define OSS_NUBUS3 3 +#define OSS_NUBUS4 4 +#define OSS_NUBUS5 5 +#define OSS_IOPISM 6 +#define OSS_IOPSCC 7 +#define OSS_SOUND 8 +#define OSS_SCSI 9 +#define OSS_60HZ 10 +#define OSS_VIA1 11 +#define OSS_UNUSED1 12 +#define OSS_UNUSED2 13 +#define OSS_PARITY 14 +#define OSS_UNUSED3 15 + +#define OSS_NUM_SOURCES 16 + +/* + * Pending interrupt bits in mac_oss->irq_pending + */ + +#define OSS_IP_NUBUS0 0x0001 +#define OSS_IP_NUBUS1 0x0002 +#define OSS_IP_NUBUS2 0x0004 +#define OSS_IP_NUBUS3 0x0008 +#define OSS_IP_NUBUS4 0x0010 +#define OSS_IP_NUBUS5 0x0020 +#define OSS_IP_IOPISM 0x0040 +#define OSS_IP_IOPSCC 0x0080 +#define OSS_IP_SOUND 0x0100 +#define OSS_IP_SCSI 0x0200 +#define OSS_IP_60HZ 0x0400 +#define OSS_IP_VIA1 0x0800 +#define OSS_IP_UNUSED1 0x1000 +#define OSS_IP_UNUSED2 0x2000 +#define OSS_IP_PARITY 0x4000 +#define OSS_IP_UNUSED3 0x8000 + +#define OSS_IP_NUBUS (OSS_IP_NUBUS0|OSS_IP_NUBUS1|OSS_IP_NUBUS2|OSS_IP_NUBUS3|OSS_IP_NUBUS4|OSS_IP_NUBUS5) + +/* + * Rom Control Register + */ + +#define OSS_POWEROFF 0x80 + +/* + * OSS Interrupt levels for various sub-systems + * + * This mapping is layed out with two things in mind: first, we try to keep + * things on their own levels to avoid having to do double-dispatches. Second, + * the levels match as closely as possible the alternate IRQ mapping mode (aka + * "A/UX mode") available on some VIA machines. + */ + +#define OSS_IRQLEV_DISABLED 0 +#define OSS_IRQLEV_IOPISM 1 /* ADB? */ +#define OSS_IRQLEV_SCSI 2 +#define OSS_IRQLEV_NUBUS 3 /* keep this on its own level */ +#define OSS_IRQLEV_IOPSCC 4 /* matches VIA alternate mapping */ +#define OSS_IRQLEV_SOUND 5 /* matches VIA alternate mapping */ +#define OSS_IRQLEV_60HZ 6 /* matches VIA alternate mapping */ +#define OSS_IRQLEV_VIA1 6 /* matches VIA alternate mapping */ +#define OSS_IRQLEV_PARITY 7 /* matches VIA alternate mapping */ + +#ifndef __ASSEMBLY__ + +struct mac_oss { + __u8 irq_level[0x10]; /* [0x000-0x00f] Interrupt levels */ + __u8 padding0[0x1F2]; /* [0x010-0x201] IO space filler */ + __u16 irq_pending; /* [0x202-0x203] pending interrupts bits */ + __u8 rom_ctrl; /* [0x204-0x204] ROM cntl reg (for poweroff) */ + __u8 padding1[0x2]; /* [0x205-0x206] currently unused by A/UX */ + __u8 ack_60hz; /* [0x207-0x207] 60 Hz ack. */ +}; + +extern volatile struct mac_oss *oss; +extern int oss_present; + +#endif /* __ASSEMBLY__ */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/mac_psc.h linux/include/asm-m68k/mac_psc.h --- v2.3.16/linux/include/asm-m68k/mac_psc.h Mon Oct 5 13:54:39 1998 +++ linux/include/asm-m68k/mac_psc.h Sat Sep 4 13:06:41 1999 @@ -1,73 +1,243 @@ /* - * Apple Peripheral System Controller (PSC) + * Apple Peripheral System Controller (PSC) * - * The PSC is used on the AV Macs to control IO functions not handled - * by the VIAs (Ethernet, DSP, SCC). + * The PSC is used on the AV Macs to control IO functions not handled + * by the VIAs (Ethernet, DSP, SCC, Sound). This includes nine DMA + * channels. + * + * The first seven DMA channels appear to be "one-shot" and are actually + * sets of two channels; one member is active while the other is being + * configured, and then you flip the active member and start all over again. + * The one-shot channels are grouped together and are: + * + * 1. SCSI + * 2. Ethernet Read + * 3. Ethernet Write + * 4. Floppy Disk Controller + * 5. SCC Channel A Receive + * 6. SCC Channel B Receive + * 7. SCC Channel A Transmit + * + * The remaining two channels are handled somewhat differently. They appear + * to be closely tied and share one set of registers. They also seem to run + * continuously, although how you keep the buffer filled in this scenario is + * not understood as there seems to be only one input and one output buffer + * pointer. + * + * Much of this was extrapolated from what was known about the Ethernet + * registers and subsequently confirmed using MacsBug (ie by pinging the + * machine with easy-to-find patterns and looking for them in the DMA + * buffers, or by sending a file over the serial ports and finding the + * file in the buffers.) + * + * 1999-05-25 (jmt) */ - -#define PSCBASE 0x50F31000 + +#define PSC_BASE (0x50F31000) /* - * The IER/IFR registers work like the VIA, except that it has 4 - * of them each on different interrupt levels. + * The IER/IFR registers work like the VIA, except that it has 4 + * of them each on different interrupt levels, and each register + * set only seems to handle four interrupts instead of seven. + * + * To access a particular set of registers, add 0xn0 to the base + * where n = 3,4,5 or 6. */ -#define pIFR3 0x130 -#define pIFR4 0x140 -#define pIFR5 0x150 -#define pIFR6 0x160 - -#define pIER3 0x134 -#define pIER4 0x144 -#define pIER5 0x154 -#define pIER6 0x164 +#define pIFRbase 0x100 +#define pIERbase 0x104 /* - * Ethernet Control Registers + * One-shot DMA control registers */ - -#define PSC_ENETRD_CTL 0xc10 -#define PSC_ENETWR_CTL 0xc20 + +#define PSC_CTL_BASE 0xC00 + +#define PSC_SCSI_CTL 0xC00 +#define PSC_ENETRD_CTL 0xC10 +#define PSC_ENETWR_CTL 0xC20 +#define PSC_FDC_CTL 0xC30 +#define PSC_SCCA_CTL 0xC40 +#define PSC_SCCB_CTL 0xC50 +#define PSC_SCCATX_CTL 0xC60 + +/* + * DMA channels. Add +0x10 for the second channel in the set. + * You're supposed to use one channel while the other runs and + * then flip channels and do the whole thing again. + */ + +#define PSC_ADDR_BASE 0x1000 +#define PSC_LEN_BASE 0x1004 +#define PSC_CMD_BASE 0x1008 + +#define PSC_SCSI_ADDR 0x1000 /* confirmed */ +#define PSC_SCSI_LEN 0x1004 /* confirmed */ +#define PSC_SCSI_CMD 0x1008 /* confirmed */ +#define PSC_ENETRD_ADDR 0x1020 /* confirmed */ +#define PSC_ENETRD_LEN 0x1024 /* confirmed */ +#define PSC_ENETRD_CMD 0x1028 /* confirmed */ +#define PSC_ENETWR_ADDR 0x1040 /* confirmed */ +#define PSC_ENETWR_LEN 0x1044 /* confirmed */ +#define PSC_ENETWR_CMD 0x1048 /* confirmed */ +#define PSC_FDC_ADDR 0x1060 /* strongly suspected */ +#define PSC_FDC_LEN 0x1064 /* strongly suspected */ +#define PSC_FDC_CMD 0x1068 /* strongly suspected */ +#define PSC_SCCA_ADDR 0x1080 /* confirmed */ +#define PSC_SCCA_LEN 0x1084 /* confirmed */ +#define PSC_SCCA_CMD 0x1088 /* confirmed */ +#define PSC_SCCB_ADDR 0x10A0 /* confirmed */ +#define PSC_SCCB_LEN 0x10A4 /* confirmed */ +#define PSC_SCCB_CMD 0x10A8 /* confirmed */ +#define PSC_SCCATX_ADDR 0x10C0 /* confirmed */ +#define PSC_SCCATX_LEN 0x10C4 /* confirmed */ +#define PSC_SCCATX_CMD 0x10C8 /* confirmed */ /* - * Receive DMA channel (add +0x10 for 2nd channel) + * Free-running DMA registers. The only part known for sure are the bits in + * the control register, the buffer addresses and the buffer length. Everything + * else is anybody's guess. + * + * These registers seem to be mirrored every thirty-two bytes up until offset + * 0x300. It's safe to assume then that a new set of registers starts there. */ - -#define PSC_ENETRD_ADDR 0x1020 -#define PSC_ENETRD_LEN 0x1024 -#define PSC_ENETRD_CMD 0x1028 + +#define PSC_SND_CTL 0x200 /* + * [ 16-bit ] + * Sound (Singer?) control register. + * + * bit 0 : ???? + * bit 1 : ???? + * bit 2 : Set to one to enable sound + * output. Possibly a mute flag. + * bit 3 : ???? + * bit 4 : ???? + * bit 5 : ???? + * bit 6 : Set to one to enable pass-thru + * audio. In this mode the audio data + * seems to appear in both the input + * buffer and the output buffer. + * bit 7 : Set to one to activate the + * sound input DMA or zero to + * disable it. + * bit 8 : Set to one to activate the + * sound output DMA or zero to + * disable it. + * bit 9 : \ + * bit 11 : | + * These two bits control the sample + * rate. Usually set to binary 10 and + * MacOS 8.0 says I'm at 48 KHz. Using + * a binary value of 01 makes things + * sound about 1/2 speed (24 KHz?) and + * binary 00 is slower still (22 KHz?) + * + * Setting this to 0x0000 is a good way to + * kill all DMA at boot time so that the + * PSC won't overwrite the kernel image + * with sound data. + */ /* - * Transmit DMA channel (add +0x10 for 2nd channel) + * 0x0202 - 0x0203 is unused. Writing there + * seems to clobber the control register. */ - -#define PSC_ENETWR_ADDR 0x1040 -#define PSC_ENETWR_LEN 0x1044 -#define PSC_ENETWR_CMD 0x1048 + +#define PSC_SND_SOURCE 0x204 /* + * [ 32-bit ] + * Controls input source and volume: + * + * bits 12-15 : input source volume, 0 - F + * bits 16-19 : unknown, always 0x5 + * bits 20-23 : input source selection: + * 0x3 = CD Audio + * 0x4 = External Audio + * + * The volume is definately not the general + * output volume as it doesn't affect the + * alert sound volume. + */ +#define PSC_SND_STATUS1 0x208 /* + * [ 32-bit ] + * Appears to be a read-only status register. + * The usual value is 0x00400002. + */ +#define PSC_SND_HUH3 0x20C /* + * [ 16-bit ] + * Unknown 16-bit value, always 0x0000. + */ +#define PSC_SND_BITS2GO 0x20E /* + * [ 16-bit ] + * Counts down to zero from some constant + * value. The value appears to be the + * number of _bits_ remaining before the + * buffer is full, which would make sense + * since Apple's docs say the sound DMA + * channels are 1 bit wide. + */ +#define PSC_SND_INADDR 0x210 /* + * [ 32-bit ] + * Address of the sound input DMA buffer + */ +#define PSC_SND_OUTADDR 0x214 /* + * [ 32-bit ] + * Address of the sound output DMA buffer + */ +#define PSC_SND_LEN 0x218 /* + * [ 16-bit ] + * Length of both buffers in eight-byte units. + */ +#define PSC_SND_HUH4 0x21A /* + * [ 16-bit ] + * Unknown, always 0x0000. + */ +#define PSC_SND_STATUS2 0x21C /* + * [ 16-bit ] + * Appears to e a read-only status register. + * The usual value is 0x0200. + */ +#define PSC_SND_HUH5 0x21E /* + * [ 16-bit ] + * Unknown, always 0x0000. + */ + +#ifndef __ASSEMBLY__ + +extern volatile __u8 *psc; +extern int psc_present; /* * Access functions */ -extern volatile unsigned char *psc; +extern inline void psc_write_byte(int offset, __u8 data) +{ + *((volatile __u8 *)(psc + offset)) = data; +} + +extern inline void psc_write_word(int offset, __u16 data) +{ + *((volatile __u16 *)(psc + offset)) = data; +} -extern inline void psc_write_word(int offset, u16 data) +extern inline void psc_write_long(int offset, __u32 data) { - *((volatile u16 *)(psc+offset)) = data; + *((volatile __u32 *)(psc + offset)) = data; } -extern inline void psc_write_long(int offset, u32 data) +extern inline u8 psc_read_byte(int offset) { - *((volatile u32 *)(psc+offset)) = data; + return *((volatile __u8 *)(psc + offset)); } extern inline u16 psc_read_word(int offset) { - return *((volatile u16 *)(psc+offset)); + return *((volatile __u16 *)(psc + offset)); } extern inline u32 psc_read_long(int offset) { - return *((volatile u32 *)(psc+offset)); + return *((volatile __u32 *)(psc + offset)); } +#endif /* __ASSEMBLY__ */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/mac_via.h linux/include/asm-m68k/mac_via.h --- v2.3.16/linux/include/asm-m68k/mac_via.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/mac_via.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,267 @@ +/* + * 6522 Versatile Interface Adapter (VIA) + * + * There are two of these on the Mac II. Some IRQ's are vectored + * via them as are assorted bits and bobs - eg rtc, adb. The picture + * is a bit incomplete as the Mac documentation doesnt cover this well + */ + +#ifndef _ASM_MAC_VIA_H_ +#define _ASM_MAC_VIA_H_ + +/* + * Base addresses for the VIAs. There are two in every machine, + * although on some machines the second is an RBV or an OSS. + * The OSS is different enough that it's handled separately. + * + * Do not use these values directly; use the via1 and via2 variables + * instead (and don't forget to check rbv_present when using via2!) + */ + +#define VIA1_BASE (0x50F00000) +#define VIA2_BASE (0x50F02000) +#define RBV_BASE (0x50F26000) + +/* + * Not all of these are true post MacII I think. + * CSA: probably the ones CHRP marks as 'unused' change purposes + * when the IWM becomes the SWIM. + * http://www.rs6000.ibm.com/resource/technology/chrpio/via5.mak.html + * ftp://ftp.austin.ibm.com/pub/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf + * + * also, http://developer.apple.com/technotes/hw/hw_09.html claims the + * following changes for IIfx: + * VIA1A_vSccWrReq not available and that VIA1A_vSync has moved to an IOP. + * Also, "All of the functionality of VIA2 has been moved to other chips". + */ + +#define VIA1A_vSccWrReq 0x80 /* SCC write. (input) + * [CHRP] SCC WREQ: Reflects the state of the + * Wait/Request pins from the SCC. + * [Macintosh Family Hardware] + * as CHRP on SE/30,II,IIx,IIcx,IIci. + * on IIfx, "0 means an active request" + */ +#define VIA1A_vRev8 0x40 /* Revision 8 board ??? + * [CHRP] En WaitReqB: Lets the WaitReq_L + * signal from port B of the SCC appear on + * the PA7 input pin. Output. + * [Macintosh Family] On the SE/30, this + * is the bit to flip screen buffers. + * 0=alternate, 1=main. + * on II,IIx,IIcx,IIci,IIfx this is a bit + * for Rev ID. 0=II,IIx, 1=IIcx,IIci,IIfx + */ +#define VIA1A_vHeadSel 0x20 /* Head select for IWM. + * [CHRP] unused. + * [Macintosh Family] "Floppy disk + * state-control line SEL" on all but IIfx + */ +#define VIA1A_vOverlay 0x10 /* [Macintosh Family] On SE/30,II,IIx,IIcx + * this bit enables the "Overlay" address + * map in the address decoders as it is on + * reset for mapping the ROM over the reset + * vector. 1=use overlay map. + * On the IIci,IIfx it is another bit of the + * CPU ID: 0=normal IIci, 1=IIci with parity + * feature or IIfx. + * [CHRP] En WaitReqA: Lets the WaitReq_L + * signal from port A of the SCC appear + * on the PA7 input pin (CHRP). Output. + * [MkLinux] "Drive Select" + * (with 0x20 being 'disk head select') + */ +#define VIA1A_vSync 0x08 /* [CHRP] Sync Modem: modem clock select: + * 1: select the external serial clock to + * drive the SCC's /RTxCA pin. + * 0: Select the 3.6864MHz clock to drive + * the SCC cell. + * [Macintosh Family] Correct on all but IIfx + */ + +/* Macintosh Family Hardware sez: bits 0-2 of VIA1A are volume control + * on Macs which had the PWM sound hardware. Reserved on newer models. + * On IIci,IIfx, bits 1-2 are the rest of the CPU ID: + * bit 2: 1=IIci, 0=IIfx + * bit 1: 1 on both IIci and IIfx. + * MkLinux sez bit 0 is 'burnin flag' in this case. + * CHRP sez: VIA1A bits 0-2 and 5 are 'unused': if programmed as + * inputs, these bits will read 0. + */ +#define VIA1A_vVolume 0x07 /* Audio volume mask for PWM */ +#define VIA1A_CPUID0 0x02 /* CPU id bit 0 on RBV, others */ +#define VIA1A_CPUID1 0x04 /* CPU id bit 0 on RBV, others */ +#define VIA1A_CPUID2 0x10 /* CPU id bit 0 on RBV, others */ +#define VIA1A_CPUID3 0x40 /* CPU id bit 0 on RBV, others */ + +/* Info on VIA1B is from Macintosh Family Hardware & MkLinux. + * CHRP offers no info. */ +#define VIA1B_vSound 0x80 /* Sound enable (for compatibility with + * PWM hardware) 0=enabled. + * Also, on IIci w/parity, shows parity error + * 0=error, 1=OK. */ +#define VIA1B_vMystery 0x40 /* On IIci, parity enable. 0=enabled,1=disabled + * On SE/30, vertical sync interrupt enable. + * 0=enabled. This vSync interrupt shows up + * as a slot $E interrupt. */ +#define VIA1B_vADBS2 0x20 /* ADB state input bit 1 (unused on IIfx) */ +#define VIA1B_vADBS1 0x10 /* ADB state input bit 0 (unused on IIfx) */ +#define VIA1B_vADBInt 0x08 /* ADB interrupt 0=interrupt (unused on IIfx)*/ +#define VIA1B_vRTCEnb 0x04 /* Enable Real time clock. 0=enabled. */ +#define VIA1B_vRTCClk 0x02 /* Real time clock serial-clock line. */ +#define VIA1B_vRTCData 0x01 /* Real time clock serial-data line. */ + +/* MkLinux defines the following "VIA1 Register B contents where they + * differ from standard VIA1". From the naming scheme, we assume they + * correspond to a VIA work-alike named 'EVR'. */ +#define EVRB_XCVR 0x08 /* XCVR_SESSION* */ +#define EVRB_FULL 0x10 /* VIA_FULL */ +#define EVRB_SYSES 0x20 /* SYS_SESSION */ +#define EVRB_AUXIE 0x00 /* Enable A/UX Interrupt Scheme */ +#define EVRB_AUXID 0x40 /* Disable A/UX Interrupt Scheme */ +#define EVRB_SFTWRIE 0x00 /* Software Interrupt ReQuest */ +#define EVRB_SFTWRID 0x80 /* Software Interrupt ReQuest */ + +/* + * VIA2 A register is the interrupt lines raised off the nubus + * slots. + * The below info is from 'Macintosh Family Hardware.' + * MkLinux calls the 'IIci internal video IRQ' below the 'RBV slot 0 irq.' + * It also notes that the slot $9 IRQ is the 'Ethernet IRQ' and + * defines the 'Video IRQ' as 0x40 for the 'EVR' VIA work-alike. + * Perhaps OSS uses vRAM1 and vRAM2 for ADB. + */ + +#define VIA2A_vRAM1 0x80 /* RAM size bit 1 (IIci: reserved) */ +#define VIA2A_vRAM0 0x40 /* RAM size bit 0 (IIci: internal video IRQ) */ +#define VIA2A_vIRQE 0x20 /* IRQ from slot $E */ +#define VIA2A_vIRQD 0x10 /* IRQ from slot $D */ +#define VIA2A_vIRQC 0x08 /* IRQ from slot $C */ +#define VIA2A_vIRQB 0x04 /* IRQ from slot $B */ +#define VIA2A_vIRQA 0x02 /* IRQ from slot $A */ +#define VIA2A_vIRQ9 0x01 /* IRQ from slot $9 */ + +/* RAM size bits decoded as follows: + * bit1 bit0 size of ICs in bank A + * 0 0 256 kbit + * 0 1 1 Mbit + * 1 0 4 Mbit + * 1 1 16 Mbit + */ + +/* + * Register B has the fun stuff in it + */ + +#define VIA2B_vVBL 0x80 /* VBL output to VIA1 (60.15Hz) driven by + * timer T1. + * on IIci, parity test: 0=test mode. + * [MkLinux] RBV_PARODD: 1=odd,0=even. */ +#define VIA2B_vSndJck 0x40 /* External sound jack status. + * 0=plug is inserted. On SE/30, always 0 */ +#define VIA2B_vTfr0 0x20 /* Transfer mode bit 0 ack from NuBus */ +#define VIA2B_vTfr1 0x10 /* Transfer mode bit 1 ack from NuBus */ +#define VIA2B_vMode32 0x08 /* 24/32bit switch - doubles as cache flush + * on II, AMU/PMMU control. + * if AMU, 0=24bit to 32bit translation + * if PMMU, 1=PMMU is accessing page table. + * on SE/30 tied low. + * on IIx,IIcx,IIfx, unused. + * on IIci/RBV, cache control. 0=flush cache. + */ +#define VIA2B_vPower 0x04 /* Power off, 0=shut off power. + * on SE/30 this signal sent to PDS card. */ +#define VIA2B_vBusLk 0x02 /* Lock NuBus transactions, 0=locked. + * on SE/30 sent to PDS card. */ +#define VIA2B_vCDis 0x01 /* Cache control. On IIci, 1=disable cache card + * on others, 0=disable processor's instruction + * and data caches. */ + +/* Apple sez: http://developer.apple.com/technotes/ov/ov_04.html + * Another example of a valid function that has no ROM support is the use + * of the alternate video page for page-flipping animation. Since there + * is no ROM call to flip pages, it is necessary to go play with the + * right bit in the VIA chip (6522 Versatile Interface Adapter). + * [CSA: don't know which one this is, but it's one of 'em!] + */ + +/* + * 6522 registers - see databook. + * CSA: Assignments for VIA1 confirmed from CHRP spec. + */ + +/* partial address decode. 0xYYXX : XX part for RBV, YY part for VIA */ +/* Note: 15 VIA regs, 8 RBV regs */ + +#define vBufB 0x0000 /* [VIA/RBV] Register B */ +#define vBufAH 0x0200 /* [VIA only] Buffer A, with handshake. DON'T USE! */ +#define vDirB 0x0400 /* [VIA only] Data Direction Register B. */ +#define vDirA 0x0600 /* [VIA only] Data Direction Register A. */ +#define vT1CL 0x0800 /* [VIA only] Timer one counter low. */ +#define vT1CH 0x0a00 /* [VIA only] Timer one counter high. */ +#define vT1LL 0x0c00 /* [VIA only] Timer one latches low. */ +#define vT1LH 0x0e00 /* [VIA only] Timer one latches high. */ +#define vT2CL 0x1000 /* [VIA only] Timer two counter low. */ +#define vT2CH 0x1200 /* [VIA only] Timer two counter high. */ +#define vSR 0x1400 /* [VIA only] Shift register. */ +#define vACR 0x1600 /* [VIA only] Auxilary control register. */ +#define vPCR 0x1800 /* [VIA only] Peripheral control register. */ + /* CHRP sez never ever to *write* this. + * Mac family says never to *change* this. + * In fact we need to initialize it once at start. */ +#define vIFR 0x1a00 /* [VIA/RBV] Interrupt flag register. */ +#define vIER 0x1c00 /* [VIA/RBV] Interrupt enable register. */ +#define vBufA 0x1e00 /* [VIA/RBV] register A (no handshake) */ + +/* The RBV only decodes the bottom eight address lines; the VIA doesn't + * decode the bottom eight -- so vBufB | rBufB will always get you BufB */ +/* CSA: in fact, only bits 0,1, and 4 seem to be decoded. + * BUT note the values for rIER and rIFR, where the top 8 bits *do* seem + * to matter. In fact *all* of the top 8 bits seem to matter; + * setting rIER=0x1813 and rIFR=0x1803 doesn't work, either. + * Perhaps some sort of 'compatibility mode' is built-in? [21-May-1999] + */ + +#define rBufB 0x0000 /* [VIA/RBV] Register B */ +#define rExp 0x0001 /* [RBV only] RBV future expansion (always 0) */ +#define rSIFR 0x0002 /* [RBV only] RBV slot interrupts register. */ +#define rIFR 0x1a03 /* [VIA/RBV] RBV interrupt flag register. */ +#define rMonP 0x0010 /* [RBV only] RBV video monitor type. */ +#define rChpT 0x0011 /* [RBV only] RBV test mode register (reads as 0). */ +#define rSIER 0x0012 /* [RBV only] RBV slot interrupt enables. */ +#define rIER 0x1c13 /* [VIA/RBV] RBV interrupt flag enable register. */ +#define rBufA rSIFR /* the 'slot interrupts register' is BufA on a VIA */ + +/* + * Video monitor parameters, for rMonP: + */ +#define RBV_DEPTH 0x07 /* bits per pixel: 000=1,001=2,010=4,011=8 */ +#define RBV_MONID 0x38 /* monitor type, as below. */ +#define RBV_VIDOFF 0x40 /* 1 turns off onboard video */ +/* Supported monitor types: */ +#define MON_15BW (1<<3) /* 15" BW portrait. */ +#define MON_IIGS (2<<3) /* 12" color (modified IIGS monitor). */ +#define MON_15RGB (5<<3) /* 15" RGB portrait. */ +#define MON_12OR13 (6<<3) /* 12" BW or 13" RGB. */ +#define MON_NONE (7<<3) /* No monitor attached. */ + +/* To clarify IER manipulations */ +#define IER_SET_BIT(b) (0x80 | (1<<(b)) ) +#define IER_CLR_BIT(b) (0x7F & (1<<(b)) ) + +#ifndef __ASSEMBLY__ + +extern volatile __u8 *via1,*via2; +extern int rbv_present,via_alt_mapping; +extern __u8 rbv_clear; + +extern __inline__ int rbv_set_video_bpp(int bpp) { + char val = (bpp==1)?0:(bpp==2)?1:(bpp==4)?2:(bpp==8)?3:-1; + if (!rbv_present || val<0) return -1; + via2[rMonP] = (via2[rMonP] & ~RBV_DEPTH) | val; + return 0; +} + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_MAC_VIA_H_ */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/machdep.h linux/include/asm-m68k/machdep.h --- v2.3.16/linux/include/asm-m68k/machdep.h Tue Jan 19 10:58:34 1999 +++ linux/include/asm-m68k/machdep.h Sat Sep 4 13:06:41 1999 @@ -30,6 +30,8 @@ extern int (*mach_hwclk)(int, struct hwclk_time*); extern int (*mach_set_clock_mmss)(unsigned long); extern void (*mach_reset)( void ); +extern void (*mach_halt)( void ); +extern void (*mach_power_off)( void ); extern unsigned long (*mach_hd_init) (unsigned long, unsigned long); extern void (*mach_hd_setup)(char *, int *); extern long mach_max_dma_address; diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/machines.h linux/include/asm-m68k/machines.h --- v2.3.16/linux/include/asm-m68k/machines.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/machines.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,87 @@ +/* $Id: machines.h,v 1.4 1995/11/25 02:31:58 davem Exp $ + * machines.h: Defines for taking apart the machine type value in the + * idprom and determining the kind of machine we are on. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Sun3/3x models added by David Monro (davidm@psrg.cs.usyd.edu.au) + */ +#ifndef _SPARC_MACHINES_H +#define _SPARC_MACHINES_H + +struct Sun_Machine_Models { + char *name; + unsigned char id_machtype; +}; + +/* Current number of machines we know about that has an IDPROM + * machtype entry including one entry for the 0x80 OBP machines. + */ +// reduced along with table in arch/m68k/sun3/idprom.c +// sun3 port doesn't need to know about sparc machines. +//#define NUM_SUN_MACHINES 23 +#define NUM_SUN_MACHINES 8 + +extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES]; + +/* The machine type in the idprom area looks like this: + * + * --------------- + * | ARCH | MACH | + * --------------- + * 7 4 3 0 + * + * The ARCH field determines the architecture line (sun4, sun4c, etc). + * The MACH field determines the machine make within that architecture. + */ + +#define SM_ARCH_MASK 0xf0 +#define SM_SUN3 0x10 +#define SM_SUN4 0x20 +#define SM_SUN3X 0x40 +#define SM_SUN4C 0x50 +#define SM_SUN4M 0x70 +#define SM_SUN4M_OBP 0x80 + +#define SM_TYP_MASK 0x0f +/* Sun3 machines */ +#define SM_3_160 0x01 /* Sun 3/160 series */ +#define SM_3_50 0x02 /* Sun 3/50 series */ +#define SM_3_260 0x03 /* Sun 3/260 series */ +#define SM_3_110 0x04 /* Sun 3/110 series */ +#define SM_3_60 0x07 /* Sun 3/60 series */ +#define SM_3_E 0x08 /* Sun 3/E series */ + +/* Sun3x machines */ +#define SM_3_460 0x01 /* Sun 3/460 (460,470,480) series */ +#define SM_3_80 0x02 /* Sun 3/80 series */ + +/* Sun4 machines */ +#define SM_4_260 0x01 /* Sun 4/200 series */ +#define SM_4_110 0x02 /* Sun 4/100 series */ +#define SM_4_330 0x03 /* Sun 4/300 series */ +#define SM_4_470 0x04 /* Sun 4/400 series */ + +/* Sun4c machines Full Name - PROM NAME */ +#define SM_4C_SS1 0x01 /* Sun4c SparcStation 1 - Sun 4/60 */ +#define SM_4C_IPC 0x02 /* Sun4c SparcStation IPC - Sun 4/40 */ +#define SM_4C_SS1PLUS 0x03 /* Sun4c SparcStation 1+ - Sun 4/65 */ +#define SM_4C_SLC 0x04 /* Sun4c SparcStation SLC - Sun 4/20 */ +#define SM_4C_SS2 0x05 /* Sun4c SparcStation 2 - Sun 4/75 */ +#define SM_4C_ELC 0x06 /* Sun4c SparcStation ELC - Sun 4/25 */ +#define SM_4C_IPX 0x07 /* Sun4c SparcStation IPX - Sun 4/50 */ + +/* Sun4m machines, these predate the OpenBoot. These values only mean + * something if the value in the ARCH field is SM_SUN4M, if it is + * SM_SUN4M_OBP then you have the following situation: + * 1) You either have a sun4d, a sun4e, or a recently made sun4m. + * 2) You have to consult OpenBoot to determine which machine this is. + */ +#define SM_4M_SS60 0x01 /* Sun4m SparcSystem 600 */ +#define SM_4M_SS50 0x02 /* Sun4m SparcStation 10 */ +#define SM_4M_SS40 0x03 /* Sun4m SparcStation 5 */ + +/* Sun4d machines -- N/A */ +/* Sun4e machines -- N/A */ +/* Sun4u machines -- N/A */ + +#endif /* !(_SPARC_MACHINES_H) */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/machw.h linux/include/asm-m68k/machw.h --- v2.3.16/linux/include/asm-m68k/machw.h Tue Jan 19 10:58:34 1999 +++ linux/include/asm-m68k/machw.h Sat Sep 4 13:06:41 1999 @@ -25,6 +25,7 @@ #include +#if 0 /* Mac SCSI Controller 5380 */ #define MAC_5380_BAS (0x50F10000) /* This is definitely wrong!! */ @@ -63,65 +64,7 @@ u_char cha_b_data; }; # define mac_scc ((*(volatile struct SCC*)MAC_SCC_BAS)) - -/* -** VIA 6522 -*/ - -#define VIA1_BAS (0x50F00000) -#define VIA2_BAS (0x50F02000) -#define VIA2_BAS_IIci (0x50F26000) -struct VIA - { - u_char buf_b; - u_char dummy1[0x199]; - u_char buf_a; - u_char dummy2[0x199]; - u_char dir_b; - u_char dummy3[0x199]; - u_char dir_a; - u_char dummy4[0x199]; - u_char timer1_cl; - u_char dummy5[0x199]; - u_char timer1_ch; - u_char dummy6[0x199]; - u_char timer1_ll; - u_char dummy7[0x199]; - u_char timer1_lh; - u_char dummy8[0x199]; - u_char timer2_cl; - u_char dummy9[0x199]; - u_char timer2_ch; - u_char dummy10[0x199]; - u_char sr; - u_char dummy11[0x199]; - u_char acr; - u_char dummy12[0x199]; - u_char pcr; - u_char dummy13[0x199]; - u_char int_fl; - u_char dummy14[0x199]; - u_char int_en; - u_char dummy15[0x199]; - u_char anr; - u_char dummy16[0x199]; - }; - -# define via_1 ((*(volatile struct VIA *)VIA1_BAS)) -# define via_2 ((*(volatile struct VIA *)VIA2_BAS)) -# define via1_regp ((volatile unsigned char *)VIA1_BAS) - -/* - * OSS/RBV base address - */ - -#define OSS_BAS 0x50f1a000 -#define PSC_BAS 0x50f31000 - -/* move to oss.h?? */ -#define nIFR 0x203 -#define oIFR 0x202 - +#endif /* hardware stuff */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/macintosh.h linux/include/asm-m68k/macintosh.h --- v2.3.16/linux/include/asm-m68k/macintosh.h Mon Oct 5 13:54:39 1998 +++ linux/include/asm-m68k/macintosh.h Sat Sep 4 13:06:41 1999 @@ -6,6 +6,7 @@ */ extern void mac_reset(void); +extern void mac_poweroff(void); extern void mac_init_IRQ(void); extern int mac_request_irq (unsigned int, void (*)(int, void *, struct pt_regs *), @@ -13,6 +14,7 @@ extern void mac_free_irq(unsigned int, void *); extern void mac_enable_irq(unsigned int); extern void mac_disable_irq(unsigned int); +extern int mac_irq_pending(unsigned int); extern int mac_get_irq_list(char *); #if 0 extern void mac_default_handler(int irq); @@ -21,7 +23,6 @@ extern void mac_report_hardware(void); extern void mac_debugging_penguin(int); extern void mac_boom(int); -extern void mac_video_setup(char *,int *); /* * Floppy driver magic hook - probably shouldnt be here @@ -58,6 +59,7 @@ #define MAC_ADB_CUDA 3 #define MAC_ADB_PB1 4 #define MAC_ADB_PB2 5 +#define MAC_ADB_IOP 6 #define MAC_VIA_II 1 #define MAC_VIA_IIci 2 @@ -131,6 +133,7 @@ #define MAC_MODEL_P550 80 /* aka: LC550, P560 */ #define MAC_MODEL_CCLII 83 /* aka: P275 */ #define MAC_MODEL_PB165 84 +#define MAC_MODEL_PB190 85 /* aka: PB190CS */ #define MAC_MODEL_TV 88 #define MAC_MODEL_P475 89 /* aka: LC475, P476 */ #define MAC_MODEL_P475F 90 /* aka: P475 w/ FPU (no LC040) */ @@ -141,7 +144,6 @@ #define MAC_MODEL_PB280 102 #define MAC_MODEL_PB280C 103 #define MAC_MODEL_PB150 115 -#define MAC_MODEL_PB190 122 /* aka: PB190CS */ extern struct mac_model *macintosh_config; diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/macints.h linux/include/asm-m68k/macints.h --- v2.3.16/linux/include/asm-m68k/macints.h Sat Jun 13 13:14:33 1998 +++ linux/include/asm-m68k/macints.h Sat Sep 4 13:06:41 1999 @@ -14,38 +14,49 @@ #include -/* -** Macintosh Interrupt sources. -** -** Note: these are all routed via the generic VIA interrupt routine! -** -*/ +/* Setting this prints debugging info for unclaimed interrupts */ + +#define DEBUG_SPURIOUS + +/* Setting this prints debugging info on each autovector interrupt */ + +/* #define DEBUG_IRQS */ + +/* Setting this prints debugging info on each Nubus interrupt */ -#define SRC_VIA1 0 -#define SRC_VIA2 1 +/* #define DEBUG_NUBUS_INT */ + +/* Setting this prints debugging info on irqs as they enabled and disabled. */ + +/* #define DEBUG_IRQUSE */ + +/* + * Base IRQ number for all Mac68K interrupt sources. Each source + * has eight indexes (base -> base+7). + */ #define VIA1_SOURCE_BASE 8 #define VIA2_SOURCE_BASE 16 -#define RBV_SOURCE_BASE 24 -#define MAC_SCC_SOURCE_BASE 32 +#define MAC_SCC_SOURCE_BASE 24 +#define PSC3_SOURCE_BASE 24 +#define PSC4_SOURCE_BASE 32 +#define PSC5_SOURCE_BASE 40 +#define PSC6_SOURCE_BASE 48 #define NUBUS_SOURCE_BASE 56 -#define NUBUS_MAX_SOURCES 8 -/* FIXME: sources not contigous ... */ -#define NUM_MAC_SOURCES (NUBUS_SOURCE_BASE+NUBUS_MAX_SOURCES-VIA1_SOURCE_BASE) +/* + * Maximum IRQ number is NUBUS_SOURCE_BASE + 7, + * giving us IRQs up through 63. + */ -#define IRQ_SRC_MASK (VIA1_SOURCE_BASE|VIA2_SOURCE_BASE|MAC_SCC_SOURCE_BASE) -#define IRQ_IDX_MASK 7 +#define NUM_MAC_SOURCES 64 /* - * quick hack to adapt old MACHSPEC-aware source + * clean way to separate IRQ into its source and index */ -#define IRQ_IDX(irq) (irq) -/* interrupt service types */ -#define IRQ_TYPE_SLOW 0 -#define IRQ_TYPE_FAST 1 -#define IRQ_TYPE_PRIO 2 +#define IRQ_SRC(irq) (irq >> 3) +#define IRQ_IDX(irq) (irq & 7) #define IRQ_SPURIOUS (0) @@ -59,15 +70,15 @@ #define IRQ_AUTO_7 (7) /* VIA1 interrupts */ -#define IRQ_VIA1_0 (8) /* one second int. */ -#define IRQ_VIA1_1 (9) /* VBlank int. */ +#define IRQ_VIA1_0 (8) /* one second int. */ +#define IRQ_VIA1_1 (9) /* VBlank int. */ #define IRQ_MAC_VBL IRQ_VIA1_1 -#define IRQ_VIA1_2 (10) /* ADB SR shifts complete */ +#define IRQ_VIA1_2 (10) /* ADB SR shifts complete */ #define IRQ_MAC_ADB IRQ_VIA1_2 #define IRQ_MAC_ADB_SR IRQ_VIA1_2 -#define IRQ_VIA1_3 (11) /* ADB SR CB2 ?? */ +#define IRQ_VIA1_3 (11) /* ADB SR CB2 ?? */ #define IRQ_MAC_ADB_SD IRQ_VIA1_3 -#define IRQ_VIA1_4 (12) /* ADB SR ext. clock pulse */ +#define IRQ_VIA1_4 (12) /* ADB SR ext. clock pulse */ #define IRQ_MAC_ADB_CL IRQ_VIA1_4 #define IRQ_VIA1_5 (13) #define IRQ_MAC_TIMER_2 IRQ_VIA1_5 @@ -75,7 +86,7 @@ #define IRQ_MAC_TIMER_1 IRQ_VIA1_6 #define IRQ_VIA1_7 (15) -/* VIA2 interrupts */ +/* VIA2/RBV interrupts */ #define IRQ_VIA2_0 (16) #define IRQ_MAC_SCSIDRQ IRQ_VIA2_0 #define IRQ_VIA2_1 (17) @@ -88,18 +99,6 @@ #define IRQ_VIA2_6 (22) #define IRQ_VIA2_7 (23) -#if 0 -/* RBV interrupts */ -#define IRQ_RBV_0 (24) -#define IRQ_RBV_1 (25) -#define IRQ_RBV_2 (26) -#define IRQ_RBV_3 (27) -#define IRQ_RBV_4 (28) -#define IRQ_RBV_5 (29) -#define IRQ_RBV_6 (30) -#define IRQ_RBV_7 (31) -#endif - /* Level 3 (PSC, AV Macs only) interrupts */ #define IRQ_PSC3_0 (24) #define IRQ_MAC_MACE IRQ_PSC3_0 @@ -109,8 +108,8 @@ /* Level 4 (SCC) interrupts */ #define IRQ_SCC (32) -#define IRQ_SCCB (33) -#define IRQ_SCCA (34) +#define IRQ_SCCA (33) +#define IRQ_SCCB (34) #if 0 /* FIXME: are there multiple interrupt conditions on the SCC ?? */ /* SCC interrupts */ #define IRQ_SCCB_TX (32) @@ -143,40 +142,21 @@ #define IRQ_PSC6_3 (51) /* Nubus interrupts (cascaded to VIA2) */ -#define IRQ_NUBUS_1 (56) +#define IRQ_NUBUS_9 (56) +#define IRQ_NUBUS_A (57) +#define IRQ_NUBUS_B (58) +#define IRQ_NUBUS_C (59) +#define IRQ_NUBUS_D (60) +#define IRQ_NUBUS_E (61) +#define IRQ_NUBUS_F (62) + +#define SLOT2IRQ(x) (x + 47) +#define IRQ2SLOT(x) (x - 47) #define INT_CLK 24576 /* CLK while int_clk =2.456MHz and divide = 100 */ #define INT_TICKS 246 /* to make sched_time = 99.902... HZ */ - -#define VIA_ENABLE 0 -#define VIA_PENDING 1 -#define VIA_SERVICE 2 -#define VIA_MASK 3 - -/* - * Utility functions for setting/clearing bits in the interrupt registers of - * the VIA. - */ - -void mac_enable_irq( unsigned irq ); -void mac_disable_irq( unsigned irq ); -void mac_turnon_irq( unsigned irq ); -void mac_turnoff_irq( unsigned irq ); -void mac_clear_pending_irq( unsigned irq ); -int mac_irq_pending( unsigned irq ); -int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct pt_regs *)); -int nubus_free_irq(int slot); - -unsigned long mac_register_nubus_int( void ); -void mac_unregister_nubus_int( unsigned long ); - -extern void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs); -extern void via1_irq(int irq, void *dev_id, struct pt_regs *regs); -extern void via2_irq(int irq, void *dev_id, struct pt_regs *regs); -extern void rbv_irq(int irq, void *dev_id, struct pt_regs *regs); -extern void mac_bang(int irq, void *dev_id, struct pt_regs *regs); - -extern void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs); +extern irq_node_t *mac_irq_list[NUM_MAC_SOURCES]; +extern void mac_do_irq_list(int irq, struct pt_regs *); #endif /* asm/macints.h */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/mmu_context.h linux/include/asm-m68k/mmu_context.h --- v2.3.16/linux/include/asm-m68k/mmu_context.h Mon Aug 9 12:27:31 1999 +++ linux/include/asm-m68k/mmu_context.h Sat Sep 4 13:06:41 1999 @@ -1,6 +1,8 @@ #ifndef __M68K_MMU_CONTEXT_H #define __M68K_MMU_CONTEXT_H +#ifndef CONFIG_SUN3 + #include #include @@ -90,4 +92,68 @@ switch_mm_0460(next_mm); } +#else /* CONFIG_SUN3 */ +#include +#include + +extern unsigned long get_free_context(struct mm_struct *mm); +extern void clear_context(unsigned long context); +extern unsigned char ctx_next_to_die; +extern unsigned char ctx_live[SUN3_CONTEXTS_NUM]; + +/* set the context for a new task to unmapped */ +static inline void init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + mm->context = SUN3_INVALID_CONTEXT; +} + +/* find the context given to this process, and if it hasn't already + got one, go get one for it. */ +static inline void get_mmu_context(struct mm_struct *mm) +{ + if(mm->context == SUN3_INVALID_CONTEXT) + mm->context = get_free_context(mm); +} + +#if 0 +/* we used to clear the context after the process exited. we still + should, things are faster that way... but very unstable. so just + clear out a context next time we need a new one.. consider this a + FIXME. */ + +/* flush context if allocated... */ +static inline void destroy_context(struct mm_struct *mm) +{ + if(mm->context != SUN3_INVALID_CONTEXT) + clear_context(mm->context); +} +#else +/* mark this context as dropped and set it for next death */ +static inline void destroy_context(struct mm_struct *mm) +{ + if(mm->context != SUN3_INVALID_CONTEXT) { + ctx_next_to_die = mm->context; + ctx_live[mm->context] = 0; + } +} +#endif + +static inline void activate_context(struct mm_struct *mm) +{ + get_mmu_context(mm); + sun3_put_context(mm->context); +} + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) +{ + activate_context(tsk->mm); +} + +extern inline void activate_mm(struct mm_struct *prev_mm, + struct mm_struct *next_mm) +{ + activate_context(next_mm); +} + +#endif #endif diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/movs.h linux/include/asm-m68k/movs.h --- v2.3.16/linux/include/asm-m68k/movs.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/movs.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,55 @@ +#ifndef __MOVS_H__ +#define __MOVS_H__ + +/* +** movs.h +** +** Inline assembly macros to generate movs & related instructions +*/ + +/* Set DFC register value */ + +#define SET_DFC(x) \ + __asm__ __volatile__ (" movec %0,%/dfc" : : "d" (x)); + +/* Get DFC register value */ + +#define GET_DFC(x) \ + __asm__ __volatile__ (" movec %/dfc, %0" : "=d" (x) : ); + +/* Set SFC register value */ + +#define SET_SFC(x) \ + __asm__ __volatile__ (" movec %0,%/sfc" : : "d" (x)); + +/* Get SFC register value */ + +#define GET_SFC(x) \ + __asm__ __volatile__ (" movec %/sfc, %0" : "=d" (x) : ); + +#define SET_VBR(x) \ + __asm__ __volatile__ (" movec %0,%/vbr" : : "r" (x)); + +#define GET_VBR(x) \ + __asm__ __volatile__ (" movec %/vbr, %0" : "=g" (x) : ); + +/* Set a byte using the "movs" instruction */ + +#define SET_CONTROL_BYTE(addr,value) \ + __asm__ __volatile__ (" movsb %0, %1@" : : "d" (value), "a" (addr)); + +/* Get a byte using the "movs" instruction */ + +#define GET_CONTROL_BYTE(addr,value) \ + __asm__ __volatile__ (" movsb %1@, %0" : "=d" (value) : "a" (addr)); + +/* Set a (long)word using the "movs" instruction */ + +#define SET_CONTROL_WORD(addr,value) \ + __asm__ __volatile__ (" movsl %0, %1@" : : "d" (value), "a" (addr)); + +/* Get a (long)word using the "movs" instruction */ + +#define GET_CONTROL_WORD(addr,value) \ + __asm__ __volatile__ (" movsl %1@, %0" : "=d" (value) : "a" (addr)); +#endif diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/openprom.h linux/include/asm-m68k/openprom.h --- v2.3.16/linux/include/asm-m68k/openprom.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/openprom.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,309 @@ +/* $Id: openprom.h,v 1.19 1996/09/25 03:51:08 davem Exp $ */ +#ifndef __SPARC_OPENPROM_H +#define __SPARC_OPENPROM_H + +/* openprom.h: Prom structures and defines for access to the OPENBOOT + * prom routines and data areas. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +/* Empirical constants... */ +#ifdef CONFIG_SUN3 +#define KADB_DEBUGGER_BEGVM 0x0fee0000 /* There is no kadb yet but...*/ +#define LINUX_OPPROM_BEGVM 0x0fef0000 +#define LINUX_OPPROM_ENDVM 0x0ff10000 /* I think this is right - tm */ +#else +#define KADB_DEBUGGER_BEGVM 0xffc00000 /* Where kern debugger is in virt-mem */ +#define LINUX_OPPROM_BEGVM 0xffd00000 +#define LINUX_OPPROM_ENDVM 0xfff00000 +#define LINUX_OPPROM_MAGIC 0x10010407 +#endif + +#ifndef __ASSEMBLY__ +/* V0 prom device operations. */ +struct linux_dev_v0_funcs { + int (*v0_devopen)(char *device_str); + int (*v0_devclose)(int dev_desc); + int (*v0_rdblkdev)(int dev_desc, int num_blks, int blk_st, char *buf); + int (*v0_wrblkdev)(int dev_desc, int num_blks, int blk_st, char *buf); + int (*v0_wrnetdev)(int dev_desc, int num_bytes, char *buf); + int (*v0_rdnetdev)(int dev_desc, int num_bytes, char *buf); + int (*v0_rdchardev)(int dev_desc, int num_bytes, int dummy, char *buf); + int (*v0_wrchardev)(int dev_desc, int num_bytes, int dummy, char *buf); + int (*v0_seekdev)(int dev_desc, long logical_offst, int from); +}; + +/* V2 and later prom device operations. */ +struct linux_dev_v2_funcs { + int (*v2_inst2pkg)(int d); /* Convert ihandle to phandle */ + char * (*v2_dumb_mem_alloc)(char *va, unsigned sz); + void (*v2_dumb_mem_free)(char *va, unsigned sz); + + /* To map devices into virtual I/O space. */ + char * (*v2_dumb_mmap)(char *virta, int which_io, unsigned paddr, unsigned sz); + void (*v2_dumb_munmap)(char *virta, unsigned size); + + int (*v2_dev_open)(char *devpath); + void (*v2_dev_close)(int d); + int (*v2_dev_read)(int d, char *buf, int nbytes); + int (*v2_dev_write)(int d, char *buf, int nbytes); + int (*v2_dev_seek)(int d, int hi, int lo); + + /* Never issued (multistage load support) */ + void (*v2_wheee2)(void); + void (*v2_wheee3)(void); +}; + +struct linux_mlist_v0 { + struct linux_mlist_v0 *theres_more; + char *start_adr; + unsigned num_bytes; +}; + +struct linux_mem_v0 { + struct linux_mlist_v0 **v0_totphys; + struct linux_mlist_v0 **v0_prommap; + struct linux_mlist_v0 **v0_available; /* What we can use */ +}; + +/* Arguments sent to the kernel from the boot prompt. */ +struct linux_arguments_v0 { + char *argv[8]; + char args[100]; + char boot_dev[2]; + int boot_dev_ctrl; + int boot_dev_unit; + int dev_partition; + char *kernel_file_name; + void *aieee1; /* XXX */ +}; + +/* V2 and up boot things. */ +struct linux_bootargs_v2 { + char **bootpath; + char **bootargs; + int *fd_stdin; + int *fd_stdout; +}; + +#ifdef CONFIG_SUN3 +struct linux_romvec { + char *pv_initsp; + int (*pv_startmon)(void); + + int *diagberr; + + struct linux_arguments_v0 **pv_v0bootargs; + unsigned *pv_sun3mem; + + unsigned char (*pv_getchar)(void); + int (*pv_putchar)(int ch); + int (*pv_nbgetchar)(void); + int (*pv_nbputchar)(int ch); + unsigned char *pv_echo; + unsigned char *pv_insource; + unsigned char *pv_outsink; + + int (*pv_getkey)(void); + int (*pv_initgetkey)(void); + unsigned int *pv_translation; + unsigned char *pv_keybid; + int *pv_screen_x; + int *pv_screen_y; + struct keybuf *pv_keybuf; + + char *pv_monid; + + /* + * Frame buffer output and terminal emulation + */ + + int (*pv_fbwritechar)(char); + int *pv_fbaddr; + char **pv_font; + int (*pv_fbwritestr)(char); + + void (*pv_reboot)(char *bootstr); + + /* + * Line input and parsing + */ + + unsigned char *pv_linebuf; + unsigned char **pv_lineptr; + int *pv_linesize; + int (*pv_getline)(void); + unsigned char (*pv_getnextchar)(void); + unsigned char (*pv_peeknextchar)(void); + int *pv_fbthere; + int (*pv_getnum)(void); + + void (*pv_printf)(const char *fmt, ...); + int (*pv_printhex)(void); + + unsigned char *pv_leds; + int (*pv_setleds)(void); + + /* + * Non-maskable interrupt (nmi) information + */ + + int (*pv_nmiaddr)(void); + int (*pv_abortentry)(void); + int *pv_nmiclock; + + int *pv_fbtype; + + /* + * Assorted other things + */ + + unsigned pv_romvers; + struct globram *pv_globram; + char *pv_kbdzscc; + + int *pv_keyrinit; + unsigned char *pv_keyrtick; + unsigned *pv_memoryavail; + long *pv_resetaddr; + long *pv_resetmap; + + void (*pv_halt)(void); + unsigned char *pv_memorybitmap; + void (*pv_setctxt)(int ctxt, char *va, int pmeg); + void (*pv_vector_cmd)(void); + int dummy1z; + int dummy2z; + int dummy3z; + int dummy4z; +}; +#else +/* The top level PROM vector. */ +struct linux_romvec { + /* Version numbers. */ + unsigned int pv_magic_cookie; + unsigned int pv_romvers; + unsigned int pv_plugin_revision; + unsigned int pv_printrev; + + /* Version 0 memory descriptors. */ + struct linux_mem_v0 pv_v0mem; + + /* Node operations. */ + struct linux_nodeops *pv_nodeops; + + char **pv_bootstr; + struct linux_dev_v0_funcs pv_v0devops; + + char *pv_stdin; + char *pv_stdout; +#define PROMDEV_KBD 0 /* input from keyboard */ +#define PROMDEV_SCREEN 0 /* output to screen */ +#define PROMDEV_TTYA 1 /* in/out to ttya */ +#define PROMDEV_TTYB 2 /* in/out to ttyb */ + + /* Blocking getchar/putchar. NOT REENTRANT! (grr) */ + int (*pv_getchar)(void); + void (*pv_putchar)(int ch); + + /* Non-blocking variants. */ + int (*pv_nbgetchar)(void); + int (*pv_nbputchar)(int ch); + + void (*pv_putstr)(char *str, int len); + + /* Miscellany. */ + void (*pv_reboot)(char *bootstr); + void (*pv_printf)(__const__ char *fmt, ...); + void (*pv_abort)(void); + __volatile__ int *pv_ticks; + void (*pv_halt)(void); + void (**pv_synchook)(void); + + /* Evaluate a forth string, not different proto for V0 and V2->up. */ + union { + void (*v0_eval)(int len, char *str); + void (*v2_eval)(char *str); + } pv_fortheval; + + struct linux_arguments_v0 **pv_v0bootargs; + + /* Get ether address. */ + unsigned int (*pv_enaddr)(int d, char *enaddr); + + struct linux_bootargs_v2 pv_v2bootargs; + struct linux_dev_v2_funcs pv_v2devops; + + int filler[15]; + + /* This one is sun4c/sun4 only. */ + void (*pv_setctxt)(int ctxt, char *va, int pmeg); + + /* Prom version 3 Multiprocessor routines. This stuff is crazy. + * No joke. Calling these when there is only one cpu probably + * crashes the machine, have to test this. :-) + */ + + /* v3_cpustart() will start the cpu 'whichcpu' in mmu-context + * 'thiscontext' executing at address 'prog_counter' + */ + int (*v3_cpustart)(unsigned int whichcpu, int ctxtbl_ptr, + int thiscontext, char *prog_counter); + + /* v3_cpustop() will cause cpu 'whichcpu' to stop executing + * until a resume cpu call is made. + */ + int (*v3_cpustop)(unsigned int whichcpu); + + /* v3_cpuidle() will idle cpu 'whichcpu' until a stop or + * resume cpu call is made. + */ + int (*v3_cpuidle)(unsigned int whichcpu); + + /* v3_cpuresume() will resume processor 'whichcpu' executing + * starting with whatever 'pc' and 'npc' were left at the + * last 'idle' or 'stop' call. + */ + int (*v3_cpuresume)(unsigned int whichcpu); +}; +#endif + +/* Routines for traversing the prom device tree. */ +struct linux_nodeops { + int (*no_nextnode)(int node); + int (*no_child)(int node); + int (*no_proplen)(int node, char *name); + int (*no_getprop)(int node, char *name, char *val); + int (*no_setprop)(int node, char *name, char *val, int len); + char * (*no_nextprop)(int node, char *name); +}; + +/* More fun PROM structures for device probing. */ +#define PROMREG_MAX 16 +#define PROMVADDR_MAX 16 +#define PROMINTR_MAX 15 + +struct linux_prom_registers { + int which_io; /* is this in OBIO space? */ + char *phys_addr; /* The physical address of this register */ + int reg_size; /* How many bytes does this register take up? */ +}; + +struct linux_prom_irqs { + int pri; /* IRQ priority */ + int vector; /* This is foobar, what does it do? */ +}; + +/* Element of the "ranges" vector */ +struct linux_prom_ranges { + unsigned int ot_child_space; + unsigned int ot_child_base; /* Bus feels this */ + unsigned int ot_parent_space; + unsigned int ot_parent_base; /* CPU looks from here */ + unsigned int or_size; +}; + +#endif /* !(__ASSEMBLY__) */ + +#endif /* !(__SPARC_OPENPROM_H) */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/oplib.h linux/include/asm-m68k/oplib.h --- v2.3.16/linux/include/asm-m68k/oplib.h Tue May 11 09:57:14 1999 +++ linux/include/asm-m68k/oplib.h Sat Sep 4 13:06:41 1999 @@ -1,8 +1,297 @@ -/* - * prototypes for dummy prom_* routines +/* $Id: oplib.h,v 1.12 1996/10/31 06:29:13 davem Exp $ + * oplib.h: Describes the interface and available routines in the + * Linux Prom library. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#ifndef __SPARC_OPLIB_H +#define __SPARC_OPLIB_H + +#include + +/* The master romvec pointer... */ +extern struct linux_romvec *romvec; + +/* Enumeration to describe the prom major version we have detected. */ +enum prom_major_version { + PROM_V0, /* Original sun4c V0 prom */ + PROM_V2, /* sun4c and early sun4m V2 prom */ + PROM_V3, /* sun4m and later, up to sun4d/sun4e machines V3 */ + PROM_P1275, /* IEEE compliant ISA based Sun PROM, only sun4u */ + PROM_AP1000, /* actually no prom at all */ +}; + +extern enum prom_major_version prom_vers; +/* Revision, and firmware revision. */ +extern unsigned int prom_rev, prom_prev; + +/* Root node of the prom device tree, this stays constant after + * initialization is complete. + */ +extern int prom_root_node; + +/* Pointer to prom structure containing the device tree traversal + * and usage utility functions. Only prom-lib should use these, + * users use the interface defined by the library only! + */ +extern struct linux_nodeops *prom_nodeops; + +/* The functions... */ + +/* You must call prom_init() before using any of the library services, + * preferably as early as possible. Pass it the romvec pointer. + */ +extern void prom_init(struct linux_romvec *rom_ptr); + +/* Boot argument acquisition, returns the boot command line string. */ +extern char *prom_getbootargs(void); + +/* Device utilities. */ + +/* Map and unmap devices in IO space at virtual addresses. Note that the + * virtual address you pass is a request and the prom may put your mappings + * somewhere else, so check your return value as that is where your new + * mappings really are! + * + * Another note, these are only available on V2 or higher proms! + */ +extern char *prom_mapio(char *virt_hint, int io_space, unsigned int phys_addr, unsigned int num_bytes); +extern void prom_unmapio(char *virt_addr, unsigned int num_bytes); + +/* Device operations. */ + +/* Open the device described by the passed string. Note, that the format + * of the string is different on V0 vs. V2->higher proms. The caller must + * know what he/she is doing! Returns the device descriptor, an int. + */ +extern int prom_devopen(char *device_string); + +/* Close a previously opened device described by the passed integer + * descriptor. + */ +extern int prom_devclose(int device_handle); + +/* Do a seek operation on the device described by the passed integer + * descriptor. + */ +extern void prom_seek(int device_handle, unsigned int seek_hival, + unsigned int seek_lowval); + +/* Machine memory configuration routine. */ + +/* This function returns a V0 format memory descriptor table, it has three + * entries. One for the total amount of physical ram on the machine, one + * for the amount of physical ram available, and one describing the virtual + * areas which are allocated by the prom. So, in a sense the physical + * available is a calculation of the total physical minus the physical mapped + * by the prom with virtual mappings. + * + * These lists are returned pre-sorted, this should make your life easier + * since the prom itself is way too lazy to do such nice things. + */ +extern struct linux_mem_v0 *prom_meminfo(void); + +/* Miscellaneous routines, don't really fit in any category per se. */ + +/* Reboot the machine with the command line passed. */ +extern void prom_reboot(char *boot_command); + +/* Evaluate the forth string passed. */ +extern void prom_feval(char *forth_string); + +/* Enter the prom, with possibility of continuation with the 'go' + * command in newer proms. + */ +extern void prom_cmdline(void); + +/* Enter the prom, with no chance of continuation for the stand-alone + * which calls this. + */ +extern void prom_halt(void); + +/* Set the PROM 'sync' callback function to the passed function pointer. + * When the user gives the 'sync' command at the prom prompt while the + * kernel is still active, the prom will call this routine. + * + * XXX The arguments are different on V0 vs. V2->higher proms, grrr! XXX + */ +typedef void (*sync_func_t)(void); +extern void prom_setsync(sync_func_t func_ptr); + +/* Acquire the IDPROM of the root node in the prom device tree. This + * gets passed a buffer where you would like it stuffed. The return value + * is the format type of this idprom or 0xff on error. + */ +extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size); + +/* Get the prom major version. */ +extern int prom_version(void); + +/* Get the prom plugin revision. */ +extern int prom_getrev(void); + +/* Get the prom firmware revision. */ +extern int prom_getprev(void); + +/* Character operations to/from the console.... */ + +/* Non-blocking get character from console. */ +extern int prom_nbgetchar(void); + +/* Non-blocking put character to console. */ +extern int prom_nbputchar(char character); + +/* Blocking get character from console. */ +extern char prom_getchar(void); + +/* Blocking put character to console. */ +extern void prom_putchar(char character); + +/* Prom's internal printf routine, don't use in kernel/boot code. */ +void prom_printf(char *fmt, ...); + +/* Query for input device type */ + +enum prom_input_device { + PROMDEV_IKBD, /* input from keyboard */ + PROMDEV_ITTYA, /* input from ttya */ + PROMDEV_ITTYB, /* input from ttyb */ + PROMDEV_I_UNK, +}; + +extern enum prom_input_device prom_query_input_device(void); + +/* Query for output device type */ + +enum prom_output_device { + PROMDEV_OSCREEN, /* to screen */ + PROMDEV_OTTYA, /* to ttya */ + PROMDEV_OTTYB, /* to ttyb */ + PROMDEV_O_UNK, +}; + +extern enum prom_output_device prom_query_output_device(void); + +/* Multiprocessor operations... */ + +/* Start the CPU with the given device tree node, context table, and context + * at the passed program counter. + */ +extern int prom_startcpu(int cpunode, struct linux_prom_registers *context_table, + int context, char *program_counter); + +/* Stop the CPU with the passed device tree node. */ +extern int prom_stopcpu(int cpunode); + +/* Idle the CPU with the passed device tree node. */ +extern int prom_idlecpu(int cpunode); + +/* Re-Start the CPU with the passed device tree node. */ +extern int prom_restartcpu(int cpunode); + +/* PROM memory allocation facilities... */ + +/* Allocated at possibly the given virtual address a chunk of the + * indicated size. + */ +extern char *prom_alloc(char *virt_hint, unsigned int size); + +/* Free a previously allocated chunk. */ +extern void prom_free(char *virt_addr, unsigned int size); + +/* Sun4/sun4c specific memory-management startup hook. */ + +/* Map the passed segment in the given context at the passed + * virtual address. + */ +extern void prom_putsegment(int context, unsigned long virt_addr, + int physical_segment); + +/* PROM device tree traversal functions... */ + +/* Get the child node of the given node, or zero if no child exists. */ +extern int prom_getchild(int parent_node); + +/* Get the next sibling node of the given node, or zero if no further + * siblings exist. + */ +extern int prom_getsibling(int node); + +/* Get the length, at the passed node, of the given property type. + * Returns -1 on error (ie. no such property at this node). + */ +extern int prom_getproplen(int thisnode, char *property); + +/* Fetch the requested property using the given buffer. Returns + * the number of bytes the prom put into your buffer or -1 on error. + */ +extern int prom_getproperty(int thisnode, char *property, + char *prop_buffer, int propbuf_size); + +/* Acquire an integer property. */ +extern int prom_getint(int node, char *property); + +/* Acquire an integer property, with a default value. */ extern int prom_getintdefault(int node, char *property, int defval); + +/* Acquire a boolean property, 0=FALSE 1=TRUE. */ extern int prom_getbool(int node, char *prop); -extern void prom_printf(char *fmt, ...); -extern void prom_halt(void) __attribute__ ((noreturn)); + +/* Acquire a string property, null string on error. */ +extern void prom_getstring(int node, char *prop, char *buf, int bufsize); + +/* Does the passed node have the given "name"? YES=1 NO=0 */ +extern int prom_nodematch(int thisnode, char *name); + +/* Puts in buffer a prom name in the form name@x,y or name (x for which_io + * and y for first regs phys address + */ +extern int prom_getname(int node, char *buf, int buflen); + +/* Search all siblings starting at the passed node for "name" matching + * the given string. Returns the node on success, zero on failure. + */ +extern int prom_searchsiblings(int node_start, char *name); + +/* Return the first property type, as a string, for the given node. + * Returns a null string on error. + */ +extern char *prom_firstprop(int node); + +/* Returns the next property after the passed property for the given + * node. Returns null string on failure. + */ +extern char *prom_nextprop(int node, char *prev_property); + +/* Returns 1 if the specified node has given property. */ +extern int prom_node_has_property(int node, char *property); + +/* Set the indicated property at the given node with the passed value. + * Returns the number of bytes of your value that the prom took. + */ +extern int prom_setprop(int node, char *prop_name, char *prop_value, + int value_size); + +extern int prom_pathtoinode(char *path); +extern int prom_inst2pkg(int); + +/* Dorking with Bus ranges... */ + +/* Adjust reg values with the passed ranges. */ +extern void prom_adjust_regs(struct linux_prom_registers *regp, int nregs, + struct linux_prom_ranges *rangep, int nranges); + +/* Adjust child ranges with the passed parent ranges. */ +extern void prom_adjust_ranges(struct linux_prom_ranges *cranges, int ncranges, + struct linux_prom_ranges *pranges, int npranges); + +/* Apply promlib probed OBIO ranges to registers. */ +extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs); + +/* Apply ranges of any prom node (and optionally parent node as well) to registers. */ +extern void prom_apply_generic_ranges(int node, int parent, + struct linux_prom_registers *sbusregs, int nregs); + + +#endif /* !(__SPARC_OPLIB_H) */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/page.h linux/include/asm-m68k/page.h --- v2.3.16/linux/include/asm-m68k/page.h Mon Aug 9 12:27:31 1999 +++ linux/include/asm-m68k/page.h Sat Sep 4 13:06:41 1999 @@ -4,14 +4,27 @@ #include /* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT 12 -#define PAGE_SIZE (1UL << PAGE_SHIFT) +#ifndef CONFIG_SUN3 +#define PAGE_SHIFT (12) +#define PAGE_SIZE (4096) +#else +#define PAGE_SHIFT (13) +#define PAGE_SIZE (8192) +#endif #define PAGE_MASK (~(PAGE_SIZE-1)) #ifdef __KERNEL__ #include +#if PAGE_SHIFT < 13 +#define KTHREAD_SIZE (8192) +#else +#define KTHREAD_SIZE PAGE_SIZE +#endif + +#ifndef __ASSEMBLY__ + #define STRICT_MM_TYPECHECKS #define get_user_page(vaddr) __get_free_page(GFP_KERNEL) @@ -110,7 +123,13 @@ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) /* This handles the memory map.. */ +#ifndef CONFIG_SUN3 #define PAGE_OFFSET 0 +#else +#define PAGE_OFFSET 0x0E000000 +#endif + +#ifndef CONFIG_SUN3 #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) /* * A hacky workaround for the problems with mmap() of frame buffer @@ -128,12 +147,46 @@ #endif return (void *)(physaddr+PAGE_OFFSET); } +#else /* !CONFIG_SUN3 */ +/* This #define is a horrible hack to suppress lots of warnings. --m */ +#define __pa(x) ___pa((unsigned long)x) +static inline unsigned long ___pa(unsigned long x) +{ + if(x == 0) + return 0; + if(x > PAGE_OFFSET) + return (x-PAGE_OFFSET); + else + return (x+0x2000000); +} + +static inline void *__va(unsigned long x) +{ + if(x == 0) + return (void *)0; + + if(x < 0x2000000) + return (void *)(x+PAGE_OFFSET); + else + return (void *)(x-0x2000000); +} +#endif /* CONFIG_SUN3 */ + #define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) +#endif /* !__ASSEMBLY__ */ + +#ifndef CONFIG_SUN3 #define BUG() do { \ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ asm volatile("illegal"); \ } while (0) +#else +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + panic("BUG!"); \ +} while (0) +#endif #define PAGE_BUG(page) do { \ BUG(); \ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/param.h linux/include/asm-m68k/param.h --- v2.3.16/linux/include/asm-m68k/param.h Wed Dec 27 12:47:20 1995 +++ linux/include/asm-m68k/param.h Sat Sep 4 13:06:41 1999 @@ -5,7 +5,11 @@ #define HZ 100 #endif +#ifndef CONFIG_SUN3 #define EXEC_PAGESIZE 4096 +#else +#define EXEC_PAGESIZE 8192 +#endif #ifndef NGROUPS #define NGROUPS 32 diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h --- v2.3.16/linux/include/asm-m68k/pgtable.h Thu Aug 26 13:05:41 1999 +++ linux/include/asm-m68k/pgtable.h Sat Sep 4 13:06:41 1999 @@ -300,6 +300,14 @@ #define _PAGE_CACHE040 0x020 /* 68040 cache mode, cachable, copyback */ #define _PAGE_CACHE040W 0x000 /* 68040 cache mode, cachable, write-through */ +/* Page protection values within PTE. */ +#define SUN3_PAGE_VALID (0x80000000) +#define SUN3_PAGE_WRITEABLE (0x40000000) +#define SUN3_PAGE_SYSTEM (0x20000000) +#define SUN3_PAGE_NOCACHE (0x10000000) +#define SUN3_PAGE_ACCESSED (0x02000000) +#define SUN3_PAGE_MODIFIED (0x01000000) + #define _DESCTYPE_MASK 0x003 #define _CACHEMASK040 (~0x060) diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h --- v2.3.16/linux/include/asm-m68k/processor.h Mon Aug 9 12:27:31 1999 +++ linux/include/asm-m68k/processor.h Sat Sep 4 13:06:41 1999 @@ -32,12 +32,24 @@ * User space process size: 3.75GB. This is hardcoded into a few places, * so don't change it unless you know what you are doing. */ +#ifndef CONFIG_SUN3 #define TASK_SIZE (0xF0000000UL) +#else +#ifdef __ASSEMBLY__ +#define TASK_SIZE (0x0E000000) +#else +#define TASK_SIZE (0x0E000000UL) +#endif +#endif /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ +#ifndef CONFIG_SUN3 #define TASK_UNMAPPED_BASE 0xC0000000UL +#else +#define TASK_UNMAPPED_BASE 0x0A000000UL +#endif #define TASK_UNMAPPED_ALIGN(addr, off) PAGE_ALIGN(addr) /* diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/sbus.h linux/include/asm-m68k/sbus.h --- v2.3.16/linux/include/asm-m68k/sbus.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/sbus.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,20 @@ +/* + * some sbus structures and macros to make usage of sbus drivers possible + */ + +#ifndef __M68K_SBUS_H +#define __M68K_SBUS_H + +struct linux_sbus_device { + struct { + unsigned int which_io; + unsigned int phys_addr; + } reg_addrs[1]; +}; + +extern void *sparc_alloc_io (u32, void *, int, char *, u32, int); +#define sparc_alloc_io(a,b,c,d,e,f) (a) + +#define ARCH_SUN4 0 + +#endif diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/setup.h linux/include/asm-m68k/setup.h --- v2.3.16/linux/include/asm-m68k/setup.h Sun Aug 15 11:47:29 1999 +++ linux/include/asm-m68k/setup.h Sat Sep 4 13:06:41 1999 @@ -88,7 +88,9 @@ #endif #if defined(CONFIG_SUN3) -# error Currently no Sun-3 support! +#define MACH_IS_SUN3 (1) +#define MACH_SUN3_ONLY (1) +#define MACH_TYPE (MACH_SUN3) #else #define MACH_IS_SUN3 (0) #endif @@ -243,7 +245,7 @@ #ifndef __ASSEMBLY__ extern unsigned long m68k_cputype; extern unsigned long m68k_fputype; -extern unsigned long m68k_mmutype; /* Not really used yet */ +extern unsigned long m68k_mmutype; /* Not really used yet */ /* * m68k_is040or060 is != 0 for a '040 or higher; @@ -255,38 +257,58 @@ #if !defined(CONFIG_M68020) # define CPU_IS_020 (0) +# define MMU_IS_851 (0) +# define MMU_IS_SUN3 (0) #elif defined(CONFIG_M68030) || defined(CONFIG_M68040) || defined(CONFIG_M68060) # define CPU_IS_020 (m68k_cputype & CPU_68020) +# define MMU_IS_851 (m68k_cputype & MMU_68851) +# define MMU_IS_SUN3 (0) /* Sun3 not supported with other CPU enabled */ #else # define CPU_M68020_ONLY # define CPU_IS_020 (1) +#ifdef MACH_SUN3_ONLY +# define MMU_IS_SUN3 (1) +# define MMU_IS_851 (0) +#else +# define MMU_IS_SUN3 (0) +# define MMU_IS_851 (1) +#endif #endif #if !defined(CONFIG_M68030) # define CPU_IS_030 (0) +# define MMU_IS_030 (0) #elif defined(CONFIG_M68020) || defined(CONFIG_M68040) || defined(CONFIG_M68060) # define CPU_IS_030 (m68k_cputype & CPU_68030) +# define MMU_IS_030 (m68k_mmutype & MMU_68030) #else # define CPU_M68030_ONLY # define CPU_IS_030 (1) +# define MMU_IS_030 (1) #endif #if !defined(CONFIG_M68040) # define CPU_IS_040 (0) +# define MMU_IS_040 (0) #elif defined(CONFIG_M68020) || defined(CONFIG_M68030) || defined(CONFIG_M68060) # define CPU_IS_040 (m68k_cputype & CPU_68040) +# define MMU_IS_040 (m68k_mmutype & MMU_68040) #else # define CPU_M68040_ONLY # define CPU_IS_040 (1) +# define MMU_IS_040 (1) #endif #if !defined(CONFIG_M68060) # define CPU_IS_060 (0) +# define MMU_IS_060 (0) #elif defined(CONFIG_M68020) || defined(CONFIG_M68030) || defined(CONFIG_M68040) # define CPU_IS_060 (m68k_cputype & CPU_68060) +# define MMU_IS_060 (m68k_mmutype & MMU_68060) #else # define CPU_M68060_ONLY # define CPU_IS_060 (1) +# define MMU_IS_060 (1) #endif #if !defined(CONFIG_M68020) && !defined(CONFIG_M68030) diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/shm.h linux/include/asm-m68k/shm.h --- v2.3.16/linux/include/asm-m68k/shm.h Wed Dec 27 12:47:22 1995 +++ linux/include/asm-m68k/shm.h Sat Sep 4 13:06:41 1999 @@ -12,8 +12,14 @@ bit 31 (SHM_READ_ONLY) flag whether the page belongs to a read-only attach */ /* on the m68k both bits 0 and 1 must be zero */ +/* format on the sun3 is similar, but bits 30, 31 are set to zero and all + others are reduced by 2. --m */ +#ifndef CONFIG_SUN3 #define SHM_ID_SHIFT 9 +#else +#define SHM_ID_SHIFT 7 +#endif #define _SHM_ID_BITS 7 #define SHM_ID_MASK ((1<<_SHM_ID_BITS)-1) diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/shmparam.h linux/include/asm-m68k/shmparam.h --- v2.3.16/linux/include/asm-m68k/shmparam.h Sat Mar 30 04:11:42 1996 +++ linux/include/asm-m68k/shmparam.h Sat Sep 4 13:06:41 1999 @@ -2,8 +2,13 @@ #define _M68K_SHMPARAM_H /* address range for shared memory attaches if no address passed to shmat() */ +#ifndef CONFIG_SUN3 #define SHM_RANGE_START 0xC0000000 #define SHM_RANGE_END 0xD0000000 +#else +#define SHM_RANGE_START 0x0C000000 +#define SHM_RANGE_END 0x0D000000 +#endif /* * Format of a swap-entry for shared memory pages currently out in diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/sun3-head.h linux/include/asm-m68k/sun3-head.h --- v2.3.16/linux/include/asm-m68k/sun3-head.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/sun3-head.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,12 @@ +/* $Id: head.h,v 1.32 1996/12/04 00:12:48 ecd Exp $ */ +#ifndef __SUN3_HEAD_H +#define __SUN3_HEAD_H + +#define KERNBASE 0xE000000 /* First address the kernel will eventually be */ +#define LOAD_ADDR 0x4000 /* prom jumps to us here unless this is elf /boot */ +#define BI_START (KERNBASE + 0x3000) /* beginning of the bootinfo records */ +#define FC_CONTROL 3 +#define FC_SUPERD 5 +#define FC_CPU 7 + +#endif __SUN3_HEAD_H diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/sun3ints.h linux/include/asm-m68k/sun3ints.h --- v2.3.16/linux/include/asm-m68k/sun3ints.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/sun3ints.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,31 @@ +/* + * sun3ints.h -- Linux/Sun3 interrupt handling code definitions + * + * Erik Verbruggen (erik@bigmama.xtdnet.nl) + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#ifndef SUN3INTS_H +#define SUN3INTS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void sun3_enable_irq(unsigned int irq); +void sun3_disable_irq(unsigned int irq); +int sun3_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id + ); + +#endif /* SUN3INTS_H */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/sun3mmu.h linux/include/asm-m68k/sun3mmu.h --- v2.3.16/linux/include/asm-m68k/sun3mmu.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/sun3mmu.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,167 @@ +/* + * Definitions for Sun3 custom MMU. + */ +#include + +#ifndef __SUN3_MMU_H__ +#define __SUN3_MMU_H__ + +#define FC_CONTROL 3 + +/* MMU characteristics. */ +#define SUN3_SEGMAPS_PER_CONTEXT 2048 +#define SUN3_PMEGS_NUM 256 +#define SUN3_CONTEXTS_NUM 8 + +#define SUN3_PMEG_SIZE_BITS 17 +#define SUN3_PMEG_SIZE (1 << SUN3_PMEG_SIZE_BITS) +#define SUN3_PMEG_MASK (SUN3_PMEG_SIZE - 1) + +#define SUN3_PTE_SIZE_BITS 13 +#define SUN3_PTE_SIZE (1 << SUN3_PTE_SIZE_BITS) +#define SUN3_PTE_MASK (SUN3_PTE_SIZE - 1) + +#define SUN3_CONTROL_MASK (0x0FFFFFFC) +#define SUN3_INVALID_PMEG 255 +#define SUN3_INVALID_CONTEXT 255 + +#define AC_IDPROM 0x00000000 /* 34 ID PROM, R/O, byte, 32 bytes */ +#define AC_PAGEMAP 0x10000000 /* 3 Pagemap R/W, long */ +#define AC_SEGMAP 0x20000000 /* 3 Segment map, byte */ +#define AC_CONTEXT 0x30000000 /* 34c current mmu-context */ +#define AC_SENABLE 0x40000000 /* 34c system dvma/cache/reset enable reg*/ +#define AC_UDVMA_ENB 0x50000000 /* 34 Not used on Sun boards, byte */ +#define AC_BUS_ERROR 0x60000000 /* 34 Cleared on read, byte. */ +#define AC_SYNC_ERR 0x60000000 /* c fault type */ +#define AC_SYNC_VA 0x60000004 /* c fault virtual address */ +#define AC_ASYNC_ERR 0x60000008 /* c asynchronous fault type */ +#define AC_ASYNC_VA 0x6000000c /* c async fault virtual address */ +#define AC_LEDS 0x70000000 /* 34 Zero turns on LEDs, byte */ +#define AC_CACHETAGS 0x80000000 /* 34c direct access to the VAC tags */ +#define AC_CACHEDDATA 0x90000000 /* 3 c direct access to the VAC data */ +#define AC_UDVMA_MAP 0xD0000000 /* 4 Not used on Sun boards, byte */ +#define AC_VME_VECTOR 0xE0000000 /* 4 For non-Autovector VME, byte */ +#define AC_BOOT_SCC 0xF0000000 /* 34 bypass to access Zilog 8530. byte.*/ + +#define SUN3_PAGE_CHG_MASK (SUN3_PAGE_PGNUM_MASK \ + | SUN3_PAGE_ACCESSED | SUN3_PAGE_MODIFIED) + +/* Bus access type within PTE. */ +#define SUN3_PAGE_TYPE_MASK (0x0c000000) +#define SUN3_PAGE_TYPE_MEMORY (0x00000000) +#define SUN3_PAGE_TYPE_IO (0x04000000) +#define SUN3_PAGE_TYPE_VME16 (0x08000000) +#define SUN3_PAGE_TYPE_VME32 (0x0c000000) + +/* Mask for page number within PTE. */ +#define SUN3_PAGE_PGNUM_MASK (0x0007FFFF) + +/* Bits within bus-error register. */ +#define SUN3_BUSERR_WATCHDOG (0x01) +#define SUN3_BUSERR_unused (0x02) +#define SUN3_BUSERR_FPAENERR (0x04) +#define SUN3_BUSERR_FPABERR (0x08) +#define SUN3_BUSERR_VMEBERR (0x10) +#define SUN3_BUSERR_TIMEOUT (0x20) +#define SUN3_BUSERR_PROTERR (0x40) +#define SUN3_BUSERR_INVALID (0x80) + +#ifndef __ASSEMBLY__ + +/* Read bus error status register (implicitly clearing it). */ +extern __inline__ unsigned char sun3_get_buserr (void) +{ + unsigned char sfc, c; + + GET_SFC (sfc); + SET_SFC (FC_CONTROL); + GET_CONTROL_BYTE (AC_BUS_ERROR, c); + SET_SFC (sfc); + + return c; +} + +/* Read segmap from hardware MMU. */ +extern __inline__ unsigned long sun3_get_segmap (unsigned long addr) +{ + register unsigned long entry; + unsigned char c, sfc; + + GET_SFC (sfc); + SET_SFC (FC_CONTROL); + GET_CONTROL_BYTE (AC_SEGMAP | (addr & SUN3_CONTROL_MASK), c); + SET_SFC (sfc); + entry = c; + + return entry; +} + +/* Write segmap to hardware MMU. */ +extern __inline__ void sun3_put_segmap (unsigned long addr, unsigned long entry) +{ + unsigned char sfc; + + GET_DFC (sfc); + SET_DFC (FC_CONTROL); + SET_CONTROL_BYTE (AC_SEGMAP | (addr & SUN3_CONTROL_MASK), entry); + SET_DFC (sfc); + + return; +} + +/* Read PTE from hardware MMU. */ +extern __inline__ unsigned long sun3_get_pte (unsigned long addr) +{ + register unsigned long entry; + unsigned char sfc; + + GET_SFC (sfc); + SET_SFC (FC_CONTROL); + GET_CONTROL_WORD (AC_PAGEMAP | (addr & SUN3_CONTROL_MASK), entry); + SET_SFC (sfc); + + return entry; +} + +/* Write PTE to hardware MMU. */ +extern __inline__ void sun3_put_pte (unsigned long addr, unsigned long entry) +{ + unsigned char sfc; + + GET_DFC (sfc); + SET_DFC (FC_CONTROL); + SET_CONTROL_WORD (AC_PAGEMAP | (addr & SUN3_CONTROL_MASK), entry); + SET_DFC (sfc); + + return; +} + +/* get current context */ +extern __inline__ unsigned char sun3_get_context(void) +{ + unsigned char sfc, c; + + GET_SFC(sfc); + SET_SFC(FC_CONTROL); + GET_CONTROL_BYTE(AC_CONTEXT, c); + SET_SFC(sfc); + + return c; +} + +/* set alternate context */ +extern __inline__ void sun3_put_context(unsigned char c) +{ + unsigned char dfc; + GET_DFC(dfc); + SET_DFC(FC_CONTROL); + SET_CONTROL_BYTE(AC_CONTEXT, c); + SET_DFC(dfc); + + return; +} + + +#endif /* !__ASSEMBLY__ */ + +#endif /* !__SUN3_MMU_H__ */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/swim_iop.h linux/include/asm-m68k/swim_iop.h --- v2.3.16/linux/include/asm-m68k/swim_iop.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/swim_iop.h Sat Sep 4 13:06:41 1999 @@ -0,0 +1,221 @@ +/* + * SWIM access through the IOP + * Written by Joshua M. Thompson + */ + +/* IOP number and channel number for the SWIM */ + +#define SWIM_IOP IOP_NUM_ISM +#define SWIM_CHAN 1 + +/* Command code: */ + +#define CMD_INIT 0x01 /* Initialize */ +#define CMD_SHUTDOWN 0x02 /* Shutdown */ +#define CMD_START_POLL 0x03 /* Start insert/eject polling */ +#define CMD_STOP_POLL 0x04 /* Stop insert/eject polling */ +#define CMD_SETHFSTAG 0x05 /* Set HFS tag buffer address */ +#define CMD_STATUS 0x06 /* Status */ +#define CMD_EJECT 0x07 /* Eject */ +#define CMD_FORMAT 0x08 /* Format */ +#define CMD_FORMAT_VERIFY 0x09 /* Format and Verify */ +#define CMD_WRITE 0x0A /* Write */ +#define CMD_READ 0x0B /* Read */ +#define CMD_READ_VERIFY 0x0C /* Read and Verify */ +#define CMD_CACHE_CTRL 0x0D /* Cache control */ +#define CMD_TAGBUFF_CTRL 0x0E /* Tag buffer control */ +#define CMD_GET_ICON 0x0F /* Get Icon */ + +/* Drive types: */ + +/* note: apple sez DRV_FDHD is 4, but I get back a type */ +/* of 5 when I do a drive status check on my FDHD */ + +#define DRV_NONE 0 /* No drive */ +#define DRV_UNKNOWN 1 /* Unspecified drive */ +#define DRV_400K 2 /* 400K */ +#define DRV_800K 3 /* 400K/800K */ +#define DRV_FDHD 5 /* 400K/800K/720K/1440K */ +#define DRV_HD20 7 /* Apple HD20 */ + +/* Format types: */ + +#define FMT_HD20 0x0001 /* Apple HD20 */ +#define FMT_400K 0x0002 /* 400K (GCR) */ +#define FMT_800K 0x0004 /* 800K (GCR) */ +#define FMT_720K 0x0008 /* 720K (MFM) */ +#define FMT_1440K 0x0010 /* 1.44M (MFM) */ + +#define FMD_KIND_400K 1 +#define FMD_KIND_800K 2 +#define FMD_KIND_720K 3 +#define FMD_KIND_1440K 1 + +/* Icon Flags: */ + +#define ICON_MEDIA 0x01 /* Have IOP supply media icon */ +#define ICON_DRIVE 0x01 /* Have IOP supply drive icon */ + +/* Error codes: */ + +#define gcrOnMFMErr -400 /* GCR (400/800K) on HD media */ +#define verErr -84 /* verify failed */ +#define fmt2Err -83 /* cant get enough sync during format */ +#define fmt1Err -82 /* can't find sector 0 after track format */ +#define sectNFErr -81 /* can't find sector */ +#define seekErr -80 /* drive error during seek */ +#define spdAdjErr -79 /* can't set drive speed */ +#define twoSideErr -78 /* drive is single-sided */ +#define initIWMErr -77 /* error during initialization */ +#define tk0badErr -76 /* track zero is bad */ +#define cantStepErr -75 /* drive error during step */ +#define wrUnderrun -74 /* write underrun occurred */ +#define badDBtSlp -73 /* bad data bitslip marks */ +#define badDCksum -72 /* bad data checksum */ +#define noDtaMkErr -71 /* can't find data mark */ +#define badBtSlpErr -70 /* bad address bitslip marks */ +#define badCksmErr -69 /* bad address-mark checksum */ +#define dataVerErr -68 /* read-verify failed */ +#define noAdrMkErr -67 /* can't find an address mark */ +#define noNybErr -66 /* no nybbles? disk is probably degaussed */ +#define offLinErr -65 /* no disk in drive */ +#define noDriveErr -64 /* drive isn't connected */ +#define nsDrvErr -56 /* no such drive */ +#define paramErr -50 /* bad positioning information */ +#define wPrErr -44 /* write protected */ +#define openErr -23 /* already initialized */ + +#ifndef __ASSEMBLY__ + +struct swim_drvstatus { + __u16 curr_track; /* Current track number */ + __u8 write_prot; /* 0x80 if disk is write protected */ + __u8 disk_in_drive; /* 0x01 or 0x02 if a disk is in the drive */ + __u8 installed; /* 0x01 if drive installed, 0xFF if not */ + __u8 num_sides; /* 0x80 if two-sided format supported */ + __u8 two_sided; /* 0xff if two-sided format diskette */ + __u8 new_interface; /* 0x00 if old 400K drive, 0xFF if newer */ + __u16 errors; /* Disk error count */ + struct { /* 32 bits */ + __u16 reserved; + __u16 :4; + __u16 external:1; /* Drive is external */ + __u16 scsi:1; /* Drive is a SCSI drive */ + __u16 fixed:1; /* Drive has fixed media */ + __u16 secondary:1; /* Drive is secondary drive */ + __u8 type; /* Drive type */ + } info; + __u8 mfm_drive; /* 0xFF if this is an FDHD drive */ + __u8 mfm_disk; /* 0xFF if 720K/1440K (MFM) disk */ + __u8 mfm_format; /* 0x00 if 720K, 0xFF if 1440K */ + __u8 ctlr_type; /* 0x00 if IWM, 0xFF if SWIM */ + __u16 curr_format; /* Current format type */ + __u16 allowed_fmt; /* Allowed format types */ + __u32 num_blocks; /* Number of blocks on disk */ + __u8 icon_flags; /* Icon flags */ + __u8 unusued; +}; + +/* Commands issued from the host to the IOP: */ + +struct swimcmd_init { + __u8 code; /* CMD_INIT */ + __u8 unusued; + __u16 error; + __u8 drives[28]; /* drive type list */ +}; + +struct swimcmd_startpoll { + __u8 code; /* CMD_START_POLL */ + __u8 unusued; + __u16 error; +}; + +struct swimcmd_sethfstag { + __u8 code; /* CMD_SETHFSTAG */ + __u8 unusued; + __u16 error; + caddr_t tagbuf; /* HFS tag buffer address */ +}; + +struct swimcmd_status { + __u8 code; /* CMD_STATUS */ + __u8 drive_num; + __u16 error; + struct swim_drvstatus status; +}; + +struct swimcmd_eject { + __u8 code; /* CMD_EJECT */ + __u8 drive_num; + __u16 error; + struct swim_drvstatus status; +}; + +struct swimcmd_format { + __u8 code; /* CMD_FORMAT */ + __u8 drive_num; + __u16 error; + union { + struct { + __u16 fmt; /* format kind */ + __u8 hdrbyte; /* fmt byte for hdr (0=default) */ + __u8 interleave; /* interleave (0 = default) */ + caddr_t databuf; /* sector data buff (0=default */ + caddr_t tagbuf; /* tag data buffer (0=default) */ + } f; + struct swim_drvstatus status; + } p; +}; + +struct swimcmd_fmtverify { + __u8 code; /* CMD_FORMAT_VERIFY */ + __u8 drive_num; + __u16 error; +}; + +struct swimcmd_rw { + __u8 code; /* CMD_READ, CMD_WRITE or CMD_READ_VERIFY */ + __u8 drive_num; + __u16 error; + caddr_t buffer; /* R/W buffer address */ + __u32 first_block; /* Starting block */ + __u32 num_blocks; /* Number of blocks */ + __u8 tag[12]; /* tag data */ +}; + +struct swimcmd_cachectl { + __u8 code; /* CMD_CACHE_CTRL */ + __u8 unused; + __u16 error; + __u8 enable; /* Nonzero to enable cache */ + __u8 install; /* +1 = install, -1 = remove, 0 = neither */ +}; + +struct swimcmd_tagbufctl { + __u8 code; /* CMD_TAGBUFF_CTRL */ + __u8 unused; + __u16 error; + caddr_t buf; /* buffer address or 0 to disable */ +}; + +struct swimcmd_geticon { + __u8 code; /* CMD_GET_ICON */ + __u8 drive_num; + __u16 error; + caddr_t buffer; /* Nuffer address */ + __u16 kind; /* 0 = media icon, 1 = drive icon */ + __u16 unused; + __u16 max_bytes; /* maximum byte count */ +}; + +/* Messages from the SWIM IOP to the host CPU: */ + +struct swimmsg_status { + __u8 code; /* 1 = insert, 2 = eject, 3 = status changed */ + __u8 drive_num; + __u16 error; + struct swim_drvstatus status; +}; + +#endif /* __ASSEMBLY__ */ diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/virtconvert.h linux/include/asm-m68k/virtconvert.h --- v2.3.16/linux/include/asm-m68k/virtconvert.h Tue Jan 19 10:58:34 1999 +++ linux/include/asm-m68k/virtconvert.h Sat Sep 4 13:06:41 1999 @@ -17,9 +17,21 @@ /* * Change virtual addresses to physical addresses and vv. */ +#ifndef CONFIG_SUN3 extern unsigned long mm_vtop(unsigned long addr) __attribute__ ((const)); extern unsigned long mm_vtop_fallback (unsigned long) __attribute__ ((const)); extern unsigned long mm_ptov(unsigned long addr) __attribute__ ((const)); +#else +extern inline unsigned long mm_vtop(unsigned long vaddr) +{ + return __pa(vaddr); +} + +extern inline unsigned long mm_ptov(unsigned long paddr) +{ + return (unsigned long)__va(paddr); +} +#endif #ifdef CONFIG_SINGLE_MEMORY_CHUNK extern inline unsigned long virt_to_phys(volatile void * address) diff -u --recursive --new-file v2.3.16/linux/include/asm-mips/hardirq.h linux/include/asm-mips/hardirq.h --- v2.3.16/linux/include/asm-mips/hardirq.h Mon Jul 19 13:12:47 1999 +++ linux/include/asm-mips/hardirq.h Wed Sep 1 14:12:09 1999 @@ -9,7 +9,7 @@ #ifndef __ASM_MIPS_HARDIRQ_H #define __ASM_MIPS_HARDIRQ_H -#include +#include extern unsigned int local_irq_count[NR_CPUS]; diff -u --recursive --new-file v2.3.16/linux/include/asm-ppc/gemini_serial.h linux/include/asm-ppc/gemini_serial.h --- v2.3.16/linux/include/asm-ppc/gemini_serial.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-ppc/gemini_serial.h Wed Sep 1 15:34:01 1999 @@ -1,6 +1,7 @@ #ifndef __ASMPPC_GEMINI_SERIAL_H #define __ASMPPC_GEMINI_SERIAL_H +#include #include /* Rate for the 24.576 Mhz clock for the onboard serial chip */ diff -u --recursive --new-file v2.3.16/linux/include/asm-ppc/pmu.h linux/include/asm-ppc/pmu.h --- v2.3.16/linux/include/asm-ppc/pmu.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-ppc/pmu.h Wed Sep 1 15:34:01 1999 @@ -6,7 +6,6 @@ * Copyright (C) 1998 Paul Mackerras. */ -#include /* * PMU commands */ diff -u --recursive --new-file v2.3.16/linux/include/asm-sh/bugs.h linux/include/asm-sh/bugs.h --- v2.3.16/linux/include/asm-sh/bugs.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-sh/bugs.h Wed Sep 1 15:34:01 1999 @@ -12,7 +12,6 @@ * I don't know of any Super-H bugs yet. */ -#include #include __initfunc(static void check_bugs(void)) diff -u --recursive --new-file v2.3.16/linux/include/asm-sh/elf.h linux/include/asm-sh/elf.h --- v2.3.16/linux/include/asm-sh/elf.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-sh/elf.h Wed Sep 1 15:34:01 1999 @@ -5,6 +5,7 @@ * ELF register definitions.. */ +#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/include/asm-sparc/ap1000/apreg.h linux/include/asm-sparc/ap1000/apreg.h --- v2.3.16/linux/include/asm-sparc/ap1000/apreg.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/ap1000/apreg.h Wed Sep 1 14:12:09 1999 @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* * Macros for accessing I/O registers. diff -u --recursive --new-file v2.3.16/linux/include/asm-sparc/audioio.h linux/include/asm-sparc/audioio.h --- v2.3.16/linux/include/asm-sparc/audioio.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-sparc/audioio.h Wed Sep 1 15:34:01 1999 @@ -237,7 +237,6 @@ #ifdef __KERNEL__ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/include/asm-sparc64/audioio.h linux/include/asm-sparc64/audioio.h --- v2.3.16/linux/include/asm-sparc64/audioio.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-sparc64/audioio.h Wed Sep 1 15:34:02 1999 @@ -237,7 +237,6 @@ #ifdef __KERNEL__ -#include #include #include #include diff -u --recursive --new-file v2.3.16/linux/include/asm-sparc64/dma.h linux/include/asm-sparc64/dma.h --- v2.3.16/linux/include/asm-sparc64/dma.h Tue Aug 31 17:29:14 1999 +++ linux/include/asm-sparc64/dma.h Wed Sep 1 15:34:02 1999 @@ -7,6 +7,7 @@ #ifndef _ASM_SPARC64_DMA_H #define _ASM_SPARC64_DMA_H +#include #include #include diff -u --recursive --new-file v2.3.16/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h --- v2.3.16/linux/include/asm-sparc64/hardirq.h Mon Jul 19 13:12:47 1999 +++ linux/include/asm-sparc64/hardirq.h Wed Sep 1 14:12:09 1999 @@ -6,7 +6,7 @@ #ifndef __SPARC64_HARDIRQ_H #define __SPARC64_HARDIRQ_H -#include +#include #ifndef __SMP__ extern unsigned int local_irq_count; diff -u --recursive --new-file v2.3.16/linux/include/linux/blk.h linux/include/linux/blk.h --- v2.3.16/linux/include/linux/blk.h Tue Aug 31 17:29:14 1999 +++ linux/include/linux/blk.h Tue Sep 7 11:29:07 1999 @@ -57,6 +57,7 @@ extern int ddv_init(void); extern int z2_init(void); extern int swim3_init(void); +extern int swimiop_init(void); extern int amiga_floppy_init(void); extern int atari_floppy_init(void); extern int nbd_init(void); diff -u --recursive --new-file v2.3.16/linux/include/linux/cd1400.h linux/include/linux/cd1400.h --- v2.3.16/linux/include/linux/cd1400.h Wed Feb 4 14:52:16 1998 +++ linux/include/linux/cd1400.h Thu Sep 2 11:22:40 1999 @@ -4,7 +4,7 @@ * cd1400.h -- cd1400 UART hardware info. * * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). - * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). + * Copyright (C) 1994-1996 Greg Ungerer. * * 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 diff -u --recursive --new-file v2.3.16/linux/include/linux/cdk.h linux/include/linux/cdk.h --- v2.3.16/linux/include/linux/cdk.h Wed Feb 4 14:52:16 1998 +++ linux/include/linux/cdk.h Thu Sep 2 11:22:40 1999 @@ -4,7 +4,7 @@ * cdk.h -- CDK interface definitions. * * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). - * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). + * Copyright (C) 1994-1996 Greg Ungerer. * * 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 diff -u --recursive --new-file v2.3.16/linux/include/linux/comstats.h linux/include/linux/comstats.h --- v2.3.16/linux/include/linux/comstats.h Wed Feb 4 14:52:16 1998 +++ linux/include/linux/comstats.h Thu Sep 2 11:22:40 1999 @@ -4,7 +4,7 @@ * comstats.h -- Serial Port Stats. * * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). - * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). + * Copyright (C) 1994-1996 Greg Ungerer. * * 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 diff -u --recursive --new-file v2.3.16/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.3.16/linux/include/linux/fs.h Tue Aug 31 17:29:14 1999 +++ linux/include/linux/fs.h Tue Sep 7 11:28:52 1999 @@ -269,6 +269,7 @@ #include #include #include +#include /* * Attribute flags. These should be or-ed together to figure out what @@ -381,6 +382,7 @@ struct hfs_inode_info hfs_i; struct adfs_inode_info adfs_i; struct qnx4_inode_info qnx4_i; + struct udf_inode_info udf_i; struct socket socket_i; void *generic_ip; } u; @@ -510,6 +512,7 @@ #include #include #include +#include extern struct list_head super_blocks; @@ -554,6 +557,7 @@ struct hfs_sb_info hfs_sb; struct adfs_sb_info adfs_sb; struct qnx4_sb_info qnx4_sb; + struct udf_sb_info udf_sb; void *generic_sbp; } u; /* diff -u --recursive --new-file v2.3.16/linux/include/linux/i2o.h linux/include/linux/i2o.h --- v2.3.16/linux/include/linux/i2o.h Fri Aug 6 11:16:54 1999 +++ linux/include/linux/i2o.h Thu Sep 2 10:18:33 1999 @@ -169,7 +169,6 @@ char dev_name[8]; /* linux /dev name if available */ }; -#ifdef CONFIG_I2O_PCI_MODULE /* * Resource data for each PCI I2O controller */ @@ -177,7 +176,7 @@ { int irq; }; -#endif + /* * Each I2O controller has one of these objects diff -u --recursive --new-file v2.3.16/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v2.3.16/linux/include/linux/if_arp.h Thu Aug 26 13:05:41 1999 +++ linux/include/linux/if_arp.h Tue Sep 7 11:29:50 1999 @@ -67,7 +67,7 @@ #define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */ #define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */ #define ARPHRD_ECONET 782 /* Acorn Econet */ -#define ARPHRD_IRDA 783 /* Linux/IR */ +#define ARPHRD_IRDA 783 /* Linux-IrDA */ /* ARP works differently on different FC media .. so */ #define ARPHRD_FCPP 784 /* Point to point fibrechanel */ #define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */ diff -u --recursive --new-file v2.3.16/linux/include/linux/if_ether.h linux/include/linux/if_ether.h --- v2.3.16/linux/include/linux/if_ether.h Thu Aug 26 13:05:41 1999 +++ linux/include/linux/if_ether.h Tue Sep 7 10:14:37 1999 @@ -74,7 +74,7 @@ #define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ #define ETH_P_CONTROL 0x0016 /* Card specific control frames */ -#define ETH_P_IRDA 0x0017 /* Linux/IR */ +#define ETH_P_IRDA 0x0017 /* Linux-IrDA */ #define ETH_P_ECONET 0x0018 /* Acorn Econet */ /* diff -u --recursive --new-file v2.3.16/linux/include/linux/ioport.h linux/include/linux/ioport.h --- v2.3.16/linux/include/linux/ioport.h Thu Aug 26 13:05:41 1999 +++ linux/include/linux/ioport.h Fri Sep 3 13:17:15 1999 @@ -87,11 +87,16 @@ /* Convenience shorthand with allocation */ #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) +#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name)) + extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name); /* Compatibility cruft */ #define check_region(start,n) __check_region(&ioport_resource, (start), (n)) #define release_region(start,n) __release_region(&ioport_resource, (start), (n)) +#define check_mem_region(start,n) __check_region(&iomem_resource, (start), (n)) +#define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n)) + extern int __check_region(struct resource *, unsigned long, unsigned long); extern void __release_region(struct resource *, unsigned long, unsigned long); diff -u --recursive --new-file v2.3.16/linux/include/linux/istallion.h linux/include/linux/istallion.h --- v2.3.16/linux/include/linux/istallion.h Sat May 15 15:05:37 1999 +++ linux/include/linux/istallion.h Thu Sep 2 11:22:40 1999 @@ -4,7 +4,7 @@ * istallion.h -- stallion intelligent multiport serial driver. * * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). - * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). + * Copyright (C) 1994-1996 Greg Ungerer. * * 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 @@ -70,9 +70,15 @@ long pgrp; unsigned int rxmarkmsk; struct tty_struct *tty; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + struct wait_queue *open_wait; + struct wait_queue *close_wait; + struct wait_queue *raw_wait; +#else wait_queue_head_t open_wait; wait_queue_head_t close_wait; wait_queue_head_t raw_wait; +#endif struct tq_struct tqhangup; struct termios normaltermios; struct termios callouttermios; diff -u --recursive --new-file v2.3.16/linux/include/linux/kernel.h linux/include/linux/kernel.h --- v2.3.16/linux/include/linux/kernel.h Tue Aug 31 17:29:14 1999 +++ linux/include/linux/kernel.h Tue Sep 7 10:14:37 1999 @@ -91,11 +91,12 @@ unsigned long freeram; /* Available memory size */ unsigned long sharedram; /* Amount of shared memory */ unsigned long bufferram; /* Memory used by buffers */ - unsigned long totalbig; /* Total big memory size */ - unsigned long freebig; /* Available big memory size */ unsigned long totalswap; /* Total swap space size */ unsigned long freeswap; /* swap space still available */ unsigned short procs; /* Number of current processes */ + unsigned long totalbig; /* Total big memory size */ + unsigned long freebig; /* Available big memory size */ + char _f[22-2*sizeof(long)]; /* Padding: libc5 uses this.. */ }; #endif diff -u --recursive --new-file v2.3.16/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.3.16/linux/include/linux/mm.h Tue Aug 31 17:29:14 1999 +++ linux/include/linux/mm.h Tue Sep 7 11:28:52 1999 @@ -57,7 +57,7 @@ struct vm_operations_struct * vm_ops; unsigned long vm_offset; struct file * vm_file; - unsigned long vm_pte; /* shared mem */ + void * vm_private_data; /* was vm_pte (shared mem) */ }; /* diff -u --recursive --new-file v2.3.16/linux/include/linux/nubus.h linux/include/linux/nubus.h --- v2.3.16/linux/include/linux/nubus.h Sat Mar 21 11:06:51 1998 +++ linux/include/linux/nubus.h Sat Sep 4 13:10:30 1999 @@ -1,96 +1,322 @@ +/* + nubus.h: various definitions and prototypes for NuBus drivers to use. -struct nubus_slot -{ - int slot_flags; -#define NUBUS_DEVICE_PRESENT 1 -#define NUBUS_DEVICE_ACTIVE 2 -#define NUBUS_DEVICE_IRQ 4 - __u32 slot_directory; - __u32 slot_dlength; - __u32 slot_crc; - __u8 slot_rev; - __u8 slot_format; - __u8 slot_lanes; - /* - * Stuff we pulled from the directory - */ - __u32 slot_dirbase; - __u32 slot_thisdir; - char slot_vendor[64]; - char slot_cardname[64]; + Originally written by Alan Cox. + + Hacked to death by C. Scott Ananian and David Huggins-Daines. + + Some of the constants in here are from the corresponding + NetBSD/OpenBSD header file, by Allen Briggs. We figured out the + rest of them on our own. */ + +#ifndef LINUX_NUBUS_H +#define LINUX_NUBUS_H + +enum nubus_category { + NUBUS_CAT_BOARD = 0x0001, + NUBUS_CAT_DISPLAY = 0x0003, + NUBUS_CAT_NETWORK = 0x0004, + NUBUS_CAT_COMMUNICATIONS = 0x0006, + NUBUS_CAT_FONT = 0x0009, + NUBUS_CAT_CPU = 0x000A, + /* For lack of a better name */ + NUBUS_CAT_DUODOCK = 0x0020 }; -struct nbnamevec -{ - char *name; - int id; +enum nubus_type_network { + NUBUS_TYPE_ETHERNET = 0x0001, + NUBUS_TYPE_RS232 = 0x0002 +}; + +enum nubus_type_display { + NUBUS_TYPE_VIDEO = 0x0001 +}; + +enum nubus_type_cpu { + NUBUS_TYPE_68020 = 0x0003, + NUBUS_TYPE_68030 = 0x0004, + NUBUS_TYPE_68040 = 0x0005 +}; + +/* Known tuples: (according to TattleTech and Slots) + * 68030 motherboards: <10,4,0,24> + * 68040 motherboards: <10,5,0,24> + * DuoDock Plus: <32,1,1,2> + * + * Toby Frame Buffer card: <3,1,1,1> + * RBV built-in video (IIci): <3,1,1,24> + * Valkyrie built-in video (Q630): <3,1,1,46> + * Macintosh Display Card: <3,1,1,25> + * Sonora built-in video (P460): <3,1,1,34> + * Jet framebuffer (DuoDock Plus): <3,1,1,41> + * + * SONIC comm-slot/on-board and DuoDock Ethernet: <4,1,1,272> + * SONIC LC-PDS Ethernet (Dayna, but like Apple 16-bit, sort of): <4,1,1,271> + * Sonic Systems Ethernet A-Series Card: <4,1,268,256> + * Asante MacCon NuBus-A: <4,1,260,256> (alpha-1.0,1.1 revision) + * ROM on the above card: <2,1,0,0> + * Cabletron ethernet card: <4,1,1,265> + * Farallon ethernet card: <4,1,268,256> (identical to Sonic Systems card) + * Kinetics EtherPort IIN: <4,1,259,262> + * API Engineering EtherRun_LCa PDS enet card: <4,1,282,256> + * + * Add your devices to the list! You can obtain the "Slots" utility + * from Apple's FTP site at: + * ftp://dev.apple.com/devworld/Tool_Chest/Devices_-_Hardware/NuBus_Slot_Manager/ + * + * Alternately, TattleTech can be found at any Info-Mac mirror site. + * or from its distribution site: ftp://ftp.decismkr.com/dms + */ + +/* DrSW: Uniquely identifies the software interface to a board. This + is usually the one you want to look at when writing a driver. It's + not as useful as you think, though, because as we should know by + now (duh), "Apple Compatible" can mean a lot of things... */ + +/* Add known DrSW values here */ +enum nubus_drsw { + /* NUBUS_CAT_DISPLAY */ + NUBUS_DRSW_APPLE = 0x0001, + NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */ + + /* NUBUS_CAT_NETWORK */ + NUBUS_DRSW_CABLETRON = 0x0001, + NUBUS_DRSW_SONIC_LC = 0x0001, + NUBUS_DRSW_KINETICS = 0x0103, + NUBUS_DRSW_ASANTE = 0x0104, + NUBUS_DRSW_DAYNA = 0x010b, + NUBUS_DRSW_FARALLON = 0x010c, + NUBUS_DRSW_APPLE_SN = 0x010f, + NUBUS_DRSW_FOCUS = 0x011a, + NUBUS_DRSW_ASANTE_CS = 0x011d, /* use asante SMC9194 driver */ + + /* NUBUS_CAT_CPU */ + NUBUS_DRSW_NONE = 0x0000, +}; + +/* DrHW: Uniquely identifies the hardware interface to a board (or at + least, it should... some video cards are known to incorrectly + identify themselves as Toby cards) */ + +/* Add known DrHW values here */ +enum nubus_drhw { + /* NUBUS_CAT_DISPLAY */ + NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */ + NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */ + NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */ + NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */ + NUBUS_DRHW_APPLE_VALKYRIE = 0x002e, + NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */ + + /* NUBUS_CAT_NETWORK */ + NUBUS_DRHW_INTERLAN = 0x0100, + NUBUS_DRHW_SMC9194 = 0x0101, + NUBUS_DRHW_KINETICS = 0x0106, + NUBUS_DRHW_CABLETRON = 0x0109, + NUBUS_DRHW_ASANTE_LC = 0x010f, + NUBUS_DRHW_SONIC = 0x0110, +}; + +/* Resource IDs: These are the identifiers for the various weird and + wonderful tidbits of information that may or may not reside in the + NuBus ROM directory. */ +enum nubus_res_id { + NUBUS_RESID_TYPE = 0x0001, + NUBUS_RESID_NAME = 0x0002, + NUBUS_RESID_ICON = 0x0003, + NUBUS_RESID_DRVRDIR = 0x0004, + NUBUS_RESID_LOADREC = 0x0005, + NUBUS_RESID_BOOTREC = 0x0006, + NUBUS_RESID_FLAGS = 0x0007, + NUBUS_RESID_HWDEVID = 0x0008, + NUBUS_RESID_MINOR_BASEOS = 0x000a, + NUBUS_RESID_MINOR_LENGTH = 0x000b, + NUBUS_RESID_MAJOR_BASEOS = 0x000c, + NUBUS_RESID_MAJOR_LENGTH = 0x000d, + NUBUS_RESID_CICN = 0x000f, + NUBUS_RESID_ICL8 = 0x0010, + NUBUS_RESID_ICL4 = 0x0011, +}; + +/* Category-specific resources. */ +enum nubus_board_res_id { + NUBUS_RESID_BOARDID = 0x0020, + NUBUS_RESID_PRAMINITDATA = 0x0021, + NUBUS_RESID_PRIMARYINIT = 0x0022, + NUBUS_RESID_TIMEOUTCONST = 0x0023, + NUBUS_RESID_VENDORINFO = 0x0024, + NUBUS_RESID_BOARDFLAGS = 0x0025, + NUBUS_RESID_SECONDINIT = 0x0026, + + /* Not sure why Apple put these next two in here */ + NUBUS_RESID_VIDNAMES = 0x0041, + NUBUS_RESID_VIDMODES = 0x007e +}; + +/* Fields within the vendor info directory */ +enum nubus_vendor_res_id { + NUBUS_RESID_VEND_ID = 0x0001, + NUBUS_RESID_VEND_SERIAL = 0x0002, + NUBUS_RESID_VEND_REV = 0x0003, + NUBUS_RESID_VEND_PART = 0x0004, + NUBUS_RESID_VEND_DATE = 0x0005 +}; + +enum nubus_net_res_id { + NUBUS_RESID_MAC_ADDRESS = 0x0080 +}; + +enum nubus_cpu_res_id { + NUBUS_RESID_MEMINFO = 0x0081, + NUBUS_RESID_ROMINFO = 0x0082 +}; + +enum nubus_display_res_id { + NUBUS_RESID_GAMMADIR = 0x0040, + NUBUS_RESID_FIRSTMODE = 0x0080, + NUBUS_RESID_SECONDMODE = 0x0081, + NUBUS_RESID_THIRDMODE = 0x0082, + NUBUS_RESID_FOURTHMODE = 0x0083, + NUBUS_RESID_FIFTHMODE = 0x0084, + NUBUS_RESID_SIXTHMODE = 0x0085 }; struct nubus_dir { unsigned char *base; - int length; - int count; + unsigned char *ptr; + int done; int mask; }; struct nubus_dirent { + unsigned char *base; unsigned char type; - int value; /* Actually 24bits used */ + __u32 data; /* Actually 24bits used */ int mask; - int base; /* For dirptr function */ }; -struct nubus_type -{ - __u16 category; - __u16 type; - __u16 DrHW; - __u16 DrSW; -}; - -#define NUBUS_CAT_BOARD 0x0001 -#define NUBUS_CAT_DISPLAY 0x0003 -#define NUBUS_CAT_NETWORK 0x0004 -#define NUBUS_CAT_COMMUNICATIONS 0x0006 -#define NUBUS_CAT_FONT 0x0009 -#define NUBUS_CAT_CPU 0x000A - -#define RES_ID_TYPE 0x0001 -#define RES_ID_NAME 0x0002 -#define RES_ID_BOARD_DIR 0x0001 -#define RES_ID_FLAGS 0x0007 - -struct nubus_device_specifier -{ - int (*setup)(struct nubus_device_specifier *, int slot, struct nubus_type *); - struct nubus_device_specifier *next; +struct nubus_board { + struct nubus_board* next; + struct nubus_dev* first_dev; + + /* Only 9-E actually exist, though 0-8 are also theoretically + possible, and 0 is a special case which represents the + motherboard and onboard peripherals (Ethernet, video) */ + int slot; + /* For slot 0, this is bogus. */ + char name[64]; + + /* Format block */ + unsigned char* fblock; + /* Root directory (does *not* always equal fblock + doffset!) */ + unsigned char* directory; + + unsigned long slot_addr; + /* Offset to root directory (sometimes) */ + unsigned long doffset; + /* Length over which to compute the crc */ + unsigned long rom_length; + /* Completely useless most of the time */ + unsigned long crc; + unsigned char rev; + unsigned char format; + unsigned char lanes; }; +struct nubus_dev { + /* Next link in device list */ + struct nubus_dev* next; + /* Directory entry in /proc/bus/nubus */ + struct proc_dir_entry* procdir; + + /* The functional resource ID of this device */ + unsigned char resid; + /* These are mostly here for convenience; we could always read + them from the ROMs if we wanted to */ + unsigned short category; + unsigned short type; + unsigned short dr_sw; + unsigned short dr_hw; + /* This is the device's name rather than the board's. + Sometimes they are different. Usually the board name is + more correct. */ + char name[64]; + /* MacOS driver (I kid you not) */ + unsigned char* driver; + /* Actually this is an offset */ + unsigned long iobase; + unsigned long iosize; + unsigned char flags, hwdevid; + + /* Functional directory */ + unsigned char* directory; + /* Much of our info comes from here */ + struct nubus_board* board; +}; -extern void register_nubus_device(struct nubus_device_specifier *nb); -extern void unregister_nubus_device(struct nubus_device_specifier *nb); +/* This is all NuBus devices (used to find devices later on) */ +extern struct nubus_dev* nubus_devices; +/* This is all NuBus cards */ +extern struct nubus_board* nubus_boards; -extern struct nubus_dir *nubus_openrootdir(int slot); -extern struct nubus_dir *nubus_opensubdir(struct nubus_dirent *d); -extern void nubus_closedir(struct nubus_dir *); -extern struct nubus_dirent *nubus_readdir(struct nubus_dir *); -extern unsigned char *nubus_dirptr(struct nubus_dirent *d); -extern void nubus_strncpy(int slot, void *to, unsigned char *p, int len); -extern void nubus_memcpy(int slot, void *to, unsigned char *p, int len); +/* Generic NuBus interface functions, modelled after the PCI interface */ extern void nubus_init(void); -extern void nubus_sweep_video(void); -extern int nubus_ethernet_addr(int slot, unsigned char *addr); +void nubus_scan_bus(void); +extern void nubus_proc_init(void); +int get_nubus_list(char *buf); +int nubus_proc_attach_device(struct nubus_dev *dev); +int nubus_proc_detach_device(struct nubus_dev *dev); +/* If we need more precision we can add some more of these */ +struct nubus_dev* nubus_find_device(unsigned short category, + unsigned short type, + unsigned short dr_hw, + unsigned short dr_sw, + const struct nubus_dev* from); +struct nubus_dev* nubus_find_type(unsigned short category, + unsigned short type, + const struct nubus_dev* from); +/* Might have more than one device in a slot, you know... */ +struct nubus_dev* nubus_find_slot(unsigned int slot, + const struct nubus_dev* from); + +/* These are somewhat more NuBus-specific. They all return 0 for + success and -1 for failure, as you'd expect. */ + +/* The root directory which contains the board and functional + directories */ +int nubus_get_root_dir(const struct nubus_board* board, + struct nubus_dir* dir); +/* The board directory */ +int nubus_get_board_dir(const struct nubus_board* board, + struct nubus_dir* dir); +/* The functional directory */ +int nubus_get_func_dir(const struct nubus_dev* dev, + struct nubus_dir* dir); + +/* These work on any directory gotten via the above */ +int nubus_readdir(struct nubus_dir* dir, + struct nubus_dirent* ent); +int nubus_find_rsrc(struct nubus_dir* dir, + unsigned char rsrc_type, + struct nubus_dirent* ent); +int nubus_rewinddir(struct nubus_dir* dir); + +/* Things to do with directory entries */ +int nubus_get_subdir(const struct nubus_dirent* ent, + struct nubus_dir* dir); +void nubus_get_rsrc_mem(void* dest, + const struct nubus_dirent *dirent, + int len); +void nubus_get_rsrc_str(void* dest, + const struct nubus_dirent *dirent, + int maxlen); -extern __inline void *nubus_slot_addr(int slot) +/* We'd like to get rid of this eventually. Only daynaport.c uses it now. */ +extern inline void *nubus_slot_addr(int slot) { return (void *)(0xF0000000|(slot<<24)); } -extern int nubus_hwreg_present(volatile void *ptr); - -extern void nubus_init_via(void); -extern int nubus_free_irq(int slot); -extern int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct pt_regs *)); - +#endif LINUX_NUBUS_H diff -u --recursive --new-file v2.3.16/linux/include/linux/pagemap.h linux/include/linux/pagemap.h --- v2.3.16/linux/include/linux/pagemap.h Wed Aug 18 16:43:44 1999 +++ linux/include/linux/pagemap.h Tue Sep 7 11:28:53 1999 @@ -108,6 +108,4 @@ ___wait_on_page(page); } -extern void update_vm_cache(struct inode *, unsigned long, const char *, int); - #endif diff -u --recursive --new-file v2.3.16/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.3.16/linux/include/linux/pci.h Tue Aug 31 17:29:14 1999 +++ linux/include/linux/pci.h Tue Sep 7 11:28:52 1999 @@ -654,6 +654,12 @@ #define PCI_DEVICE_ID_MYLEX_DAC960P_V4 0x0010 #define PCI_DEVICE_ID_MYLEX_DAC960P_V5 0x0020 +#define PCI_VENDOR_ID_MYLEX 0x1069 +#define PCI_DEVICE_ID_MYLEX_DAC960P_V2 0x0001 +#define PCI_DEVICE_ID_MYLEX_DAC960P_V3 0x0002 +#define PCI_DEVICE_ID_MYLEX_DAC960P_V4 0x0010 +#define PCI_DEVICE_ID_MYLEX_DAC960P_V5 0x0020 + #define PCI_VENDOR_ID_PICOP 0x1066 #define PCI_DEVICE_ID_PICOP_PT86C52X 0x0001 #define PCI_DEVICE_ID_PICOP_PT80C524 0x8002 @@ -1341,6 +1347,10 @@ #define PCI_DEVICE_ID_INTERPHASE_5526 0x0004 #define PCI_DEVICE_ID_INTERPHASE_55x6 0x0005 +#define PCI_VENDOR_ID_INTERPHASE 0x107e +#define PCI_DEVICE_ID_INTERPHASE_5526 0x0004 +#define PCI_DEVICE_ID_INTERPHASE_55x6 0x0005 + /* * The PCI interface treats multi-function devices as independent * devices. The slot/function address of each device is encoded @@ -1478,7 +1488,9 @@ void pcibios_init(void); void pcibios_fixup_bus(struct pci_bus *); char *pcibios_setup (char *str); -int pcibios_assign_resource(struct pci_dev *, int i); +void pcibios_update_resource(struct pci_dev *, struct resource *, + struct resource *, int); +void pcibios_update_irq(struct pci_dev *, int irq); /* Backward compatibility, don't use in new code! */ @@ -1519,6 +1531,12 @@ struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from); struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); + +int pci_claim_resource(struct pci_dev *, int); +void pci_assign_unassigned_resources(u32 min_io, u32 min_mem); +void pci_set_bus_ranges(void); +void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *), + int (*)(struct pci_dev *, u8, u8)); #define PCI_ANY_ID (~0) diff -u --recursive --new-file v2.3.16/linux/include/linux/personality.h linux/include/linux/personality.h --- v2.3.16/linux/include/linux/personality.h Thu Aug 26 13:05:41 1999 +++ linux/include/linux/personality.h Sat Sep 4 13:06:08 1999 @@ -28,9 +28,10 @@ #define PER_IRIXN32 (0x000a | STICKY_TIMEOUTS) /* IRIX6 new 32-bit */ #define PER_IRIX64 (0x000b | STICKY_TIMEOUTS) /* IRIX6 64-bit */ #define PER_RISCOS (0x000c) +#define PER_SOLARIS (0x000d | STICKY_TIMEOUTS) /* Prototype for an lcall7 syscall handler. */ -typedef void (*lcall7_func)(struct pt_regs *); +typedef void (*lcall7_func)(int, struct pt_regs *); /* Description of an execution domain - personality range supported, diff -u --recursive --new-file v2.3.16/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v2.3.16/linux/include/linux/proc_fs.h Thu Aug 26 13:05:41 1999 +++ linux/include/linux/proc_fs.h Tue Sep 7 11:28:53 1999 @@ -23,6 +23,7 @@ PROC_PCI, PROC_MCA, PROC_NUBUS, + PROC_MAC_VIA, PROC_SELF, /* will change inode # */ PROC_NET, PROC_SCSI, @@ -234,6 +235,8 @@ PROC_BUS_ZORRO, PROC_BUS_ZORRO_DEVICES, PROC_BUS_ECARD_DEVICES, + PROC_BUS_NUBUS, + PROC_BUS_NUBUS_DEVICES, PROC_BUS_LAST }; diff -u --recursive --new-file v2.3.16/linux/include/linux/serialP.h linux/include/linux/serialP.h --- v2.3.16/linux/include/linux/serialP.h Tue Aug 31 17:29:15 1999 +++ linux/include/linux/serialP.h Tue Sep 7 11:28:52 1999 @@ -19,6 +19,7 @@ * For definitions of the flags field, see tty.h */ +#include #include #include #include @@ -146,6 +147,7 @@ #define ALPHA_KLUDGE_MCR 0 #endif +#ifdef CONFIG_PCI /* * Structures and definitions for PCI support */ @@ -170,6 +172,7 @@ #ifndef PCI_ANY_ID #define PCI_ANY_ID (~0) +#endif #endif #define SPCI_FL_BASE_MASK 0x0007 diff -u --recursive --new-file v2.3.16/linux/include/linux/stallion.h linux/include/linux/stallion.h --- v2.3.16/linux/include/linux/stallion.h Sat May 15 15:05:37 1999 +++ linux/include/linux/stallion.h Thu Sep 2 11:22:40 1999 @@ -4,7 +4,7 @@ * stallion.h -- stallion multiport serial driver. * * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). - * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). + * Copyright (C) 1994-1996 Greg Ungerer. * * 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 @@ -95,8 +95,13 @@ unsigned long hwid; void *uartp; struct tty_struct *tty; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + struct wait_queue *open_wait; + struct wait_queue *close_wait; +#else wait_queue_head_t open_wait; wait_queue_head_t close_wait; +#endif struct termios normaltermios; struct termios callouttermios; struct tq_struct tqueue; diff -u --recursive --new-file v2.3.16/linux/include/linux/tty.h linux/include/linux/tty.h --- v2.3.16/linux/include/linux/tty.h Wed Aug 18 16:43:35 1999 +++ linux/include/linux/tty.h Tue Sep 7 11:28:52 1999 @@ -344,6 +344,7 @@ extern int lp_init(void); extern int pty_init(void); extern int tty_init(void); +extern int ip2_init(void); extern int pcxe_init(void); extern int pc_init(void); extern int vcs_init(void); diff -u --recursive --new-file v2.3.16/linux/include/linux/udf_167.h linux/include/linux/udf_167.h --- v2.3.16/linux/include/linux/udf_167.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/udf_167.h Sat Sep 4 12:42:30 1999 @@ -0,0 +1,778 @@ +#if !defined(_LINUX_UDF_167_H) +#define _LINUX_UDF_167_H +/* + * udf_167.h + * + * DESCRIPTION + * Definitions from the ECMA 167 standard. + * http://www.ecma.ch/ + * + * These abbreviations are used to keep the symbols short: + * Alloc Allocation + * App Application + * Attr Attribute + * Char Characters + * Desc Descriptor + * Descs Descriptors + * Ext Extent + * Ident Identifier + * Imp Implementation + * Lvl Level + * Max Maximum + * Num Number + * Ptr Pointer + * Seq Sequence + * Std Standard + * Struct Structure + * Vol Volume + * The symbols are otherwise identical to the standard, and the + * sections of the standard to refer to are indicated. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * HISTORY + * July 12, 1997 - Andrew E. Mileski + * Adapted from the ECMA-167 standard. + * + * 10/2/98 dgb Adaptation + * 10/4/98 Changes by HJA Sandkuyl + * 10/7/98 Changed FILE_EXISTENCE to FILE_HIDDEN, per UDF 2.0 spec + * 11/26/98 Modifed some entries for UDF 1.5/2.0 + * 11/26/98 bf Fixed typos, non-linux types, more structures + * 12/5/98 dgb Adjusted structure and content of include files. + */ + +#ifdef __KERNEL__ +#include +#define Uint8 __u8 +#define Uint16 __u16 +#define Uint32 __u32 +#define Uint64 __u64 +typedef Uint8 dstring; +#else +#define Uint8 unsigned char +#define Uint16 unsigned short +#define Uint32 unsigned int +#define Uint64 unsigned long long +typedef Uint8 dstring; +#endif + +/* make sure all structures are packed! */ +#pragma pack(1) + +/* CS0 Charspec (ECMA 167 1/7.2.1) */ +typedef struct { + Uint8 charSetType; + Uint8 charSetInfo[63]; +} charspec; + +/* Timestamp (ECMA 167 1/7.3) */ +typedef struct { + Uint16 typeAndTimezone; + Uint16 year; + Uint8 month; + Uint8 day; + Uint8 hour; + Uint8 minute; + Uint8 second; + Uint8 centiseconds; + Uint8 hundredsOfMicroseconds; + Uint8 microseconds; +} timestamp; + +/* Timestamp types (ECMA 167 1/7.3.1) */ +#define TIMESTAMP_TYPE_CUT 0x0000U +#define TIMESTAMP_TYPE_LOCAL 0x0001U +#define TIMESTAMP_TYPE_AGREEMENT 0x0002U + +/* Entity Identifier (ECMA 167 1/7.4) */ +typedef struct { + Uint8 flags; + Uint8 ident[23]; + Uint8 identSuffix[8]; +} EntityID; +#define regid EntityID + +/* Entity identifier flags (ECMA 167 1/7.4.1) */ +#define ENTITYID_FLAGS_DIRTY 0x01U +#define ENTITYID_FLAGS_PROTECTED 0x02U + +/* Volume Structure Descriptor (ECMA 167 2/9.1) */ +#define STD_ID_LEN 5 +struct VolStructDesc { + Uint8 structType; + Uint8 stdIdent[STD_ID_LEN]; + Uint8 structVersion; + Uint8 structData[2041]; +}; + +/* Std structure identifiers (ECMA 167 2/9.1.2) */ +#define STD_ID_BEA01 "BEA01" +#define STD_ID_BOOT2 "BOOT2" +#define STD_ID_CD001 "CD001" +#define STD_ID_CDW02 "CDW02" +#define STD_ID_NSR02 "NSR02" +#define STD_ID_NSR03 "NSR03" +#define STD_ID_TEA01 "TEA01" + +/* Beginning Extended Area Descriptor (ECMA 167 2/9.2) */ +struct BeginningExtendedAreaDesc { + Uint8 structType; + Uint8 stdIdent[STD_ID_LEN]; + Uint8 structVersion; + Uint8 structData[2041]; +}; + +/* Terminating Extended Area Descriptor (ECMA 167 2/9.3) */ +struct TerminatingExtendedAreaDesc { + Uint8 structType; + Uint8 stdIdent[STD_ID_LEN]; + Uint8 structVersion; + Uint8 structData[2041]; +}; + +/* Boot Descriptor (ECMA 167 2/9.4) */ +struct BootDesc { + Uint8 structType; + Uint8 stdIdent[STD_ID_LEN]; + Uint8 structVersion; + Uint8 reserved1; + EntityID architectureType; + EntityID bootIdent; + Uint32 bootExtLocation; + Uint32 bootExtLength; + Uint64 loadAddress; + Uint64 startAddress; + timestamp descCreationDateAndTime; + Uint16 flags; + Uint8 reserved2[32]; + Uint8 bootUse[1906]; +}; + +/* Boot flags (ECMA 167 2/9.4.12) */ +#define BOOT_FLAGS_ERASE 1 + +/* Extent Descriptor (ECMA 167 3/7.1) */ +typedef struct { + Uint32 extLength; + Uint32 extLocation; +} extent_ad; + +/* Descriptor Tag (ECMA 167 3/7.2) */ +typedef struct { + Uint16 tagIdent; + Uint16 descVersion; + Uint8 tagChecksum; + Uint8 reserved; + Uint16 tagSerialNum; + Uint16 descCRC; + Uint16 descCRCLength; + Uint32 tagLocation; +} tag; + +/* Tag Identifiers (ECMA 167 3/7.2.1) */ +#define TID_UNUSED_DESC 0x0000U +#define TID_PRIMARY_VOL_DESC 0x0001U +#define TID_ANCHOR_VOL_DESC_PTR 0x0002U +#define TID_VOL_DESC_PTR 0x0003U +#define TID_IMP_USE_VOL_DESC 0x0004U +#define TID_PARTITION_DESC 0x0005U +#define TID_LOGICAL_VOL_DESC 0x0006U +#define TID_UNALLOC_SPACE_DESC 0x0007U +#define TID_TERMINATING_DESC 0x0008U +#define TID_LOGICAL_VOL_INTEGRITY_DESC 0x0009U + +/* Tag Identifiers (ECMA 167 4/7.2.1) */ +#define TID_FILE_SET_DESC 0x0100U +#define TID_FILE_IDENT_DESC 0x0101U +#define TID_ALLOC_EXTENT_DESC 0x0102U +#define TID_INDIRECT_ENTRY 0x0103U +#define TID_TERMINAL_ENTRY 0x0104U +#define TID_FILE_ENTRY 0x0105U +#define TID_EXTENDED_ATTRE_HEADER_DESC 0x0106U +#define TID_UNALLOCATED_SPACE_ENTRY 0x0107U +#define TID_SPACE_BITMAP_DESC 0x0108U +#define TID_PARTITION_INTEGRITY_ENTRY 0x0109U +#define TID_EXTENDED_FILE_ENTRY 0x010AU + +/* NSR Descriptor (ECMA 167 3/9.1) */ +struct NSRDesc { + Uint8 structType; + Uint8 stdIdent[STD_ID_LEN]; + Uint8 structVersion; + Uint8 reserved; + Uint8 structData[2040]; +}; + +/* Primary Volume Descriptor (ECMA 167 3/10.1) */ +struct PrimaryVolDesc { + tag descTag; + Uint32 volDescSeqNum; + Uint32 primaryVolDescNum; + dstring volIdent[32]; + Uint16 volSeqNum; + Uint16 maxVolSeqNum; + Uint16 interchangeLvl; + Uint16 maxInterchangeLvl; + Uint32 charSetList; + Uint32 maxCharSetList; + dstring volSetIdent[128]; + charspec descCharSet; + charspec explanatoryCharSet; + extent_ad volAbstract; + extent_ad volCopyright; + EntityID appIdent; + timestamp recordingDateAndTime; + EntityID impIdent; + Uint8 impUse[64]; + Uint32 predecessorVolDescSeqLocation; + Uint16 flags; + Uint8 reserved[22]; +}; + +/* Primary volume descriptor flags (ECMA 167 3/10.1.21) */ +#define VOL_SET_IDENT 1 + +/* Anchor Volume Descriptor Pointer (ECMA 167 3/10.2) */ +struct AnchorVolDescPtr { + tag descTag; + extent_ad mainVolDescSeqExt; + extent_ad reserveVolDescSeqExt; + Uint8 reserved[480]; +}; + +/* Volume Descriptor Pointer (ECMA 167 3/10.3) */ +struct VolDescPtr { + tag descTag; + Uint32 volDescSeqNum; + extent_ad nextVolDescSeqExt; + Uint8 reserved[484]; +}; + +/* Implementation Use Volume Descriptor (ECMA 167 3/10.4) */ +struct ImpUseVolDesc { + tag descTag; + Uint32 volDescSeqNum; + EntityID impIdent; + Uint8 impUse[460]; +}; + +/* Partition Descriptor (ECMA 167 3/10.5) */ +struct PartitionDesc { + tag descTag; + Uint32 volDescSeqNum; + Uint16 partitionFlags; + Uint16 partitionNumber; + EntityID partitionContents; + Uint8 partitionContentsUse[128]; + Uint32 accessType; + Uint32 partitionStartingLocation; + Uint32 partitionLength; + EntityID impIdent; + Uint8 impUse[128]; + Uint8 reserved[156]; +}; + +/* Partition Flags (ECMA 167 3/10.5.3) */ +#define PARTITION_FLAGS_ALLOC 1 + +/* Partition Contents (ECMA 167 3/10.5.5) */ +#define PARTITION_CONTENTS_FDC01 "+FDC01" +#define PARTITION_CONTENTS_CD001 "+CD001" +#define PARTITION_CONTENTS_CDW02 "+CDW02" +#define PARTITION_CONTENTS_NSR02 "+NSR02" +#define PARTITION_CONTENTS_NSR03 "+NSR03" + +/* Partition Access Types (ECMA 167 3/10.5.7) */ +#define PARTITION_ACCESS_NONE 0 +#define PARTITION_ACCESS_R 1 +#define PARTITION_ACCESS_WO 2 +#define PARTITION_ACCESS_RW 3 +#define PARTITION_ACCESS_OW 4 + +/* Logical Volume Descriptor (ECMA 167 3/10.6) */ +struct LogicalVolDesc { + tag descTag; + Uint32 volDescSeqNum; + charspec descCharSet; + dstring logicalVolIdent[128]; + Uint32 logicalBlockSize; + EntityID domainIdent; + Uint8 logicalVolContentsUse[16]; /* used to find fileset */ + Uint32 mapTableLength; + Uint32 numPartitionMaps; + EntityID impIdent; + Uint8 impUse[128]; + extent_ad integritySeqExt; + Uint8 partitionMaps[0]; +}; + +/* Generic Partition Map (ECMA 167 3/10.7.1) */ +struct GenericPartitionMap { + Uint8 partitionMapType; + Uint8 partitionMapLength; + Uint8 partitionMapping[0]; +}; + +/* Partition Map Type (ECMA 167 3/10.7.1.1) */ +#define PARTITION_MAP_TYPE_NONE 0 +#define PARTITION_MAP_TYPE_1 1 +#define PARTITION_MAP_TYPE_2 2 + +/* Type 1 Partition Map (ECMA 167 3/10.7.2) */ +struct GenericPartitionMap1 { + Uint8 partitionMapType; + Uint8 partitionMapLength; + Uint16 volSeqNum; + Uint16 partitionNum; +}; + +/* Type 2 Partition Map (ECMA 167 3/10.7.3) */ +struct GenericPartitionMap2 { + Uint8 partitionMapType; /* 2 */ + Uint8 partitionMapLength; + Uint8 partitionIdent[62]; +}; + +/* Unallocated Space Descriptor (ECMA 167 3/10.8) */ +struct UnallocatedSpaceDesc { + tag descTag; + Uint32 volDescSeqNum; + Uint32 numAllocDescs; + extent_ad allocDescs[0]; +}; + +/* Terminating Descriptor (ECMA 3/10.9) */ +struct TerminatingDesc { + tag descTag; + Uint8 reserved[496]; +}; + +struct GenericDesc +{ + tag descTag; + Uint32 volDescSeqNum; +}; + +/* Logical Volume Integrity Descriptor (ECMA 167 3/10.10) */ +struct LogicalVolIntegrityDesc { + tag descTag; + timestamp recordingDateAndTime; + Uint32 integrityType; + extent_ad nextIntegrityExt; + Uint8 logicalVolContentsUse[32]; + Uint32 numOfPartitions; + Uint32 lengthOfImpUse; + Uint32 freeSpaceTable[0]; + Uint32 sizeTable[0]; + Uint8 impUse[0]; +}; + +/* Integrity Types (ECMA 167 3/10.10.3) */ +#define INTEGRITY_TYPE_OPEN 0 +#define INTEGRITY_TYPE_CLOSE 1 + +/* Recorded Address (ECMA 167 4/7.1) */ +typedef struct { + Uint32 logicalBlockNum; + Uint16 partitionReferenceNum; +} lb_addr; + +/* Extent interpretation (ECMA 167 4/14.14.1.1) */ +#define EXTENT_RECORDED_ALLOCATED 0x00 +#define EXTENT_NOT_RECORDED_ALLOCATED 0x01 +#define EXTENT_NOT_RECORDED_NOT_ALLOCATED 0x02 +#define EXTENT_NEXT_EXTENT_ALLOCDECS 0x03 + +/* Long Allocation Descriptor (ECMA 167 4/14.14.2) */ +typedef struct { + Uint32 extLength; + lb_addr extLocation; + Uint8 impUse[6]; +} long_ad; + /* upper 2 bits of extLength indicate type */ + +/* File Set Descriptor (ECMA 167 4/14.1) */ +struct FileSetDesc { + tag descTag; + timestamp recordingDateAndTime; + Uint16 interchangeLvl; + Uint16 maxInterchangeLvl; + Uint32 charSetList; + Uint32 maxCharSetList; + Uint32 fileSetNum; + Uint32 fileSetDescNum; + charspec logicalVolIdentCharSet; + dstring logicalVolIdent[128]; + charspec fileSetCharSet; + dstring fileSetIdent[32]; + dstring copyrightFileIdent[32]; + dstring abstractFileIdent[32]; + long_ad rootDirectoryICB; + EntityID domainIdent; + long_ad nextExt; + long_ad streamDirectoryICB; + Uint8 reserved[32]; +}; + +/* Short Allocation Descriptor (ECMA 167 4/14.14.1) */ +typedef struct { + Uint32 extLength; + Uint32 extPosition; +} short_ad; + +/* Partition Header Descriptor (ECMA 167 4/14.3) */ +struct PartitionHeaderDesc { + short_ad unallocatedSpaceTable; + short_ad unallocatedSpaceBitmap; + short_ad partitionIntegrityTable; + short_ad freedSpaceTable; + short_ad freedSpaceBitmap; + Uint8 reserved[88]; +}; + +/* File Identifier Descriptor (ECMA 167 4/14.4) */ +struct FileIdentDesc +{ + tag descTag; + Uint16 fileVersionNum; /* 1 */ + Uint8 fileCharacteristics; + Uint8 lengthFileIdent; + long_ad icb; + Uint16 lengthOfImpUse; + Uint8 impUse[0]; + Uint8 fileIdent[0]; + Uint8 padding[0]; +}; + +/* File Characteristics (ECMA 167 4/14.4.3) */ +#define FILE_HIDDEN 1 +#define FILE_DIRECTORY 2 +#define FILE_DELETED 4 +#define FILE_PARENT 8 +#define FILE_METADATA 0x10 /* UDF 2.0 */ + +/* Allocation Ext Descriptor (ECMA 167 4/14.5) */ +struct AllocExtDesc +{ + tag descTag; + Uint32 previousAllocExtLocation; + Uint32 lengthAllocDescs; +}; + +/* ICB Tag (ECMA 167 4/14.6) */ +typedef struct { + Uint32 priorRecordedNumDirectEntries; + Uint16 strategyType; + Uint16 strategyParameter; + Uint16 numEntries; + Uint8 reserved; + Uint8 fileType; + lb_addr parentICBLocation; + Uint16 flags; +} icbtag; + +/* ICB File Type (ECMA 167 4/14.6.6) */ +#define FILE_TYPE_NONE 0x00U +#define FILE_TYPE_UNALLOC 0x01U +#define FILE_TYPE_INTEGRITY 0x02U +#define FILE_TYPE_INDIRECT 0x03U +#define FILE_TYPE_DIRECTORY 0x04U +#define FILE_TYPE_REGULAR 0x05U +#define FILE_TYPE_BLOCK 0x06U +#define FILE_TYPE_CHAR 0x07U +#define FILE_TYPE_EXTENDED 0x08U +#define FILE_TYPE_FIFO 0x09U +#define FILE_TYPE_SOCKET 0x0aU +#define FILE_TYPE_TERMINAL 0x0bU +#define FILE_TYPE_SYMLINK 0x0cU +#define FILE_TYPE_STREAMDIR 0x0dU /* ECMA 167 4/13 */ + +/* ICB Flags (ECMA 167 4/14.6.8) */ +#define ICB_FLAG_ALLOC_MASK 0x0007U +#define ICB_FLAG_SORTED 0x0008U +#define ICB_FLAG_NONRELOCATABLE 0x0010U +#define ICB_FLAG_ARCHIVE 0x0020U +#define ICB_FLAG_SETUID 0x0040U +#define ICB_FLAG_SETGID 0x0080U +#define ICB_FLAG_STICKY 0x0100U +#define ICB_FLAG_CONTIGUOUS 0x0200U +#define ICB_FLAG_SYSTEM 0x0400U +#define ICB_FLAG_TRANSFORMED 0x0800U +#define ICB_FLAG_MULTIVERSIONS 0x1000U + +/* ICB Flags Allocation type(ECMA 167 4/14.6.8) */ +#define ICB_FLAG_AD_SHORT 0 +#define ICB_FLAG_AD_LONG 1 +#define ICB_FLAG_AD_EXTENDED 2 +#define ICB_FLAG_AD_IN_ICB 3 + +/* Indirect Entry (ECMA 167 4/14.7) */ +struct IndirectEntry { + tag descTag; + icbtag icbTag; + long_ad indirectICB; +}; + +/* Terminal Entry (ECMA 167 4/14.8) */ +struct TerminalEntry { + tag descTag; + icbtag icbTag; +}; + +/* File Entry (ECMA 167 4/14.9) */ +struct FileEntry { + tag descTag; + icbtag icbTag; + Uint32 uid; + Uint32 gid; + Uint32 permissions; + Uint16 fileLinkCount; + Uint8 recordFormat; + Uint8 recordDisplayAttr; + Uint32 recordLength; + Uint64 informationLength; + Uint64 logicalBlocksRecorded; + timestamp accessTime; + timestamp modificationTime; + timestamp attrTime; + Uint32 checkpoint; + long_ad extendedAttrICB; + EntityID impIdent; + Uint64 uniqueID; /* 0= root, 16- (2^32-1) */ + Uint32 lengthExtendedAttr; + Uint32 lengthAllocDescs; + Uint8 extendedAttr[0]; + Uint8 allocDescs[0]; +}; + +/* File Permissions (ECMA 167 4/14.9.5) */ +#define PERM_O_EXEC 0x00000001U +#define PERM_O_WRITE 0x00000002U +#define PERM_O_READ 0x00000004U +#define PERM_O_CHATTR 0x00000008U +#define PERM_O_DELETE 0x00000010U +#define PERM_G_EXEC 0x00000020U +#define PERM_G_WRITE 0x00000040U +#define PERM_G_READ 0x00000080U +#define PERM_G_CHATTR 0x00000100U +#define PERM_G_DELETE 0x00000200U +#define PERM_U_EXEC 0x00000400U +#define PERM_U_WRITE 0x00000800U +#define PERM_U_READ 0x00001000U +#define PERM_U_CHATTR 0x00002000U +#define PERM_U_DELETE 0x00004000U + +/* File Record Format (ECMA 167 4/14.9.7) */ +#define RECORD_FMT_NONE 0 +#define RECORD_FMT_FIXED_PAD 1 +#define RECORD_FMT_FIXED 2 +#define RECORD_FMT_VARIABLE8 3 +#define RECORD_FMT_VARIABLE16 4 +#define RECORD_FMT_VARIABLE16_MSB 5 +#define RECORD_FMT_VARIABLE32 6 +#define RECORD_FMT_PRINT 7 +#define RECORD_FMT_LF 8 +#define RECORD_FMT_CR 9 +#define RECORD_FMT_CRLF 10 +#define RECORD_FMT_LFCR 10 + +/* Extended Attribute Header Descriptor (ECMA 167 4/14.10.1) */ +struct ExtendedAttrHeaderDesc { + tag descTag; + Uint32 impAttrLocation; + Uint32 appAttrLocation; +}; + +/* Generic Attribute Format (ECMA 4/14.10.2) */ +struct GenericAttrFormat { + Uint32 attrType; + Uint8 attrSubtype; + Uint8 reserved[3]; + Uint32 attrLength; + Uint8 attrData[0]; +}; + +/* Character Set Attribute Format (ECMA 4/14.10.3) */ +struct CharSetAttrFormat { + Uint32 attrType; /* 1 */ + Uint8 attrSubtype; /* 1 */ + Uint8 reserved[3]; + Uint32 attrLength; + Uint32 escapeSeqLength; + Uint8 charSetType; + Uint8 escapeSeq[0]; +}; + +/* Alternate Permissions (ECMA 167 4/14.10.4) */ +struct AlternatePermissionsExtendedAttr { + Uint32 attrType; /* 3 */ + Uint8 attrSubtype; /* 1 */ + Uint8 reserved[3]; + Uint32 attrLength; + Uint16 ownerIdent; + Uint16 groupIdent; + Uint16 permission; +}; + +/* File Times Extended Attribute (ECMA 167 4/14.10.5) */ +struct FileTimesExtendedAttr { + Uint32 attrType; /* 5 */ + Uint8 attrSubtype; /* 1 */ + Uint8 reserved[3]; + Uint32 attrLength; + Uint32 dataLength; + Uint32 fileTimeExistence; + Uint8 fileTimes; +}; + +/* FileTimeExistence (ECMA 167 4/14.10.5.6) */ +#define FTE_CREATION 0 +#define FTE_DELETION 2 +#define FTE_EFFECTIVE 3 +#define FTE_BACKUP 5 + +/* Information Times Extended Attribute (ECMA 167 4/14.10.6) */ +struct InfoTimesExtendedAttr { + Uint32 attrType; /* 6 */ + Uint8 attrSubtype; /* 1 */ + Uint8 reserved[3]; + Uint32 attrLength; + Uint32 dataLength; + Uint32 infoTimeExistence; + Uint8 infoTimes[0]; +}; + +/* Device Specification Extended Attribute (ECMA 167 4/14.10.7) */ +struct DeviceSpecificationExtendedAttr { + Uint32 attrType; /* 12 */ + Uint8 attrSubtype; /* 1 */ + Uint8 reserved[3]; + Uint32 attrLength; + Uint32 impUseLength; + Uint32 majorDeviceIdent; + Uint32 minorDeviceIdent; + Uint8 impUse[0]; +}; + +/* Implementation Use Extended Attr (ECMA 167 4/14.10.8) */ +struct ImpUseExtendedAttr { + Uint32 attrType; /* 2048 */ + Uint8 attrSubtype; /* 1 */ + Uint8 reserved[3]; + Uint32 attrLength; + Uint32 impUseLength; + EntityID impIdent; + Uint8 impUse[0]; +}; + +/* Application Use Extended Attribute (ECMA 167 4/14.10.9) */ +struct AppUseExtendedAttr { + Uint32 attrType; /* 65536 */ + Uint8 attrSubtype; /* 1 */ + Uint8 reserved[3]; + Uint32 attrLength; + Uint32 appUseLength; + EntityID appIdent; + Uint8 appUse[0]; +}; + +#define EXTATTR_CHAR_SET 1 +#define EXTATTR_ALT_PERMS 3 +#define EXTATTR_FILE_TIMES 5 +#define EXTATTR_INFO_TIMES 6 +#define EXTATTR_DEV_SPEC 12 +#define EXTATTR_IMP_USE 2048 +#define EXTATTR_APP_USE 65536 + + +/* Unallocated Space Entry (ECMA 167 4/14.11) */ +struct UnallocatedSpaceEntry { + tag descTag; + icbtag icbTag; + Uint32 lengthAllocDescs; + Uint8 allocDescs[0]; +}; + +/* Space Bitmap Descriptor (ECMA 167 4/14.12) */ +struct SpaceBitmapDesc { + tag descTag; + Uint32 numOfBits; + Uint32 numOfBytes; + Uint8 bitmap[0]; +}; + +/* Partition Integrity Entry (ECMA 167 4/14.13) */ +struct PartitionIntegrityEntry { + tag descTag; + icbtag icbTag; + timestamp recordingDateAndTime; + Uint8 integrityType; + Uint8 reserved[175]; + EntityID impIdent; + Uint8 impUse[256]; +}; + +/* Extended Allocation Descriptor (ECMA 167 4/14.14.3) */ +typedef struct { /* ECMA 167 4/14.14.3 */ + Uint32 extLength; + Uint32 recordedLength; + Uint32 informationLength; + lb_addr extLocation; +} ext_ad; + +/* Logical Volume Header Descriptor (ECMA 167 4/14.5) */ +struct LogicalVolHeaderDesc { + Uint64 uniqueID; + Uint8 reserved[24]; +}; + +/* Path Component (ECMA 167 4/14.16.1) */ +struct PathComponent { + Uint8 componentType; + Uint8 lengthComponentIdent; + Uint16 componentFileVersionNum; + dstring componentIdent[0]; +}; + +/* File Entry (ECMA 167 4/14.17) */ +struct ExtendedFileEntry { + tag descTag; + icbtag icbTag; + Uint32 uid; + Uint32 gid; + Uint32 permissions; + Uint16 fileLinkCount; + Uint8 recordFormat; + Uint8 recordDisplayAttr; + Uint32 recordLength; + Uint64 informationLength; + Uint64 objectSize; + Uint64 logicalBlocksRecorded; + timestamp accessTime; + timestamp modificationTime; + timestamp createTime; + timestamp attrTime; + Uint32 checkpoint; + Uint32 reserved; + long_ad extendedAttrICB; + long_ad streamDirectoryICB; + EntityID impIdent; + Uint64 uniqueID; + Uint32 lengthExtendedAttr; + Uint32 lengthAllocDescs; + Uint8 extendedAttr[0]; + Uint8 allocDescs[0]; +}; +#pragma pack() + +#endif /* !defined(_LINUX_UDF_167_H) */ diff -u --recursive --new-file v2.3.16/linux/include/linux/udf_fs.h linux/include/linux/udf_fs.h --- v2.3.16/linux/include/linux/udf_fs.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/udf_fs.h Sat Sep 4 12:42:30 1999 @@ -0,0 +1,63 @@ +/* + * udf_fs.h + * + * Included by fs/filesystems.c + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * HISTORY + * July 21, 1997 - Andrew E. Mileski + * Written, tested, and released. + * + * 10/2/98 dgb rearranged all headers + * 11/26/98 bf added byte order macros + * 12/5/98 dgb removed other includes to reduce kernel namespace pollution. + * This should only be included by the kernel now! + */ +#if !defined(_LINUX_UDF_FS_H) +#define _LINUX_UDF_FS_H + +#define UDF_PREALLOCATE +#define UDF_DEFAULT_PREALLOC_BLOCKS 8 +#define UDF_DEFAULT_PREALLOC_DIR_BLOCKS 0 + +#define UDFFS_DATE "99/09/02" +#define UDFFS_VERSION "0.8.9" +#define UDFFS_DEBUG + +#ifdef UDFFS_DEBUG +#define udf_debug(f, a...) \ + { \ + printk (KERN_DEBUG "UDF-fs DEBUG (%s, %d): %s: ", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (## f, ## a); \ + } +#else +#define udf_debug(f, a...) /**/ +#endif + +#define udf_info(f, a...) \ + printk (KERN_INFO "UDF-fs INFO " ## f, ## a); + +struct udf_addr +{ + __u32 block; + __u16 partition; + unsigned error : 1; + unsigned reserved : 15; +}; + + +/* Prototype for fs/filesystem.c (the only thing really required in this file) */ +extern int init_udf_fs(void); + +#endif /* !defined(_LINUX_UDF_FS_H) */ diff -u --recursive --new-file v2.3.16/linux/include/linux/udf_fs_i.h linux/include/linux/udf_fs_i.h --- v2.3.16/linux/include/linux/udf_fs_i.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/udf_fs_i.h Sat Sep 4 12:42:30 1999 @@ -0,0 +1,60 @@ +/* + * udf_fs_i.h + * + * This file is intended for the Linux kernel/module. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + */ + +#if !defined(_LINUX_UDF_FS_I_H) +#define _LINUX_UDF_FS_I_H + +#ifdef __KERNEL__ + +#ifndef _LINUX_UDF_167_H +typedef struct +{ + __u32 logicalBlockNum; + __u16 partitionReferenceNum; +} lb_addr; +#endif + +struct udf_inode_info +{ + long i_uatime; + long i_umtime; + long i_uctime; + /* Physical address of inode */ + lb_addr i_ext0Location; /* partition relative */ + lb_addr i_location; + __u32 i_ext0Length; /* in blocks */ + __u32 i_ext0Offset; /* for short directories */ + __u64 i_unique; + __u32 i_lenEAttr; + __u32 i_lenAlloc; + __u32 i_next_alloc_block; + __u32 i_next_alloc_goal; + unsigned i_alloc_type : 3; + unsigned i_extended_fe : 1; + unsigned i_strat_4096 : 1; + unsigned reserved : 27; +}; + +#endif + +/* exported IOCTLs, we have 'l', 0x40-0x7f */ + +#define UDF_GETEASIZE _IOR('l', 0x40, int) +#define UDF_GETEABLOCK _IOR('l', 0x41, void *) +#define UDF_GETVOLIDENT _IOR('l', 0x42, void *) + +#endif /* !defined(_LINUX_UDF_FS_I_H) */ diff -u --recursive --new-file v2.3.16/linux/include/linux/udf_fs_sb.h linux/include/linux/udf_fs_sb.h --- v2.3.16/linux/include/linux/udf_fs_sb.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/udf_fs_sb.h Sat Sep 4 12:42:30 1999 @@ -0,0 +1,108 @@ +/* + * udf_fs_sb.h + * + * This include file is for the Linux kernel/module. + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + */ + +#if !defined(_LINUX_UDF_FS_SB_H) +#define _LINUX_UDF_FS_SB_H + +#pragma pack(1) + +#define UDF_MAX_BLOCK_LOADED 8 + +#define UDF_TYPE1_MAP15 0x1511U +#define UDF_VIRTUAL_MAP15 0x1512U +#define UDF_VIRTUAL_MAP20 0x2012U +#define UDF_SPARABLE_MAP15 0x1522U + +struct udf_sparing_data +{ + __u32 s_spar_loc; + __u16 s_spar_plen; +}; + +struct udf_virtual_data +{ + __u32 s_num_entries; + __u16 s_start_offset; +}; + +struct udf_part_map +{ + __u32 s_uspace_bitmap; + __u32 s_partition_root; + __u32 s_partition_len; + __u16 s_partition_type; + __u16 s_partition_num; + union + { + struct udf_sparing_data s_sparing; + struct udf_virtual_data s_virtual; + } s_type_specific; + __u16 s_volumeseqnum; +}; + +#pragma pack() + +struct udf_sb_info +{ + struct udf_part_map *s_partmaps; + __u8 s_volident[32]; + + /* Overall info */ + __u16 s_partitions; + __u16 s_partition; + + /* Sector headers */ + __u32 s_session; + __u32 s_anchor[4]; + __u32 s_lastblock; + + struct buffer_head *s_lvidbh; + + lb_addr s_location; + + __u16 s_loaded_block_bitmaps; + __u32 s_block_bitmap_number[UDF_MAX_BLOCK_LOADED]; + struct buffer_head *s_block_bitmap[UDF_MAX_BLOCK_LOADED]; + + /* Default permissions */ + mode_t s_umask; + gid_t s_gid; + uid_t s_uid; + + /* Root Info */ + time_t s_recordtime; + + /* Fileset Info */ + __u16 s_serialnum; + + /* Character Mapping Info */ + struct nls_table *s_nls_iocharset; + __u8 s_utf8; + + /* Miscellaneous flags */ + __u32 s_flags; + + /* VAT inode */ + struct inode *s_vat; + +#if LINUX_VERSION_CODE < 0x020206 + int s_rename_lock; + struct wait_queue * s_rename_wait; +#endif +}; + +#endif /* !defined(_LINUX_UDF_FS_SB_H) */ diff -u --recursive --new-file v2.3.16/linux/include/linux/udf_udf.h linux/include/linux/udf_udf.h --- v2.3.16/linux/include/linux/udf_udf.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/udf_udf.h Sat Sep 4 12:42:30 1999 @@ -0,0 +1,228 @@ +#if !defined(_LINUX_UDF_UDF_H) +#define _LINUX_UDF_UDF_H +/* + * udf_udf.h + * + * PURPOSE + * OSTA-UDF(tm) format specification [based on ECMA 167 standard]. + * http://www.osta.org/ + * + * CONTACTS + * E-mail regarding any portion of the Linux UDF file system should be + * directed to the development team mailing list (run by majordomo): + * linux_udf@hootie.lvld.hp.com + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + * + * 10/2/98 dgb changed UDF_ID_DEVELOPER + * 11/26/98 bf changed UDF_ID_DEVELOPER, + * 12/5/98 dgb updated include file hierarchy, more UDF definitions + */ + +/* based on ECMA 167 structure definitions */ +#include + +#pragma pack(1) + +/* -------- Basic types and constants ----------- */ +/* UDF character set (UDF 1.50 2.1.2) */ +#define UDF_CHAR_SET_TYPE 0 +#define UDF_CHAR_SET_INFO "OSTA Compressed Unicode" + +#define UDF_ID_DEVELOPER "*Linux UDFFS" + +/* UDF 1.02 2.2.6.4 */ +struct LogicalVolIntegrityDescImpUse +{ + EntityID impIdent; + Uint32 numFiles; + Uint32 numDirs; + Uint16 minUDFReadRev; + Uint16 minUDFWriteRev; + Uint16 maxUDFWriteRev; +}; + +/* UDF 1.02 2.2.7.2 */ +/* LVInformation may be present in ImpUseVolDesc.impUse */ +struct ImpUseVolDescImpUse +{ + charspec LVICharset; + dstring logicalVolIdent[128]; + dstring LVInfo1[36]; + dstring LVInfo2[36]; + dstring LVInfo3[36]; + EntityID impIdent; + Uint8 impUse[128]; +}; + +struct UdfPartitionMap2 +{ + Uint8 partitionMapType; + Uint8 partitionMapLength; + Uint8 reserved1[2]; + EntityID partIdent; + Uint16 volSeqNum; + Uint16 partitionNum; + Uint8 reserved2[24]; +}; + +/* UDF 1.5 2.2.8 */ +struct VirtualPartitionMap +{ + Uint8 partitionMapType; /* 2 */ + Uint8 partitionMapLength; /* 64 */ + Uint8 reserved1[2]; /* #00 */ + EntityID partIdent; + Uint16 volSeqNum; + Uint16 partitionNum; + Uint8 reserved2[24]; /* #00 */ +}; + +/* UDF 1.5 2.2.9 */ +struct SparablePartitionMap +{ + Uint8 partitionMapType; /* 2 */ + Uint8 partitionMapLength; /* 64 */ + Uint8 reserved1[2]; /* #00 */ + EntityID partIdent; /* Flags = 0 */ + /* Id = UDF_ID_SPARABLE */ + /* IdSuf = 2.1.5.3 */ + Uint16 volSeqNum; + Uint16 partitionNum; + Uint16 packetLength; /* 32 */ + Uint8 numSparingTables; + Uint8 reserved2[1]; /* #00 */ + Uint32 sizeSparingTable; + Uint32 locSparingTable[0]; + Uint8 pad[0]; +}; + +/* DVD Copyright Management Info, see UDF 1.02 3.3.4.5.1.2 */ +/* when ImpUseExtendedAttr.impIdent= "*UDF DVD CGMS Info" */ +struct DVDCopyrightImpUse { + Uint16 headerChecksum; + Uint8 CGMSInfo; + Uint8 dataType; + Uint8 protectionSystemInfo[4]; +}; + +/* the impUse of long_ad used in AllocDescs - UDF 1.02 2.3.10.1 */ +struct ADImpUse +{ + Uint16 flags; + Uint8 impUse[4]; +}; + +/* UDF 1.02 2.3.10.1 */ +#define UDF_EXTENT_LENGTH_MASK 0x3FFFFFFF +#define UDF_EXTENT_FLAG_MASK 0xc0000000 +#define UDF_EXTENT_FLAG_ERASED 0x40000000 + +/* + * Important! VirtualAllocationTables are + * very different between 1.5 and 2.0! + */ + +/* ----------- 1.5 ------------- */ +/* UDF 1.5 2.2.10 */ +#define FILE_TYPE_VAT15 0x0U + +/* UDF 1.5 2.2.10 - VAT layout: */ +struct VirutalAllocationTable15 { + Uint32 VirtualSector[0]; + EntityID ident; + Uint32 previousVATICB; + }; +/* where number of VirtualSector's is (VATSize-36)/4 */ + +/* ----------- 2.0 ------------- */ +/* UDF 2.0 2.2.10 */ +#define FILE_TYPE_VAT20 0xf8U + +/* UDF 2.0 2.2.10 (different from 1.5!) */ +struct VirtualAllocationTable20 { + Uint16 lengthHeader; + Uint16 lengthImpUse; + dstring logicalVolIdent[128]; + Uint32 previousVatICBLoc; + Uint32 numFIDSFiles; + Uint32 numFIDSDirectories; /* non-parent */ + Uint16 minReadRevision; + Uint16 minWriteRevision; + Uint16 maxWriteRevision; + Uint16 reserved; + Uint8 impUse[0]; + Uint32 vatEntry[0]; +}; + +/* Sparing maps, see UDF 1.5 2.2.11 */ +typedef struct { + Uint32 origLocation; + Uint32 mappedLocation; +} SparingEntry; + +/* sparing maps, see UDF 2.0 2.2.11 */ +struct SparingTable { + tag descTag; + EntityID sparingIdent; /* *UDF Sparing Table */ + Uint16 reallocationTableLen; + Uint16 reserved; /* #00 */ + Uint32 sequenceNum; + SparingEntry mapEntry[0]; +}; + +/* Entity Identifiers (UDF 1.50 6.1) */ +#define UDF_ID_COMPLIANT "*OSTA UDF Compliant" +#define UDF_ID_LV_INFO "*UDF LV Info" +#define UDF_ID_FREE_EA "*UDF FreeEASpace" +#define UDF_ID_FREE_APP_EA "*UDF FreeAppEASpace" +#define UDF_ID_DVD_CGMS "*UDF DVD CGMS Info" +#define UDF_ID_OS2_EA "*UDF OS/2 EA" +#define UDF_ID_OS2_EA_LENGTH "*UDF OS/2 EALength" +#define UDF_ID_MAC_VOLUME "*UDF Mac VolumeInfo" +#define UDF_ID_MAC_FINDER "*UDF Mac FinderInfo" +#define UDF_ID_MAC_UNIQUE "*UDF Mac UniqueIDTable" +#define UDF_ID_MAC_RESOURCE "*UDF Mac ResourceFork" +#define UDF_ID_VIRTUAL "*UDF Virtual Partition" +#define UDF_ID_SPARABLE "*UDF Sparable Partition" +#define UDF_ID_ALLOC "*UDF Virtual Alloc Tbl" +#define UDF_ID_SPARING "*UDF Sparing Table" + +/* Operating System Identifiers (UDF 1.50 6.3) */ +#define UDF_OS_CLASS_UNDEF 0x00U +#define UDF_OS_CLASS_DOS 0x01U +#define UDF_OS_CLASS_OS2 0x02U +#define UDF_OS_CLASS_MAC 0x03U +#define UDF_OS_CLASS_UNIX 0x04U +#define UDF_OS_CLASS_WIN95 0x05U +#define UDF_OS_CLASS_WINNT 0x06U +#define UDF_OS_ID_UNDEF 0x00U +#define UDF_OS_ID_DOS 0x00U +#define UDF_OS_ID_OS2 0x00U +#define UDF_OS_ID_MAC 0x00U +#define UDF_OS_ID_UNIX 0x00U +#define UDF_OS_ID_WIN95 0x00U +#define UDF_OS_ID_WINNT 0x00U +#define UDF_OS_ID_AIX 0x01U +#define UDF_OS_ID_SOLARIS 0x02U +#define UDF_OS_ID_HPUX 0x03U +#define UDF_OS_ID_IRIX 0x04U +#define UDF_OS_ID_LINUX 0x05U +#define UDF_OS_ID_MKLINUX 0x06U +#define UDF_OS_ID_FREEBSD 0x07U + +#define UDF_NAME_PAD 4 +#define UDF_NAME_LEN 255 +#define UDF_PATH_LEN 1023 + +#pragma pack() + +#endif /* !defined(_LINUX_UDF_FMT_H) */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/bulkmem.h linux/include/pcmcia/bulkmem.h --- v2.3.16/linux/include/pcmcia/bulkmem.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/bulkmem.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,195 @@ +/* + * Definitions for bulk memory services + * + * bulkmem.h 1.10 1999/08/28 04:12:33 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + * bulkmem.h 1.3 1995/05/27 04:49:49 + */ + +#ifndef _LINUX_BULKMEM_H +#define _LINUX_BULKMEM_H + +/* For GetFirstRegion and GetNextRegion */ +typedef struct region_info_t { + u_int Attributes; + u_int CardOffset; + u_int RegionSize; + u_int AccessSpeed; + u_int BlockSize; + u_int PartMultiple; + u_char JedecMfr, JedecInfo; + memory_handle_t next; +} region_info_t; + +#define REGION_TYPE 0x0001 +#define REGION_TYPE_CM 0x0000 +#define REGION_TYPE_AM 0x0001 +#define REGION_PREFETCH 0x0008 +#define REGION_CACHEABLE 0x0010 +#define REGION_BAR_MASK 0xe000 +#define REGION_BAR_SHIFT 13 + +/* For OpenMemory */ +typedef struct open_mem_t { + u_int Attributes; + u_int Offset; +} open_mem_t; + +/* Attributes for OpenMemory */ +#define MEMORY_TYPE 0x0001 +#define MEMORY_TYPE_CM 0x0000 +#define MEMORY_TYPE_AM 0x0001 +#define MEMORY_EXCLUSIVE 0x0002 +#define MEMORY_PREFETCH 0x0008 +#define MEMORY_CACHEABLE 0x0010 +#define MEMORY_BAR_MASK 0xe000 +#define MEMORY_BAR_SHIFT 13 + +typedef struct eraseq_entry_t { + memory_handle_t Handle; + u_char State; + u_int Size; + u_int Offset; + void *Optional; +} eraseq_entry_t; + +typedef struct eraseq_hdr_t { + int QueueEntryCnt; + eraseq_entry_t *QueueEntryArray; +} eraseq_hdr_t; + +#define ERASE_QUEUED 0x00 +#define ERASE_IN_PROGRESS(n) (((n) > 0) && ((n) < 0x80)) +#define ERASE_IDLE 0xff +#define ERASE_PASSED 0xe0 +#define ERASE_FAILED 0xe1 + +#define ERASE_MISSING 0x80 +#define ERASE_MEDIA_WRPROT 0x84 +#define ERASE_NOT_ERASABLE 0x85 +#define ERASE_BAD_OFFSET 0xc1 +#define ERASE_BAD_TECH 0xc2 +#define ERASE_BAD_SOCKET 0xc3 +#define ERASE_BAD_VCC 0xc4 +#define ERASE_BAD_VPP 0xc5 +#define ERASE_BAD_SIZE 0xc6 + +/* For CopyMemory */ +typedef struct copy_op_t { + u_int Attributes; + u_int SourceOffset; + u_int DestOffset; + u_int Count; +} copy_op_t; + +/* For ReadMemory and WriteMemory */ +typedef struct mem_op_t { + u_int Attributes; + u_int Offset; + u_int Count; +} mem_op_t; + +#define MEM_OP_BUFFER 0x01 +#define MEM_OP_BUFFER_USER 0x00 +#define MEM_OP_BUFFER_KERNEL 0x01 +#define MEM_OP_DISABLE_ERASE 0x02 +#define MEM_OP_VERIFY 0x04 + +/* For RegisterMTD */ +typedef struct mtd_reg_t { + u_int Attributes; + u_int Offset; + u_long MediaID; +} mtd_reg_t; + +/* + * Definitions for MTD requests + */ + +typedef struct mtd_request_t { + u_int SrcCardOffset; + u_int DestCardOffset; + u_int TransferLength; + u_int Function; + u_long MediaID; + u_int Status; + u_int Timeout; +} mtd_request_t; + +/* Fields in MTD Function */ +#define MTD_REQ_ACTION 0x003 +#define MTD_REQ_ERASE 0x000 +#define MTD_REQ_READ 0x001 +#define MTD_REQ_WRITE 0x002 +#define MTD_REQ_COPY 0x003 +#define MTD_REQ_NOERASE 0x004 +#define MTD_REQ_VERIFY 0x008 +#define MTD_REQ_READY 0x010 +#define MTD_REQ_TIMEOUT 0x020 +#define MTD_REQ_LAST 0x040 +#define MTD_REQ_FIRST 0x080 +#define MTD_REQ_KERNEL 0x100 + +/* Status codes */ +#define MTD_WAITREQ 0x00 +#define MTD_WAITTIMER 0x01 +#define MTD_WAITRDY 0x02 +#define MTD_WAITPOWER 0x03 + +/* + * Definitions for MTD helper functions + */ + +/* For MTDModifyWindow */ +typedef struct mtd_mod_win_t { + u_int Attributes; + u_int AccessSpeed; + u_int CardOffset; +} mtd_mod_win_t; + +/* For MTDSetVpp */ +typedef struct mtd_vpp_req_t { + u_char Vpp1, Vpp2; +} mtd_vpp_req_t; + +/* For MTDRDYMask */ +typedef struct mtd_rdy_req_t { + u_int Mask; +} mtd_rdy_req_t; + +enum mtd_helper { + MTDRequestWindow, MTDModifyWindow, MTDReleaseWindow, + MTDSetVpp, MTDRDYMask +}; + +#ifdef IN_CARD_SERVICES +extern int MTDHelperEntry(int func, void *a1, void *a2); +#else +extern int MTDHelperEntry(int func, ...); +#endif + +#endif /* _LINUX_BULKMEM_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/bus_ops.h linux/include/pcmcia/bus_ops.h --- v2.3.16/linux/include/pcmcia/bus_ops.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/bus_ops.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,150 @@ +/* + * bus_ops.h 1.6 1999/08/28 04:12:33 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_BUS_OPS_H +#define _LINUX_BUS_OPS_H + +typedef struct bus_operations { + void *priv; + u32 (*b_in)(void *bus, u32 port, s32 sz); + void (*b_ins)(void *bus, u32 port, void *buf, + u32 count, s32 sz); + void (*b_out)(void *bus, u32 val, u32 port, s32 sz); + void (*b_outs)(void *bus, u32 port, void *buf, + u32 count, s32 sz); + void *(*b_ioremap)(void *bus, u_long ofs, u_long sz); + void (*b_iounmap)(void *bus, void *addr); + u32 (*b_read)(void *bus, void *addr, s32 sz); + void (*b_write)(void *bus, u32 val, void *addr, s32 sz); + void (*b_copy_from)(void *bus, void *d, void *s, u32 count); + void (*b_copy_to)(void *bus, void *d, void *s, u32 count); + int (*b_request_irq)(void *bus, u_int irq, + void (*handler)(int, void *, + struct pt_regs *), + u_long flags, const char *device, + void *dev_id); + void (*b_free_irq)(void *bus, u_int irq, void *dev_id); +} bus_operations; + +#ifdef CONFIG_VIRTUAL_BUS + +#define bus_inb(b,p) (b)->b_in((b),(p),0) +#define bus_inw(b,p) (b)->b_in((b),(p),1) +#define bus_inl(b,p) (b)->b_in((b),(p),2) +#define bus_inw_ns(b,p) (b)->b_in((b),(p),-1) +#define bus_inl_ns(b,p) (b)->b_in((b),(p),-2) + +#define bus_insb(b,p,a,c) (b)->b_ins((b),(p),(a),(c),0) +#define bus_insw(b,p,a,c) (b)->b_ins((b),(p),(a),(c),1) +#define bus_insl(b,p,a,c) (b)->b_ins((b),(p),(a),(c),2) +#define bus_insw_ns(b,p,a,c) (b)->b_ins((b),(p),(a),(c),-1) +#define bus_insl_ns(b,p,a,c) (b)->b_ins((b),(p),(a),(c),-2) + +#define bus_outb(b,v,p) (b)->b_out((b),(v),(p),0) +#define bus_outw(b,v,p) (b)->b_out((b),(v),(p),1) +#define bus_outl(b,v,p) (b)->b_out((b),(v),(p),2) +#define bus_outw_ns(b,v,p) (b)->b_out((b),(v),(p),-1) +#define bus_outl_ns(b,v,p) (b)->b_out((b),(v),(p),-2) + +#define bus_outsb(b,p,a,c) (b)->b_outs((b),(p),(a),(c),0) +#define bus_outsw(b,p,a,c) (b)->b_outs((b),(p),(a),(c),1) +#define bus_outsl(b,p,a,c) (b)->b_outs((b),(p),(a),(c),2) +#define bus_outsw_ns(b,p,a,c) (b)->b_outs((b),(p),(a),(c),-1) +#define bus_outsl_ns(b,p,a,c) (b)->b_outs((b),(p),(a),(c),-2) + +#define bus_readb(b,a) (b)->b_read((b),(a),0) +#define bus_readw(b,a) (b)->b_read((b),(a),1) +#define bus_readl(b,a) (b)->b_read((b),(a),2) +#define bus_readw_ns(b,a) (b)->b_read((b),(a),-1) +#define bus_readl_ns(b,a) (b)->b_read((b),(a),-2) + +#define bus_writeb(b,v,a) (b)->b_write((b),(v),(a),0) +#define bus_writew(b,v,a) (b)->b_write((b),(v),(a),1) +#define bus_writel(b,v,a) (b)->b_write((b),(v),(a),2) +#define bus_writew_ns(b,v,a) (b)->b_write((b),(v),(a),-1) +#define bus_writel_ns(b,v,a) (b)->b_write((b),(v),(a),-2) + +#define bus_ioremap(b,s,n) (b)->b_ioremap((b),(s),(n)) +#define bus_iounmap(b,a) (b)->b_iounmap((b),(a)) +#define bus_memcpy_fromio(b,d,s,n) (b)->b_copy_from((b),(d),(s),(n)) +#define bus_memcpy_toio(b,d,s,n) (b)->b_copy_to((b),(d),(s),(n)) + +#define bus_request_irq(b,i,h,f,n,d) \ + (b)->b_request_irq((b),(i),(h),(f),(n),(d)) +#define bus_free_irq(b,i,d) (b)->b_free_irq((b),(i),(d)) + +#else + +#define bus_inb(b,p) inb(p) +#define bus_inw(b,p) inw(p) +#define bus_inl(b,p) inl(p) +#define bus_inw_ns(b,p) inw_ns(p) +#define bus_inl_ns(b,p) inl_ns(p) + +#define bus_insb(b,p,a,c) insb(p,a,c) +#define bus_insw(b,p,a,c) insw(p,a,c) +#define bus_insl(b,p,a,c) insl(p,a,c) +#define bus_insw_ns(b,p,a,c) insw_ns(p,a,c) +#define bus_insl_ns(b,p,a,c) insl_ns(p,a,c) + +#define bus_outb(b,v,p) outb(b,v,p) +#define bus_outw(b,v,p) outw(b,v,p) +#define bus_outl(b,v,p) outl(b,v,p) +#define bus_outw_ns(b,v,p) outw_ns(b,v,p) +#define bus_outl_ns(b,v,p) outl_ns(b,v,p) + +#define bus_outsb(b,p,a,c) outsb(p,a,c) +#define bus_outsw(b,p,a,c) outsw(p,a,c) +#define bus_outsl(b,p,a,c) outsl(p,a,c) +#define bus_outsw_ns(b,p,a,c) outsw_ns(p,a,c) +#define bus_outsl_ns(b,p,a,c) outsl_ns(p,a,c) + +#define bus_readb(b,a) readb(a) +#define bus_readw(b,a) readw(a) +#define bus_readl(b,a) readl(a) +#define bus_readw_ns(b,a) readw_ns(a) +#define bus_readl_ns(b,a) readl_ns(a) + +#define bus_writeb(b,v,a) writeb(v,a) +#define bus_writew(b,v,a) writew(v,a) +#define bus_writel(b,v,a) writel(v,a) +#define bus_writew_ns(b,v,a) writew_ns(v,a) +#define bus_writel_ns(b,v,a) writel_ns(v,a) + +#define bus_ioremap(b,s,n) ioremap(s,n) +#define bus_iounmap(b,a) iounmap(a) +#define bus_memcpy_fromio(b,d,s,n) memcpy_fromio(d,s,n) +#define bus_memcpy_toio(b,d,s,n) memcpy_toio(d,s,n) + +#define bus_request_irq(b,i,h,f,n,d) request_irq((i),(h),(f),(n),(d)) +#define bus_free_irq(b,i,d) free_irq((i),(d)) + +#endif /* CONFIG_VIRTUAL_BUS */ + +#endif /* _LINUX_BUS_OPS_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/ciscode.h linux/include/pcmcia/ciscode.h --- v2.3.16/linux/include/pcmcia/ciscode.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/ciscode.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,115 @@ +/* + * ciscode.h 1.38 1999/08/28 04:12:32 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CISCODE_H +#define _LINUX_CISCODE_H + +/* Manufacturer and Product ID codes */ + +#define MANFID_3COM 0x0101 +#define PRODID_3COM_3CXEM556 0x0035 +#define PRODID_3COM_3CCFEM556 0x0556 +#define PRODID_3COM_3C562 0x0562 + +#define MANFID_ACCTON 0x01bf +#define PRODID_ACCTON_EN2226 0x010a + +#define MANFID_ADAPTEC 0x012f +#define PRODID_ADAPTEC_SCSI 0x0001 + +#define MANFID_ATT 0xffff +#define PRODID_ATT_KIT 0x0100 + +#define MANFID_CONTEC 0xc001 + +#define MANFID_FUJITSU 0x0004 +#define PRODID_FUJITSU_MBH10302 0x0004 +#define PRODID_FUJITSU_MBH10304 0x1003 +#define PRODID_FUJITSU_LA501 0x2000 + +#define MANFID_IBM 0x00a4 +#define PRODID_IBM_HOME_AND_AWAY 0x002e + +#define MANFID_INTEL 0x0089 +#define PRODID_INTEL_DUAL_RS232 0x0301 +#define PRODID_INTEL_2PLUS 0x8422 + +#define MANFID_LINKSYS 0x0143 +#define PRODID_LINKSYS_PCMLM28 0xc0ab +#define PRODID_LINKSYS_3400 0x3341 + +#define MANFID_MEGAHERTZ 0x0102 +#define PRODID_MEGAHERTZ_VARIOUS 0x0000 +#define PRODID_MEGAHERTZ_EM3288 0x0006 + +#define MANFID_MACNICA 0xc00b + +#define MANFID_MOTOROLA 0x0109 +#define PRODID_MOTOROLA_MARINER 0x0501 + +#define MANFID_NATINST 0x010b +#define PRODID_NATINST_QUAD_RS232 0xd180 + +#define MANFID_NEW_MEDIA 0x0057 + +#define MANFID_OLICOM 0x0121 +#define PRODID_OLICOM_OC2231 0x3122 +#define PRODID_OLICOM_OC2232 0x3222 + +#define MANFID_OMEGA 0x0137 +#define PRODID_OMEGA_QSP_100 0x0025 + +#define MANFID_OSITECH 0x0140 +#define PRODID_OSITECH_JACK_144 0x0001 +#define PRODID_OSITECH_JACK_288 0x0002 +#define PRODID_OSITECH_JACK_336 0x0007 +#define PRODID_OSITECH_SEVEN 0x0008 + +#define MANFID_PSION 0x016c + +#define MANFID_QUATECH 0x0137 +#define PRODID_QUATECH_SPP100 0x0003 +#define PRODID_QUATECH_DUAL_RS232 0x0012 +#define PRODID_QUATECH_DUAL_RS232_D1 0x0007 +#define PRODID_QUATECH_QUAD_RS232 0x001b + +#define MANFID_SMC 0x0108 +#define PRODID_SMC_ETHER 0x0105 + +#define MANFID_SOCKET 0x0104 +#define PRODID_SOCKET_DUAL_RS232 0x0006 +#define PRODID_SOCKET_LPE 0x000d + +#define MANFID_SUNDISK 0x0045 + +#define MANFID_TDK 0x0105 + +#define MANFID_XIRCOM 0x0105 + +#endif /* _LINUX_CISCODE_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/cisreg.h linux/include/pcmcia/cisreg.h --- v2.3.16/linux/include/pcmcia/cisreg.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/cisreg.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,116 @@ +/* + * cisreg.h 1.13 1999/08/28 04:12:32 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CISREG_H +#define _LINUX_CISREG_H + +/* Offsets from ConfigBase for CIS registers */ +#define CISREG_COR 0x00 +#define CISREG_CCSR 0x02 +#define CISREG_PRR 0x04 +#define CISREG_SCR 0x06 +#define CISREG_ESR 0x08 +#define CISREG_IOBASE_0 0x0a +#define CISREG_IOBASE_1 0x0c +#define CISREG_IOBASE_2 0x0e +#define CISREG_IOBASE_3 0x10 +#define CISREG_IOSIZE 0x12 + +/* + * Configuration Option Register + */ +#define COR_CONFIG_MASK 0x3f +#define COR_MFC_CONFIG_MASK 0x38 +#define COR_FUNC_ENA 0x01 +#define COR_ADDR_DECODE 0x02 +#define COR_IREQ_ENA 0x04 +#define COR_LEVEL_REQ 0x40 +#define COR_SOFT_RESET 0x80 + +/* + * Card Configuration and Status Register + */ +#define CCSR_INTR_ACK 0x01 +#define CCSR_INTR_PENDING 0x02 +#define CCSR_POWER_DOWN 0x04 +#define CCSR_AUDIO_ENA 0x08 +#define CCSR_IOIS8 0x20 +#define CCSR_SIGCHG_ENA 0x40 +#define CCSR_CHANGED 0x80 + +/* + * Pin Replacement Register + */ +#define PRR_WP_STATUS 0x01 +#define PRR_READY_STATUS 0x02 +#define PRR_BVD2_STATUS 0x04 +#define PRR_BVD1_STATUS 0x08 +#define PRR_WP_EVENT 0x10 +#define PRR_READY_EVENT 0x20 +#define PRR_BVD2_EVENT 0x40 +#define PRR_BVD1_EVENT 0x80 + +/* + * Socket and Copy Register + */ +#define SCR_SOCKET_NUM 0x0f +#define SCR_COPY_NUM 0x70 + +/* + * Extended Status Register + */ +#define ESR_REQ_ATTN_ENA 0x01 +#define ESR_REQ_ATTN 0x10 + +/* + * CardBus Function Status Registers + */ +#define CBFN_EVENT 0x00 +#define CBFN_MASK 0x04 +#define CBFN_STATE 0x08 +#define CBFN_FORCE 0x0c + +/* + * These apply to all the CardBus function registers + */ +#define CBFN_WP 0x0001 +#define CBFN_READY 0x0002 +#define CBFN_BVD2 0x0004 +#define CBFN_BVD1 0x0008 +#define CBFN_GWAKE 0x0010 +#define CBFN_INTR 0x8000 + +/* + * Extra bits in the Function Event Mask Register + */ +#define FEMR_BAM_ENA 0x0020 +#define FEMR_PWM_ENA 0x0040 +#define FEMR_WKUP_MASK 0x4000 + +#endif /* _LINUX_CISREG_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/cistpl.h linux/include/pcmcia/cistpl.h --- v2.3.16/linux/include/pcmcia/cistpl.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/cistpl.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,583 @@ +/* + * cistpl.h 1.30 1999/08/28 04:12:32 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CISTPL_H +#define _LINUX_CISTPL_H + +#define CISTPL_NULL 0x00 +#define CISTPL_DEVICE 0x01 +#define CISTPL_LONGLINK_CB 0x02 +#define CISTPL_CONFIG_CB 0x04 +#define CISTPL_CFTABLE_ENTRY_CB 0x05 +#define CISTPL_LONGLINK_MFC 0x06 +#define CISTPL_BAR 0x07 +#define CISTPL_CHECKSUM 0x10 +#define CISTPL_LONGLINK_A 0x11 +#define CISTPL_LONGLINK_C 0x12 +#define CISTPL_LINKTARGET 0x13 +#define CISTPL_NO_LINK 0x14 +#define CISTPL_VERS_1 0x15 +#define CISTPL_ALTSTR 0x16 +#define CISTPL_DEVICE_A 0x17 +#define CISTPL_JEDEC_C 0x18 +#define CISTPL_JEDEC_A 0x19 +#define CISTPL_CONFIG 0x1a +#define CISTPL_CFTABLE_ENTRY 0x1b +#define CISTPL_DEVICE_OC 0x1c +#define CISTPL_DEVICE_OA 0x1d +#define CISTPL_DEVICE_GEO 0x1e +#define CISTPL_DEVICE_GEO_A 0x1f +#define CISTPL_MANFID 0x20 +#define CISTPL_FUNCID 0x21 +#define CISTPL_FUNCE 0x22 +#define CISTPL_SWIL 0x23 +#define CISTPL_END 0xff +/* Layer 2 tuples */ +#define CISTPL_VERS_2 0x40 +#define CISTPL_FORMAT 0x41 +#define CISTPL_GEOMETRY 0x42 +#define CISTPL_BYTEORDER 0x43 +#define CISTPL_DATE 0x44 +#define CISTPL_BATTERY 0x45 +/* Layer 3 tuples */ +#define CISTPL_ORG 0x46 + +typedef struct cistpl_longlink_t { + u_int addr; +} cistpl_longlink_t; + +typedef struct cistpl_checksum_t { + u_short addr; + u_short len; + u_char sum; +} cistpl_checksum_t; + +#define CISTPL_MAX_FUNCTIONS 8 +#define CISTPL_MFC_ATTR 0x00 +#define CISTPL_MFC_COMMON 0x01 + +typedef struct cistpl_longlink_mfc_t { + u_char nfn; + struct { + u_char space; + u_int addr; + } fn[CISTPL_MAX_FUNCTIONS]; +} cistpl_longlink_mfc_t; + +#define CISTPL_MAX_ALTSTR_STRINGS 4 + +typedef struct cistpl_altstr_t { + u_char ns; + u_char ofs[CISTPL_MAX_ALTSTR_STRINGS]; + char str[254]; +} cistpl_altstr_t; + +#define CISTPL_DTYPE_NULL 0x00 +#define CISTPL_DTYPE_ROM 0x01 +#define CISTPL_DTYPE_OTPROM 0x02 +#define CISTPL_DTYPE_EPROM 0x03 +#define CISTPL_DTYPE_EEPROM 0x04 +#define CISTPL_DTYPE_FLASH 0x05 +#define CISTPL_DTYPE_SRAM 0x06 +#define CISTPL_DTYPE_DRAM 0x07 +#define CISTPL_DTYPE_FUNCSPEC 0x0d +#define CISTPL_DTYPE_EXTEND 0x0e + +#define CISTPL_MAX_DEVICES 4 + +typedef struct cistpl_device_t { + u_char ndev; + struct { + u_char type; + u_char wp; + u_int speed; + u_int size; + } dev[CISTPL_MAX_DEVICES]; +} cistpl_device_t; + +#define CISTPL_DEVICE_MWAIT 0x01 +#define CISTPL_DEVICE_3VCC 0x02 + +typedef struct cistpl_device_o_t { + u_char flags; + cistpl_device_t device; +} cistpl_device_o_t; + +#define CISTPL_VERS_1_MAX_PROD_STRINGS 4 + +typedef struct cistpl_vers_1_t { + u_char major; + u_char minor; + u_char ns; + u_char ofs[CISTPL_VERS_1_MAX_PROD_STRINGS]; + char str[254]; +} cistpl_vers_1_t; + +typedef struct cistpl_jedec_t { + u_char nid; + struct { + u_char mfr; + u_char info; + } id[CISTPL_MAX_DEVICES]; +} cistpl_jedec_t; + +typedef struct cistpl_manfid_t { + u_short manf; + u_short card; +} cistpl_manfid_t; + +#define CISTPL_FUNCID_MULTI 0x00 +#define CISTPL_FUNCID_MEMORY 0x01 +#define CISTPL_FUNCID_SERIAL 0x02 +#define CISTPL_FUNCID_PARALLEL 0x03 +#define CISTPL_FUNCID_FIXED 0x04 +#define CISTPL_FUNCID_VIDEO 0x05 +#define CISTPL_FUNCID_NETWORK 0x06 +#define CISTPL_FUNCID_AIMS 0x07 +#define CISTPL_FUNCID_SCSI 0x08 + +#define CISTPL_SYSINIT_POST 0x01 +#define CISTPL_SYSINIT_ROM 0x02 + +typedef struct cistpl_funcid_t { + u_char func; + u_char sysinit; +} cistpl_funcid_t; + +typedef struct cistpl_funce_t { + u_char type; + u_char data[0]; +} cistpl_funce_t; + +/*====================================================================== + + Modem Function Extension Tuples + +======================================================================*/ + +#define CISTPL_FUNCE_SERIAL_IF 0x00 +#define CISTPL_FUNCE_SERIAL_CAP 0x01 +#define CISTPL_FUNCE_SERIAL_SERV_DATA 0x02 +#define CISTPL_FUNCE_SERIAL_SERV_FAX 0x03 +#define CISTPL_FUNCE_SERIAL_SERV_VOICE 0x04 +#define CISTPL_FUNCE_SERIAL_CAP_DATA 0x05 +#define CISTPL_FUNCE_SERIAL_CAP_FAX 0x06 +#define CISTPL_FUNCE_SERIAL_CAP_VOICE 0x07 +#define CISTPL_FUNCE_SERIAL_IF_DATA 0x08 +#define CISTPL_FUNCE_SERIAL_IF_FAX 0x09 +#define CISTPL_FUNCE_SERIAL_IF_VOICE 0x0a + +/* UART identification */ +#define CISTPL_SERIAL_UART_8250 0x00 +#define CISTPL_SERIAL_UART_16450 0x01 +#define CISTPL_SERIAL_UART_16550 0x02 +#define CISTPL_SERIAL_UART_8251 0x03 +#define CISTPL_SERIAL_UART_8530 0x04 +#define CISTPL_SERIAL_UART_85230 0x05 + +/* UART capabilities */ +#define CISTPL_SERIAL_UART_SPACE 0x01 +#define CISTPL_SERIAL_UART_MARK 0x02 +#define CISTPL_SERIAL_UART_ODD 0x04 +#define CISTPL_SERIAL_UART_EVEN 0x08 +#define CISTPL_SERIAL_UART_5BIT 0x01 +#define CISTPL_SERIAL_UART_6BIT 0x02 +#define CISTPL_SERIAL_UART_7BIT 0x04 +#define CISTPL_SERIAL_UART_8BIT 0x08 +#define CISTPL_SERIAL_UART_1STOP 0x10 +#define CISTPL_SERIAL_UART_MSTOP 0x20 +#define CISTPL_SERIAL_UART_2STOP 0x40 + +typedef struct cistpl_serial_t { + u_char uart_type; + u_char uart_cap_0; + u_char uart_cap_1; +} cistpl_serial_t; + +typedef struct cistpl_modem_cap_t { + u_char flow; + u_char cmd_buf; + u_char rcv_buf_0, rcv_buf_1, rcv_buf_2; + u_char xmit_buf_0, xmit_buf_1, xmit_buf_2; +} cistpl_modem_cap_t; + +#define CISTPL_SERIAL_MOD_103 0x01 +#define CISTPL_SERIAL_MOD_V21 0x02 +#define CISTPL_SERIAL_MOD_V23 0x04 +#define CISTPL_SERIAL_MOD_V22 0x08 +#define CISTPL_SERIAL_MOD_212A 0x10 +#define CISTPL_SERIAL_MOD_V22BIS 0x20 +#define CISTPL_SERIAL_MOD_V26 0x40 +#define CISTPL_SERIAL_MOD_V26BIS 0x80 +#define CISTPL_SERIAL_MOD_V27BIS 0x01 +#define CISTPL_SERIAL_MOD_V29 0x02 +#define CISTPL_SERIAL_MOD_V32 0x04 +#define CISTPL_SERIAL_MOD_V32BIS 0x08 +#define CISTPL_SERIAL_MOD_V34 0x10 + +#define CISTPL_SERIAL_ERR_MNP2_4 0x01 +#define CISTPL_SERIAL_ERR_V42_LAPM 0x02 + +#define CISTPL_SERIAL_CMPR_V42BIS 0x01 +#define CISTPL_SERIAL_CMPR_MNP5 0x02 + +#define CISTPL_SERIAL_CMD_AT1 0x01 +#define CISTPL_SERIAL_CMD_AT2 0x02 +#define CISTPL_SERIAL_CMD_AT3 0x04 +#define CISTPL_SERIAL_CMD_MNP_AT 0x08 +#define CISTPL_SERIAL_CMD_V25BIS 0x10 +#define CISTPL_SERIAL_CMD_V25A 0x20 +#define CISTPL_SERIAL_CMD_DMCL 0x40 + +typedef struct cistpl_data_serv_t { + u_char max_data_0; + u_char max_data_1; + u_char modulation_0; + u_char modulation_1; + u_char error_control; + u_char compression; + u_char cmd_protocol; + u_char escape; + u_char encrypt; + u_char misc_features; + u_char ccitt_code[0]; +} cistpl_data_serv_t; + +typedef struct cistpl_fax_serv_t { + u_char max_data_0; + u_char max_data_1; + u_char modulation; + u_char encrypt; + u_char features_0; + u_char features_1; + u_char ccitt_code[0]; +} cistpl_fax_serv_t; + +typedef struct cistpl_voice_serv_t { + u_char max_data_0; + u_char max_data_1; +} cistpl_voice_serv_t; + +/*====================================================================== + + LAN Function Extension Tuples + +======================================================================*/ + +#define CISTPL_FUNCE_LAN_TECH 0x01 +#define CISTPL_FUNCE_LAN_SPEED 0x02 +#define CISTPL_FUNCE_LAN_MEDIA 0x03 +#define CISTPL_FUNCE_LAN_NODE_ID 0x04 +#define CISTPL_FUNCE_LAN_CONNECTOR 0x05 + +/* LAN technologies */ +#define CISTPL_LAN_TECH_ARCNET 0x01 +#define CISTPL_LAN_TECH_ETHERNET 0x02 +#define CISTPL_LAN_TECH_TOKENRING 0x03 +#define CISTPL_LAN_TECH_LOCALTALK 0x04 +#define CISTPL_LAN_TECH_FDDI 0x05 +#define CISTPL_LAN_TECH_ATM 0x06 +#define CISTPL_LAN_TECH_WIRELESS 0x07 + +typedef struct cistpl_lan_tech_t { + u_char tech; +} cistpl_lan_tech_t; + +typedef struct cistpl_lan_speed_t { + u_int speed; +} cistpl_lan_speed_t; + +/* LAN media definitions */ +#define CISTPL_LAN_MEDIA_UTP 0x01 +#define CISTPL_LAN_MEDIA_STP 0x02 +#define CISTPL_LAN_MEDIA_THIN_COAX 0x03 +#define CISTPL_LAN_MEDIA_THICK_COAX 0x04 +#define CISTPL_LAN_MEDIA_FIBER 0x05 +#define CISTPL_LAN_MEDIA_900MHZ 0x06 +#define CISTPL_LAN_MEDIA_2GHZ 0x07 +#define CISTPL_LAN_MEDIA_5GHZ 0x08 +#define CISTPL_LAN_MEDIA_DIFF_IR 0x09 +#define CISTPL_LAN_MEDIA_PTP_IR 0x0a + +typedef struct cistpl_lan_media_t { + u_char media; +} cistpl_lan_media_t; + +typedef struct cistpl_lan_node_id_t { + u_char nb; + u_char id[16]; +} cistpl_lan_node_id_t; + +typedef struct cistpl_lan_connector_t { + u_char code; +} cistpl_lan_connector_t; + +/*====================================================================== + + IDE Function Extension Tuples + +======================================================================*/ + +#define CISTPL_IDE_INTERFACE 0x01 + +typedef struct cistpl_ide_interface_t { + u_char interface; +} cistpl_ide_interface_t; + +/* First feature byte */ +#define CISTPL_IDE_SILICON 0x04 +#define CISTPL_IDE_UNIQUE 0x08 +#define CISTPL_IDE_DUAL 0x10 + +/* Second feature byte */ +#define CISTPL_IDE_HAS_SLEEP 0x01 +#define CISTPL_IDE_HAS_STANDBY 0x02 +#define CISTPL_IDE_HAS_IDLE 0x04 +#define CISTPL_IDE_LOW_POWER 0x08 +#define CISTPL_IDE_REG_INHIBIT 0x10 +#define CISTPL_IDE_HAS_INDEX 0x20 +#define CISTPL_IDE_IOIS16 0x40 + +typedef struct cistpl_ide_feature_t { + u_char feature1; + u_char feature2; +} cistpl_ide_feature_t; + +#define CISTPL_FUNCE_IDE_IFACE 0x01 +#define CISTPL_FUNCE_IDE_MASTER 0x02 +#define CISTPL_FUNCE_IDE_SLAVE 0x03 + +/*====================================================================== + + Configuration Table Entries + +======================================================================*/ + +#define CISTPL_BAR_SPACE 0x07 +#define CISTPL_BAR_SPACE_IO 0x10 +#define CISTPL_BAR_PREFETCH 0x20 +#define CISTPL_BAR_CACHEABLE 0x40 +#define CISTPL_BAR_1MEG_MAP 0x80 + +typedef struct cistpl_bar_t { + u_char attr; + u_int size; +} cistpl_bar_t; + +typedef struct cistpl_config_t { + u_char last_idx; + u_int base; + u_int rmask[4]; + u_char subtuples; +} cistpl_config_t; + +/* These are bits in the 'present' field, and indices in 'param' */ +#define CISTPL_POWER_VNOM 0 +#define CISTPL_POWER_VMIN 1 +#define CISTPL_POWER_VMAX 2 +#define CISTPL_POWER_ISTATIC 3 +#define CISTPL_POWER_IAVG 4 +#define CISTPL_POWER_IPEAK 5 +#define CISTPL_POWER_IDOWN 6 + +#define CISTPL_POWER_HIGHZ_OK 0x01 +#define CISTPL_POWER_HIGHZ_REQ 0x02 + +typedef struct cistpl_power_t { + u_char present; + u_char flags; + u_int param[7]; +} cistpl_power_t; + +typedef struct cistpl_timing_t { + u_int wait, waitscale; + u_int ready, rdyscale; + u_int reserved, rsvscale; +} cistpl_timing_t; + +#define CISTPL_IO_LINES_MASK 0x1f +#define CISTPL_IO_8BIT 0x20 +#define CISTPL_IO_16BIT 0x40 +#define CISTPL_IO_RANGE 0x80 + +#define CISTPL_IO_MAX_WIN 16 + +typedef struct cistpl_io_t { + u_char flags; + u_char nwin; + struct { + u_int base; + u_int len; + } win[CISTPL_IO_MAX_WIN]; +} cistpl_io_t; + +typedef struct cistpl_irq_t { + u_int IRQInfo1; + u_int IRQInfo2; +} cistpl_irq_t; + +#define CISTPL_MEM_MAX_WIN 8 + +typedef struct cistpl_mem_t { + u_char flags; + u_char nwin; + struct { + u_int len; + u_int card_addr; + u_int host_addr; + } win[CISTPL_MEM_MAX_WIN]; +} cistpl_mem_t; + +#define CISTPL_CFTABLE_DEFAULT 0x0001 +#define CISTPL_CFTABLE_BVDS 0x0002 +#define CISTPL_CFTABLE_WP 0x0004 +#define CISTPL_CFTABLE_RDYBSY 0x0008 +#define CISTPL_CFTABLE_MWAIT 0x0010 +#define CISTPL_CFTABLE_AUDIO 0x0800 +#define CISTPL_CFTABLE_READONLY 0x1000 +#define CISTPL_CFTABLE_PWRDOWN 0x2000 + +typedef struct cistpl_cftable_entry_t { + u_char index; + u_short flags; + u_char interface; + cistpl_power_t vcc, vpp1, vpp2; + cistpl_timing_t timing; + cistpl_io_t io; + cistpl_irq_t irq; + cistpl_mem_t mem; + u_char subtuples; +} cistpl_cftable_entry_t; + +#define CISTPL_CFTABLE_MASTER 0x000100 +#define CISTPL_CFTABLE_INVALIDATE 0x000200 +#define CISTPL_CFTABLE_VGA_PALETTE 0x000400 +#define CISTPL_CFTABLE_PARITY 0x000800 +#define CISTPL_CFTABLE_WAIT 0x001000 +#define CISTPL_CFTABLE_SERR 0x002000 +#define CISTPL_CFTABLE_FAST_BACK 0x004000 +#define CISTPL_CFTABLE_BINARY_AUDIO 0x010000 +#define CISTPL_CFTABLE_PWM_AUDIO 0x020000 + +typedef struct cistpl_cftable_entry_cb_t { + u_char index; + u_int flags; + cistpl_power_t vcc, vpp1, vpp2; + u_char io; + cistpl_irq_t irq; + u_char mem; + u_char subtuples; +} cistpl_cftable_entry_cb_t; + +typedef struct cistpl_device_geo_t { + u_char ngeo; + struct { + u_char buswidth; + u_int erase_block; + u_int read_block; + u_int write_block; + u_int partition; + u_int interleave; + } geo[CISTPL_MAX_DEVICES]; +} cistpl_device_geo_t; + +typedef struct cistpl_vers_2_t { + u_char vers; + u_char comply; + u_short dindex; + u_char vspec8, vspec9; + u_char nhdr; + u_char vendor, info; + char str[244]; +} cistpl_vers_2_t; + +typedef struct cistpl_org_t { + u_char data_org; + char desc[30]; +} cistpl_org_t; + +#define CISTPL_ORG_FS 0x00 +#define CISTPL_ORG_APPSPEC 0x01 +#define CISTPL_ORG_XIP 0x02 + +typedef union cisparse_t { + cistpl_device_t device; + cistpl_checksum_t checksum; + cistpl_longlink_t longlink; + cistpl_longlink_mfc_t longlink_mfc; + cistpl_vers_1_t version_1; + cistpl_altstr_t altstr; + cistpl_jedec_t jedec; + cistpl_manfid_t manfid; + cistpl_funcid_t funcid; + cistpl_funce_t funce; + cistpl_bar_t bar; + cistpl_config_t config; + cistpl_cftable_entry_t cftable_entry; + cistpl_cftable_entry_cb_t cftable_entry_cb; + cistpl_device_geo_t device_geo; + cistpl_vers_2_t vers_2; + cistpl_org_t org; +} cisparse_t; + +typedef struct tuple_t { + u_int Attributes; + cisdata_t DesiredTuple; + u_int Flags; /* internal use */ + u_int LinkOffset; /* internal use */ + u_int CISOffset; /* internal use */ + cisdata_t TupleCode; + cisdata_t TupleLink; + cisdata_t TupleOffset; + cisdata_t TupleDataMax; + cisdata_t TupleDataLen; + cisdata_t *TupleData; +} tuple_t; + +/* Special cisdata_t value */ +#define RETURN_FIRST_TUPLE 0xff + +/* Attributes for tuple calls */ +#define TUPLE_RETURN_LINK 0x01 +#define TUPLE_RETURN_COMMON 0x02 + +/* For ValidateCIS */ +typedef struct cisinfo_t { + u_int Chains; +} cisinfo_t; + +#define CISTPL_MAX_CIS_SIZE 0x200 + +/* For ReplaceCIS */ +typedef struct cisdump_t { + u_int Length; + cisdata_t Data[CISTPL_MAX_CIS_SIZE]; +} cisdump_t; + +#endif /* LINUX_CISTPL_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/cs.h linux/include/pcmcia/cs.h --- v2.3.16/linux/include/pcmcia/cs.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/cs.h Tue Sep 7 11:46:55 1999 @@ -0,0 +1,468 @@ +/* + * cs.h 1.67 1999/09/02 18:34:59 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CS_H +#define _LINUX_CS_H + +/* For AccessConfigurationRegister */ +typedef struct conf_reg_t { + u_char Function; + u_int Action; + off_t Offset; + u_int Value; +} conf_reg_t; + +/* Actions */ +#define CS_READ 1 +#define CS_WRITE 2 + +/* for AdjustResourceInfo */ +typedef struct adjust_t { + u_int Action; + u_int Resource; + u_int Attributes; + union { + struct memory { + u_long Base; + u_long Size; + } memory; + struct io { + ioaddr_t BasePort; + ioaddr_t NumPorts; + u_int IOAddrLines; + } io; + struct irq { + u_int IRQ; + } irq; + } resource; +} adjust_t; + +/* Action field */ +#define REMOVE_MANAGED_RESOURCE 1 +#define ADD_MANAGED_RESOURCE 2 +#define GET_FIRST_MANAGED_RESOURCE 3 +#define GET_NEXT_MANAGED_RESOURCE 4 +/* Resource field */ +#define RES_MEMORY_RANGE 1 +#define RES_IO_RANGE 2 +#define RES_IRQ 3 +/* Attribute field */ +#define RES_IRQ_TYPE 0x03 +#define RES_IRQ_TYPE_EXCLUSIVE 0 +#define RES_IRQ_TYPE_TIME 1 +#define RES_IRQ_TYPE_DYNAMIC 2 +#define RES_IRQ_CSC 0x04 +#define RES_SHARED 0x08 +#define RES_RESERVED 0x10 +#define RES_ALLOCATED 0x20 +#define RES_REMOVED 0x40 + +typedef struct servinfo_t { + char Signature[2]; + u_int Count; + u_int Revision; + u_int CSLevel; + char *VendorString; +} servinfo_t; + +typedef struct event_callback_args_t { + client_handle_t client_handle; + void *info; + void *mtdrequest; + void *buffer; + void *misc; + void *client_data; + struct bus_operations *bus; +} event_callback_args_t; + +/* for GetConfigurationInfo */ +typedef struct config_info_t { + u_char Function; + u_int Attributes; + u_int Vcc, Vpp1, Vpp2; + u_int IntType; + u_int ConfigBase; + u_char Status, Pin, Copy, Option, ExtStatus; + u_int Present; + u_int CardValues; + u_int AssignedIRQ; + u_int IRQAttributes; + ioaddr_t BasePort1; + ioaddr_t NumPorts1; + u_int Attributes1; + ioaddr_t BasePort2; + ioaddr_t NumPorts2; + u_int Attributes2; + u_int IOAddrLines; +} config_info_t; + +/* For CardValues field */ +#define CV_OPTION_VALUE 0x01 +#define CV_STATUS_VALUE 0x02 +#define CV_PIN_REPLACEMENT 0x04 +#define CV_COPY_VALUE 0x08 +#define CV_EXT_STATUS 0x10 + +/* For GetFirst/NextClient */ +typedef struct client_req_t { + socket_t Socket; + u_int Attributes; +} client_req_t; + +#define CLIENT_THIS_SOCKET 0x01 + +/* For RegisterClient */ +typedef struct client_reg_t { + dev_info_t *dev_info; + u_int Attributes; + u_int EventMask; + int (*event_handler)(event_t event, int priority, + event_callback_args_t *); + event_callback_args_t event_callback_args; + u_int Version; +} client_reg_t; + +/* ModifyConfiguration */ +typedef struct modconf_t { + u_int Attributes; + u_int Vcc, Vpp1, Vpp2; +} modconf_t; + +/* Attributes for ModifyConfiguration */ +#define CONF_IRQ_CHANGE_VALID 0x100 +#define CONF_VCC_CHANGE_VALID 0x200 +#define CONF_VPP1_CHANGE_VALID 0x400 +#define CONF_VPP2_CHANGE_VALID 0x800 + +/* For RequestConfiguration */ +typedef struct config_req_t { + u_int Attributes; + u_int Vcc, Vpp1, Vpp2; + u_int IntType; + u_int ConfigBase; + u_char Status, Pin, Copy, ExtStatus; + u_char ConfigIndex; + u_int Present; +} config_req_t; + +/* Attributes for RequestConfiguration */ +#define CONF_ENABLE_IRQ 0x01 +#define CONF_ENABLE_DMA 0x02 +#define CONF_ENABLE_SPKR 0x04 +#define CONF_VALID_CLIENT 0x100 + +/* IntType field */ +#define INT_MEMORY 0x01 +#define INT_MEMORY_AND_IO 0x02 +#define INT_CARDBUS 0x04 + +/* For RequestIO and ReleaseIO */ +typedef struct io_req_t { + ioaddr_t BasePort1; + ioaddr_t NumPorts1; + u_int Attributes1; + ioaddr_t BasePort2; + ioaddr_t NumPorts2; + u_int Attributes2; + u_int IOAddrLines; +} io_req_t; + +/* Attributes for RequestIO and ReleaseIO */ +#define IO_SHARED 0x01 +#define IO_FIRST_SHARED 0x02 +#define IO_FORCE_ALIAS_ACCESS 0x04 +#define IO_DATA_PATH_WIDTH 0x18 +#define IO_DATA_PATH_WIDTH_8 0x00 +#define IO_DATA_PATH_WIDTH_16 0x08 +#define IO_DATA_PATH_WIDTH_AUTO 0x10 + +/* For RequestIRQ and ReleaseIRQ */ +typedef struct irq_req_t { + u_int Attributes; + u_int AssignedIRQ; + u_int IRQInfo1, IRQInfo2; + void *Handler; + void *Instance; +} irq_req_t; + +/* Attributes for RequestIRQ and ReleaseIRQ */ +#define IRQ_TYPE 0x03 +#define IRQ_TYPE_EXCLUSIVE 0x00 +#define IRQ_TYPE_TIME 0x01 +#define IRQ_TYPE_DYNAMIC_SHARING 0x02 +#define IRQ_FORCED_PULSE 0x04 +#define IRQ_FIRST_SHARED 0x08 +#define IRQ_HANDLE_PRESENT 0x10 +#define IRQ_PULSE_ALLOCATED 0x100 + +/* Bits in IRQInfo1 field */ +#define IRQ_MASK 0x0f +#define IRQ_NMI_ID 0x01 +#define IRQ_IOCK_ID 0x02 +#define IRQ_BERR_ID 0x04 +#define IRQ_VEND_ID 0x08 +#define IRQ_INFO2_VALID 0x10 +#define IRQ_LEVEL_ID 0x20 +#define IRQ_PULSE_ID 0x40 +#define IRQ_SHARE_ID 0x80 + +typedef struct eventmask_t { + u_int Attributes; + u_int EventMask; +} eventmask_t; + +#define CONF_EVENT_MASK_VALID 0x01 + +/* Configuration registers present */ +#define PRESENT_OPTION 0x001 +#define PRESENT_STATUS 0x002 +#define PRESENT_PIN_REPLACE 0x004 +#define PRESENT_COPY 0x008 +#define PRESENT_EXT_STATUS 0x010 +#define PRESENT_IOBASE_0 0x020 +#define PRESENT_IOBASE_1 0x040 +#define PRESENT_IOBASE_2 0x080 +#define PRESENT_IOBASE_3 0x100 +#define PRESENT_IOSIZE 0x200 + +/* Attributes for Request/GetConfiguration */ +#define CONF_ENABLE_IRQ 0x01 +#define EXCLUSIVE_USE 0x02 +#define VALID_CLIENT 0x04 + +/* For GetMemPage, MapMemPage */ +typedef struct memreq_t { + u_int CardOffset; + page_t Page; +} memreq_t; + +/* For ModifyWindow */ +typedef struct modwin_t { + u_int Attributes; + u_int AccessSpeed; +} modwin_t; + +/* For RequestWindow */ +typedef struct win_req_t { + u_int Attributes; + u_long Base; + u_int Size; + u_int AccessSpeed; +} win_req_t; + +/* Attributes for RequestWindow */ +#define WIN_ADDR_SPACE 0x0001 +#define WIN_ADDR_SPACE_MEM 0x0000 +#define WIN_ADDR_SPACE_IO 0x0001 +#define WIN_MEMORY_TYPE 0x0002 +#define WIN_MEMORY_TYPE_CM 0x0000 +#define WIN_MEMORY_TYPE_AM 0x0002 +#define WIN_ENABLE 0x0004 +#define WIN_DATA_WIDTH 0x0018 +#define WIN_DATA_WIDTH_8 0x0000 +#define WIN_DATA_WIDTH_16 0x0008 +#define WIN_DATA_WIDTH_32 0x0010 +#define WIN_PAGED 0x0020 +#define WIN_SHARED 0x0040 +#define WIN_FIRST_SHARED 0x0080 +#define WIN_USE_WAIT 0x0100 +#define WIN_MAP_BELOW_1MB 0x0400 +#define WIN_PREFETCH 0x0800 +#define WIN_CACHEABLE 0x1000 +#define WIN_BAR_MASK 0xe000 +#define WIN_BAR_SHIFT 13 + +/* Attributes for RegisterClient */ +#define INFO_MASTER_CLIENT 0x01 +#define INFO_IO_CLIENT 0x02 +#define INFO_MTD_CLIENT 0x04 +#define INFO_MEM_CLIENT 0x08 +#define MAX_NUM_CLIENTS 3 + +#define INFO_CARD_SHARE 0x10 +#define INFO_CARD_EXCL 0x20 + +typedef struct cs_status_t { + u_char Function; + event_t CardState; + event_t SocketState; +} cs_status_t; + +typedef struct error_info_t { + int func; + int retcode; +} error_info_t; + +/* Special stuff for binding drivers to sockets */ +typedef struct bind_req_t { + socket_t Socket; + u_char Function; + dev_info_t *dev_info; +} bind_req_t; + +/* Flag to bind to all functions */ +#define BIND_FN_ALL 0xff + +typedef struct mtd_bind_t { + socket_t Socket; + u_int Attributes; + u_int CardOffset; + dev_info_t *dev_info; +} mtd_bind_t; + +/* Events */ +#define CS_EVENT_PRI_LOW 0 +#define CS_EVENT_PRI_HIGH 1 + +#define CS_EVENT_WRITE_PROTECT 0x000001 +#define CS_EVENT_CARD_LOCK 0x000002 +#define CS_EVENT_CARD_INSERTION 0x000004 +#define CS_EVENT_CARD_REMOVAL 0x000008 +#define CS_EVENT_BATTERY_DEAD 0x000010 +#define CS_EVENT_BATTERY_LOW 0x000020 +#define CS_EVENT_READY_CHANGE 0x000040 +#define CS_EVENT_CARD_DETECT 0x000080 +#define CS_EVENT_RESET_REQUEST 0x000100 +#define CS_EVENT_RESET_PHYSICAL 0x000200 +#define CS_EVENT_CARD_RESET 0x000400 +#define CS_EVENT_REGISTRATION_COMPLETE 0x000800 +#define CS_EVENT_RESET_COMPLETE 0x001000 +#define CS_EVENT_PM_SUSPEND 0x002000 +#define CS_EVENT_PM_RESUME 0x004000 +#define CS_EVENT_INSERTION_REQUEST 0x008000 +#define CS_EVENT_EJECTION_REQUEST 0x010000 +#define CS_EVENT_MTD_REQUEST 0x020000 +#define CS_EVENT_ERASE_COMPLETE 0x040000 +#define CS_EVENT_REQUEST_ATTENTION 0x080000 +#define CS_EVENT_CB_DETECT 0x100000 +#define CS_EVENT_3VCARD 0x200000 +#define CS_EVENT_XVCARD 0x400000 + +/* Return codes */ +#define CS_SUCCESS 0x00 +#define CS_BAD_ADAPTER 0x01 +#define CS_BAD_ATTRIBUTE 0x02 +#define CS_BAD_BASE 0x03 +#define CS_BAD_EDC 0x04 +#define CS_BAD_IRQ 0x06 +#define CS_BAD_OFFSET 0x07 +#define CS_BAD_PAGE 0x08 +#define CS_READ_FAILURE 0x09 +#define CS_BAD_SIZE 0x0a +#define CS_BAD_SOCKET 0x0b +#define CS_BAD_TYPE 0x0d +#define CS_BAD_VCC 0x0e +#define CS_BAD_VPP 0x0f +#define CS_BAD_WINDOW 0x11 +#define CS_WRITE_FAILURE 0x12 +#define CS_NO_CARD 0x14 +#define CS_UNSUPPORTED_FUNCTION 0x15 +#define CS_UNSUPPORTED_MODE 0x16 +#define CS_BAD_SPEED 0x17 +#define CS_BUSY 0x18 +#define CS_GENERAL_FAILURE 0x19 +#define CS_WRITE_PROTECTED 0x1a +#define CS_BAD_ARG_LENGTH 0x1b +#define CS_BAD_ARGS 0x1c +#define CS_CONFIGURATION_LOCKED 0x1d +#define CS_IN_USE 0x1e +#define CS_NO_MORE_ITEMS 0x1f +#define CS_OUT_OF_RESOURCE 0x20 +#define CS_BAD_HANDLE 0x21 + +#define CS_BAD_TUPLE 0x40 + +#ifdef __KERNEL__ + +/* + * Calls to set up low-level "Socket Services" drivers + */ + +typedef int (*ss_entry_t)(u_int sock, u_int cmd, void *arg); +extern int register_ss_entry(int nsock, ss_entry_t entry); +extern void unregister_ss_entry(ss_entry_t entry); + +/* + * The main Card Services entry point + */ + +enum service { + AccessConfigurationRegister, AddSocketServices, + AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory, + DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo, + GetClientInfo, GetConfigurationInfo, GetEventMask, + GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple, + GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple, + GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage, + MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow, + OpenMemory, ParseTuple, ReadMemory, RegisterClient, + RegisterEraseQueue, RegisterMTD, RegisterTimer, + ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ, + ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices, + RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ, + RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry, + SetEventMask, SetRegion, ValidateCIS, VendorSpecific, + WriteMemory, BindDevice, BindMTD, ReportError, + SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS, + GetFirstWindow, GetNextWindow, GetMemPage +}; + +#ifdef IN_CARD_SERVICES +extern int CardServices(int func, void *a1, void *a2, void *a3); +#else +extern int CardServices(int func, ...); +#endif + +#ifdef __BEOS__ +#define SS_MODULE_NAME(s) ("busses/pcmcia/" s "/v1") +#define MTD_MODULE_NAME(s) ("busses/pcmcia/" s "/v1") +#define CS_CLIENT_MODULE_NAME "bus_managers/pcmcia_cs/client/v1" +typedef struct cs_client_module_info { + bus_manager_info binfo; + int (*_CardServices)(int, ...); + int (*_MTDHelperEntry)(int, ...); + void (*_add_timer)(struct timer_list *); + void (*_del_timer)(struct timer_list *); +} cs_client_module_info; +#define CS_SOCKET_MODULE_NAME "bus_managers/pcmcia_cs/socket/v1" +typedef struct cs_socket_module_info { + bus_manager_info binfo; + int (*_register_ss_entry)(int, ss_entry_t); + void (*_unregister_ss_entry)(ss_entry_t); + void (*_add_timer)(struct timer_list *); + void (*_del_timer)(struct timer_list *); + int (*register_resource)(int, u_long, u_long); + int (*release_resource)(int, u_long, u_long); + int (*check_resource)(int, u_long, u_long); +} cs_socket_module_info; +#endif + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_CS_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/cs_types.h linux/include/pcmcia/cs_types.h --- v2.3.16/linux/include/pcmcia/cs_types.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/cs_types.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,61 @@ +/* + * cs_types.h 1.15 1999/08/28 04:12:32 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CS_TYPES_H +#define _LINUX_CS_TYPES_H + +#ifdef __linux__ +#include +#endif + +typedef u_short socket_t; +typedef u_short ioaddr_t; +typedef u_int event_t; +typedef u_char cisdata_t; +typedef u_short page_t; + +struct client_t; +typedef struct client_t *client_handle_t; + +struct window_t; +typedef struct window_t *window_handle_t; + +struct region_t; +typedef struct region_t *memory_handle_t; + +struct eraseq_t; +typedef struct eraseq_t *eraseq_handle_t; + +#ifndef DEV_NAME_LEN +#define DEV_NAME_LEN 32 +#endif + +typedef char dev_info_t[DEV_NAME_LEN]; + +#endif /* _LINUX_CS_TYPES_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/driver_ops.h linux/include/pcmcia/driver_ops.h --- v2.3.16/linux/include/pcmcia/driver_ops.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/driver_ops.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,82 @@ +/* + * driver_ops.h 1.13 1999/08/28 04:12:33 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_DRIVER_OPS_H +#define _LINUX_DRIVER_OPS_H + +#ifndef DEV_NAME_LEN +#define DEV_NAME_LEN 32 +#endif + +#ifdef __KERNEL__ + +typedef struct dev_node_t { + char dev_name[DEV_NAME_LEN]; + u_short major, minor; + struct dev_node_t *next; +} dev_node_t; + +typedef struct dev_locator_t { + enum { LOC_ISA, LOC_PCI } bus; + union { + struct { + u_short io_base_1, io_base_2; + u_long mem_base; + u_char irq, dma; + } isa; + struct { + u_char bus; + u_char devfn; + } pci; + } b; +} dev_locator_t; + +typedef struct driver_operations { + char *name; + dev_node_t *(*attach) (dev_locator_t *loc); + void (*suspend) (dev_node_t *dev); + void (*resume) (dev_node_t *dev); + void (*detach) (dev_node_t *dev); +} driver_operations; + +int register_driver(struct driver_operations *ops); +void unregister_driver(struct driver_operations *ops); + +#ifdef __BEOS__ +#define CB_ENABLER_MODULE_NAME "bus_managers/cb_enabler/v1" +typedef struct cb_enabler_module_info { + bus_manager_info binfo; + int (*register_driver)(struct driver_operations *ops); + void (*unregister_driver)(struct driver_operations *ops); +} cb_enabler_module_info; +#endif /* __BEOS__ */ + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_DRIVER_OPS_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/ds.h linux/include/pcmcia/ds.h --- v2.3.16/linux/include/pcmcia/ds.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/ds.h Tue Sep 7 11:46:55 1999 @@ -0,0 +1,163 @@ +/* + * ds.h 1.54 1999/09/03 16:44:49 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_DS_H +#define _LINUX_DS_H + +#include +#include + +typedef struct tuple_parse_t { + tuple_t tuple; + cisdata_t data[255]; + cisparse_t parse; +} tuple_parse_t; + +typedef struct win_info_t { + window_handle_t handle; + win_req_t window; + memreq_t map; +} win_info_t; + +typedef struct bind_info_t { + dev_info_t dev_info; + u_char function; + struct dev_link_t *instance; + char name[DEV_NAME_LEN]; + u_short major, minor; + void *next; +} bind_info_t; + +typedef struct mtd_info_t { + dev_info_t dev_info; + u_int Attributes; + u_int CardOffset; +} mtd_info_t; + +typedef union ds_ioctl_arg_t { + servinfo_t servinfo; + adjust_t adjust; + config_info_t config; + tuple_t tuple; + tuple_parse_t tuple_parse; + client_req_t client_req; + cs_status_t status; + conf_reg_t conf_reg; + cisinfo_t cisinfo; + region_info_t region; + bind_info_t bind_info; + mtd_info_t mtd_info; + win_info_t win_info; + cisdump_t cisdump; +} ds_ioctl_arg_t; + +#define DS_GET_CARD_SERVICES_INFO _IOR ('d', 1, servinfo_t) +#define DS_ADJUST_RESOURCE_INFO _IOWR('d', 2, adjust_t) +#define DS_GET_CONFIGURATION_INFO _IOWR('d', 3, config_info_t) +#define DS_GET_FIRST_TUPLE _IOWR('d', 4, tuple_t) +#define DS_GET_NEXT_TUPLE _IOWR('d', 5, tuple_t) +#define DS_GET_TUPLE_DATA _IOWR('d', 6, tuple_parse_t) +#define DS_PARSE_TUPLE _IOWR('d', 7, tuple_parse_t) +#define DS_RESET_CARD _IO ('d', 8) +#define DS_GET_STATUS _IOWR('d', 9, cs_status_t) +#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t) +#define DS_VALIDATE_CIS _IOR ('d', 11, cisinfo_t) +#define DS_SUSPEND_CARD _IO ('d', 12) +#define DS_RESUME_CARD _IO ('d', 13) +#define DS_EJECT_CARD _IO ('d', 14) +#define DS_INSERT_CARD _IO ('d', 15) +#define DS_GET_FIRST_REGION _IOWR('d', 16, region_info_t) +#define DS_GET_NEXT_REGION _IOWR('d', 17, region_info_t) +#define DS_REPLACE_CIS _IOWR('d', 18, cisdump_t) +#define DS_GET_FIRST_WINDOW _IOR ('d', 19, win_info_t) +#define DS_GET_NEXT_WINDOW _IOWR('d', 20, win_info_t) +#define DS_GET_MEM_PAGE _IOWR('d', 21, win_info_t) + +#define DS_BIND_REQUEST _IOWR('d', 60, bind_info_t) +#define DS_GET_DEVICE_INFO _IOWR('d', 61, bind_info_t) +#define DS_GET_NEXT_DEVICE _IOWR('d', 62, bind_info_t) +#define DS_UNBIND_REQUEST _IOW ('d', 63, bind_info_t) +#define DS_BIND_MTD _IOWR('d', 64, mtd_info_t) + +#ifdef __KERNEL__ + +typedef struct dev_link_t { + dev_node_t *dev; + u_int state, open; + wait_queue_head_t pending; + struct timer_list release; + client_handle_t handle; + io_req_t io; + irq_req_t irq; + config_req_t conf; + window_handle_t win; + void *priv; + struct dev_link_t *next; +} dev_link_t; + +/* Flags for device state */ +#define DEV_PRESENT 0x01 +#define DEV_CONFIG 0x02 +#define DEV_STALE_CONFIG 0x04 /* release on close */ +#define DEV_STALE_LINK 0x08 /* detach on release */ +#define DEV_CONFIG_PENDING 0x10 +#define DEV_RELEASE_PENDING 0x20 +#define DEV_SUSPEND 0x40 +#define DEV_BUSY 0x80 + +#define DEV_OK(l) \ + ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT))) + +int register_pccard_driver(dev_info_t *dev_info, + dev_link_t *(*attach)(void), + void (*detach)(dev_link_t *)); + +int unregister_pccard_driver(dev_info_t *dev_info); + +#define register_pcmcia_driver register_pccard_driver +#define unregister_pcmcia_driver unregister_pccard_driver + +#ifdef __BEOS__ +#define DS_MODULE_NAME "bus_managers/pcmcia_ds/v1" +typedef struct ds_module_info { + bus_manager_info binfo; + int (*_register_pccard_driver)(dev_info_t *, + dev_link_t *(*)(void), + void (*)(dev_link_t *)); + int (*_unregister_pccard_driver)(dev_info_t *); + struct driver_info_t **root_driver; + int *sockets; + struct socket_info_t **socket_table; + sem_id *list_sem; +} ds_module_info; +#endif /* __BEOS__ */ + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_DS_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/ftl.h linux/include/pcmcia/ftl.h --- v2.3.16/linux/include/pcmcia/ftl.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/ftl.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,73 @@ +/* + * ftl.h 1.6 1999/08/28 04:12:33 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_FTL_H +#define _LINUX_FTL_H + +typedef struct erase_unit_header_t { + u_char LinkTargetTuple[5]; + u_char DataOrgTuple[10]; + u_char NumTransferUnits; + u_int EraseCount; + u_short LogicalEUN; + u_char BlockSize; + u_char EraseUnitSize; + u_short FirstPhysicalEUN; + u_short NumEraseUnits; + u_int FormattedSize; + u_int FirstVMAddress; + u_short NumVMPages; + u_char Flags; + u_char Code; + u_int SerialNumber; + u_int AltEUHOffset; + u_int BAMOffset; + u_char Reserved[12]; + u_char EndTuple[2]; +} erase_unit_header_t; + +/* Flags in erase_unit_header_t */ +#define HIDDEN_AREA 0x01 +#define REVERSE_POLARITY 0x02 +#define DOUBLE_BAI 0x04 + +/* Definitions for block allocation information */ + +#define BLOCK_FREE(b) ((b) == 0xffffffff) +#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe)) + +#define BLOCK_TYPE(b) ((b) & 0x7f) +#define BLOCK_ADDRESS(b) ((b) & ~0x7f) +#define BLOCK_NUMBER(b) ((b) >> 9) +#define BLOCK_CONTROL 0x30 +#define BLOCK_DATA 0x40 +#define BLOCK_REPLACEMENT 0x60 +#define BLOCK_BAD 0x70 + +#endif /* _LINUX_FTL_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/mem_op.h linux/include/pcmcia/mem_op.h --- v2.3.16/linux/include/pcmcia/mem_op.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/mem_op.h Fri Sep 3 15:28:39 1999 @@ -0,0 +1,133 @@ +/* + * mem_op.h 1.10 1999/08/28 04:12:33 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_MEM_OP_H +#define _LINUX_MEM_OP_H + +#include + +/* + If UNSAFE_MEMCPY is defined, we use the (optimized) system routines + to copy between a card and kernel memory. These routines do 32-bit + operations which may not work with all PCMCIA controllers. The + safe versions defined here will do only 8-bit and 16-bit accesses. +*/ + +#ifdef UNSAFE_MEMCPY + +#define copy_from_pc memcpy_fromio +#define copy_to_pc memcpy_toio + +static inline void copy_pc_to_user(void *to, const void *from, size_t n) +{ + size_t odd = (n & 3); + n -= odd; + while (n) { + put_user(readl_ns(from), (int *)to); + (char *)from += 4; (char *)to += 4; n -= 4; + } + while (odd--) + put_user(readb((char *)from++), (char *)to++); +} + +static inline void copy_user_to_pc(void *to, const void *from, size_t n) +{ + int l; + char c; + size_t odd = (n & 3); + n -= odd; + while (n) { + get_user(l, (int *)from); + writel_ns(l, to); + (char *)to += 4; (char *)from += 4; n -= 4; + } + while (odd--) { + get_user(c, (char *)from++); + writeb(c, (char *)to++); + } +} + +#else /* UNSAFE_MEMCPY */ + +static inline void copy_from_pc(void *to, const void *from, size_t n) +{ + size_t odd = (n & 1); + n -= odd; + while (n) { + *(u_short *)to = __raw_readw(from); + (char *)to += 2; (char *)from += 2; n -= 2; + } + if (odd) + *(u_char *)to = readb(from); +} + +static inline void copy_to_pc(void *to, const void *from, size_t n) +{ + size_t odd = (n & 1); + n -= odd; + while (n) { + __raw_writew(*(u_short *)from, to); + (char *)to += 2; (char *)from += 2; n -= 2; + } + if (odd) + writeb(*(u_char *)from, to); +} + +static inline void copy_pc_to_user(void *to, const void *from, size_t n) +{ + size_t odd = (n & 1); + n -= odd; + while (n) { + put_user(__raw_readw(from), (short *)to); + (char *)to += 2; (char *)from += 2; n -= 2; + } + if (odd) + put_user(readb(from), (char *)to); +} + +static inline void copy_user_to_pc(void *to, const void *from, size_t n) +{ + short s; + char c; + size_t odd = (n & 1); + n -= odd; + while (n) { + get_user(s, (short *)from); + __raw_writew(s, to); + (char *)to += 2; (char *)from += 2; n -= 2; + } + if (odd) { + get_user(c, (char *)from); + writeb(c, to); + } +} + +#endif /* UNSAFE_MEMCPY */ + +#endif /* _LINUX_MEM_OP_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/memory.h linux/include/pcmcia/memory.h --- v2.3.16/linux/include/pcmcia/memory.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/memory.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,41 @@ +/* + * memory.h 1.5 1999/08/28 04:12:33 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_MEMORY_H +#define _LINUX_MEMORY_H + +typedef struct erase_info_t { + u_long Offset; + u_long Size; +} erase_info_t; + +#define MEMGETINFO _IOR('M', 1, region_info_t) +#define MEMERASE _IOW('M', 2, erase_info_t) + +#endif /* _LINUX_MEMORY_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/ss.h linux/include/pcmcia/ss.h --- v2.3.16/linux/include/pcmcia/ss.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/ss.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,130 @@ +/* + * ss.h 1.24 1999/08/28 04:12:33 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_SS_H +#define _LINUX_SS_H + +/* For RegisterCallback */ +typedef struct ss_callback_t { + void (*handler)(void *info, u_int events); + void *info; +} ss_callback_t; + +/* Definitions for card status flags for GetStatus */ +#define SS_WRPROT 0x0001 +#define SS_CARDLOCK 0x0002 +#define SS_EJECTION 0x0004 +#define SS_INSERTION 0x0008 +#define SS_BATDEAD 0x0010 +#define SS_BATWARN 0x0020 +#define SS_READY 0x0040 +#define SS_DETECT 0x0080 +#define SS_POWERON 0x0100 +#define SS_GPI 0x0200 +#define SS_STSCHG 0x0400 +#define SS_CARDBUS 0x0800 +#define SS_3VCARD 0x1000 +#define SS_XVCARD 0x2000 + +/* for InquireSocket */ +typedef struct socket_cap_t { + u_int features; + u_int irq_mask; + u_int map_size; + u_char pci_irq; + u_char cardbus; + struct pci_bus *cb_bus; + struct bus_operations *bus; +} socket_cap_t; + +/* InquireSocket capabilities */ +#define SS_CAP_PAGE_REGS 0x0001 +#define SS_CAP_VIRTUAL_BUS 0x0002 +#define SS_CAP_MEM_ALIGN 0x0004 +#define SS_CAP_PCCARD 0x4000 +#define SS_CAP_CARDBUS 0x8000 + +/* for GetSocket, SetSocket */ +typedef struct socket_state_t { + u_int flags; + u_int csc_mask; + u_char Vcc, Vpp; + u_char io_irq; +} socket_state_t; + +/* Socket configuration flags */ +#define SS_PWR_AUTO 0x0010 +#define SS_IOCARD 0x0020 +#define SS_RESET 0x0040 +#define SS_DMA_MODE 0x0080 +#define SS_SPKR_ENA 0x0100 +#define SS_OUTPUT_ENA 0x0200 + +/* Flags for I/O port and memory windows */ +#define MAP_ACTIVE 0x01 +#define MAP_16BIT 0x02 +#define MAP_AUTOSZ 0x04 +#define MAP_0WS 0x08 +#define MAP_WRPROT 0x10 +#define MAP_ATTRIB 0x20 +#define MAP_USE_WAIT 0x40 +#define MAP_PREFETCH 0x80 + +/* Use this just for bridge windows */ +#define MAP_IOSPACE 0x20 + +typedef struct pccard_io_map { + u_char map; + u_char flags; + u_short speed; + u_short start, stop; +} pccard_io_map; + +typedef struct pccard_mem_map { + u_char map; + u_char flags; + u_short speed; + u_long sys_start, sys_stop; + u_int card_start; +} pccard_mem_map; + +typedef struct cb_bridge_map { + u_char map; + u_char flags; + u_int start, stop; +} cb_bridge_map; + +enum ss_service { + SS_RegisterCallback, SS_InquireSocket, + SS_GetStatus, SS_GetSocket, SS_SetSocket, + SS_GetIOMap, SS_SetIOMap, SS_GetMemMap, SS_SetMemMap, + SS_GetBridge, SS_SetBridge, SS_ProcSetup +}; + +#endif /* _LINUX_SS_H */ diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/version.h linux/include/pcmcia/version.h --- v2.3.16/linux/include/pcmcia/version.h Wed Dec 31 16:00:00 1969 +++ linux/include/pcmcia/version.h Fri Sep 3 12:27:31 1999 @@ -0,0 +1,4 @@ +/* version.h 1.72 1999/08/05 06:09:53 (David Hinds) */ + +#define CS_RELEASE "3.1.0" +#define CS_RELEASE_CODE 0x3100 diff -u --recursive --new-file v2.3.16/linux/init/main.c linux/init/main.c --- v2.3.16/linux/init/main.c Tue Aug 31 17:29:15 1999 +++ linux/init/main.c Fri Sep 3 22:06:48 1999 @@ -84,6 +84,7 @@ extern void sysctl_init(void); extern void filescache_init(void); extern void signals_init(void); +extern int pcmcia_init(void); extern void free_initmem(void); extern void filesystem_setup(void); @@ -657,7 +658,9 @@ #ifdef CONFIG_IRDA irda_device_init(); /* Must be done after protocol initialization */ #endif - +#ifdef CONFIG_PCMCIA + pcmcia_init(); /* Do this last */ +#endif /* Mount the root filesystem.. */ mount_root(); diff -u --recursive --new-file v2.3.16/linux/ipc/shm.c linux/ipc/shm.c --- v2.3.16/linux/ipc/shm.c Tue Aug 31 17:29:15 1999 +++ linux/ipc/shm.c Tue Sep 7 10:55:54 1999 @@ -372,7 +372,7 @@ * shmd->vm_next next attach for task * shmd->vm_next_share next attach for segment * shmd->vm_offset offset into segment - * shmd->vm_pte signature for this attach + * shmd->vm_private_data signature for this attach */ static struct vm_operations_struct shm_vm_ops = { @@ -511,7 +511,7 @@ goto out; } - shmd->vm_pte = SWP_ENTRY(SHM_SWP_TYPE, id); + shmd->vm_private_data = shm_segs + id; shmd->vm_start = addr; shmd->vm_end = addr + shp->shm_npages * PAGE_SIZE; shmd->vm_mm = current->mm; @@ -547,16 +547,10 @@ /* This is called by fork, once for every shm attach. */ static void shm_open (struct vm_area_struct *shmd) { - unsigned int id; struct shmid_kernel *shp; lock_kernel(); - id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK; - shp = shm_segs[id]; - if (shp == IPC_UNUSED) { - printk("shm_open: unused id=%d PANIC\n", id); - return; - } + shp = *(struct shmid_kernel **) shmd->vm_private_data; insert_attach(shp,shmd); /* insert shmd into shp->attaches */ shp->u.shm_nattch++; shp->u.shm_atime = CURRENT_TIME; @@ -573,17 +567,17 @@ static void shm_close (struct vm_area_struct *shmd) { struct shmid_kernel *shp; - int id; lock_kernel(); /* remove from the list of attaches of the shm segment */ - id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK; - shp = shm_segs[id]; + shp = *(struct shmid_kernel **) shmd->vm_private_data; remove_attach(shp,shmd); /* remove from shp->attaches */ shp->u.shm_lpid = current->pid; shp->u.shm_dtime = CURRENT_TIME; - if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST) + if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST) { + unsigned int id = (struct shmid_kernel **)shmd->vm_private_data - shm_segs; killseg (id); + } unlock_kernel(); } @@ -628,20 +622,12 @@ { pte_t pte; struct shmid_kernel *shp; - unsigned int id, idx; + unsigned int idx; unsigned long page; struct page * page_map; - id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK; + shp = *(struct shmid_kernel **) shmd->vm_private_data; idx = (address - shmd->vm_start + shmd->vm_offset) >> PAGE_SHIFT; - -#ifdef DEBUG_SHM - if (id > max_shmid) { - printk ("shm_nopage: id=%d too big. proc mem corrupted\n", id); - return 0; - } -#endif - shp = shm_segs[id]; #ifdef DEBUG_SHM if (shp == IPC_UNUSED || shp == IPC_NOID) { diff -u --recursive --new-file v2.3.16/linux/kernel/exec_domain.c linux/kernel/exec_domain.c --- v2.3.16/linux/kernel/exec_domain.c Thu Aug 26 13:05:42 1999 +++ linux/kernel/exec_domain.c Sat Sep 4 13:06:08 1999 @@ -2,7 +2,7 @@ #include #include -static asmlinkage void no_lcall7(struct pt_regs * regs); +static asmlinkage void no_lcall7(int segment, struct pt_regs * regs); static unsigned long ident_map[32] = { @@ -25,9 +25,8 @@ static struct exec_domain *exec_domains = &default_exec_domain; -static asmlinkage void no_lcall7(struct pt_regs * regs) +static asmlinkage void no_lcall7(int segment, struct pt_regs * regs) { - /* * This may have been a static linked SVr4 binary, so we would have the * personality set incorrectly. Check to see whether SVr4 is available, @@ -44,7 +43,7 @@ if (current->exec_domain && current->exec_domain->handler && current->exec_domain->handler != no_lcall7) { - current->exec_domain->handler(regs); + current->exec_domain->handler(segment, regs); return; } diff -u --recursive --new-file v2.3.16/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.3.16/linux/kernel/ksyms.c Tue Aug 31 17:29:15 1999 +++ linux/kernel/ksyms.c Thu Sep 2 09:25:10 1999 @@ -320,6 +320,7 @@ /* resource handling */ EXPORT_SYMBOL(request_resource); EXPORT_SYMBOL(release_resource); +EXPORT_SYMBOL(allocate_resource); EXPORT_SYMBOL(__request_region); EXPORT_SYMBOL(__check_region); EXPORT_SYMBOL(__release_region); diff -u --recursive --new-file v2.3.16/linux/kernel/sys.c linux/kernel/sys.c --- v2.3.16/linux/kernel/sys.c Thu Aug 26 13:05:42 1999 +++ linux/kernel/sys.c Sat Sep 4 13:10:35 1999 @@ -41,10 +41,6 @@ return notifier_chain_unregister(&reboot_notifier_list, nb); } - - -extern void adjust_clock(void); - asmlinkage long sys_ni_syscall(void) { return -ENOSYS; diff -u --recursive --new-file v2.3.16/linux/mm/filemap.c linux/mm/filemap.c --- v2.3.16/linux/mm/filemap.c Tue Aug 31 17:29:15 1999 +++ linux/mm/filemap.c Wed Sep 1 14:10:09 1999 @@ -1303,7 +1303,7 @@ struct dentry * dentry = file->f_dentry; struct inode * inode = dentry->d_inode; struct page * page, **hash; - unsigned long old_page, new_page = 0; + unsigned long old_page; unsigned long offset = address - area->vm_start + area->vm_offset; @@ -1339,18 +1339,19 @@ * and possibly copy it over to another page.. */ old_page = page_address(page); - if (!no_share) { - flush_page_to_ram(old_page); - return old_page; - } + if (no_share) { + unsigned long new_page = page_cache_alloc(); - new_page = page_cache_alloc(); - if (new_page) { - copy_page(new_page, old_page); - flush_page_to_ram(new_page); - } - page_cache_release(page); - return new_page; + if (new_page) { + copy_page(new_page, old_page); + flush_page_to_ram(new_page); + } + page_cache_release(page); + return new_page; + } + + flush_page_to_ram(old_page); + return old_page; no_cached_page: /* @@ -1408,8 +1409,6 @@ * mm layer so, possibly freeing the page cache page first. */ page_cache_release(page); - if (new_page) - page_cache_free(new_page); return 0; } diff -u --recursive --new-file v2.3.16/linux/mm/mmap.c linux/mm/mmap.c --- v2.3.16/linux/mm/mmap.c Thu Aug 26 13:05:42 1999 +++ linux/mm/mmap.c Tue Sep 7 10:57:08 1999 @@ -275,7 +275,7 @@ vma->vm_ops = NULL; vma->vm_offset = off; vma->vm_file = NULL; - vma->vm_pte = 0; + vma->vm_private_data = NULL; /* Clear old maps */ error = -ENOMEM; @@ -547,7 +547,7 @@ mpnt->vm_ops = area->vm_ops; mpnt->vm_offset = area->vm_offset + (end - area->vm_start); mpnt->vm_file = area->vm_file; - mpnt->vm_pte = area->vm_pte; + mpnt->vm_private_data = area->vm_private_data; if (mpnt->vm_file) get_file(mpnt->vm_file); if (mpnt->vm_ops && mpnt->vm_ops->open) @@ -778,7 +778,7 @@ vma->vm_ops = NULL; vma->vm_offset = 0; vma->vm_file = NULL; - vma->vm_pte = 0; + vma->vm_private_data = NULL; /* * merge_segments may merge our vma, so we can't refer to it @@ -920,7 +920,7 @@ /* To share, we must have the same file, operations.. */ if ((mpnt->vm_file != prev->vm_file)|| - (mpnt->vm_pte != prev->vm_pte) || + (mpnt->vm_private_data != prev->vm_private_data) || (mpnt->vm_ops != prev->vm_ops) || (mpnt->vm_flags != prev->vm_flags) || (prev->vm_end != mpnt->vm_start)) diff -u --recursive --new-file v2.3.16/linux/net/README linux/net/README --- v2.3.16/linux/net/README Mon Apr 12 16:18:27 1999 +++ linux/net/README Tue Sep 7 10:14:37 1999 @@ -13,6 +13,7 @@ ipv4 davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se ipv6 davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se ipx/spx Jay.Schulist@spacs.k12.wi.us +irda dagb@cs.uit.no lapb g4klx@g4klx.demon.co.uk netrom g4klx@g4klx.demon.co.uk rose g4klx@g4klx.demon.co.uk diff -u --recursive --new-file v2.3.16/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.3.16/linux/net/appletalk/ddp.c Thu Aug 26 13:05:42 1999 +++ linux/net/appletalk/ddp.c Tue Sep 7 10:20:11 1999 @@ -1360,13 +1360,6 @@ return (0); } -/* - * Not relevant - */ -static int atalk_accept(struct socket *sock, struct socket *newsock, int flags) -{ - return (-EOPNOTSUPP); -} /* * Find the name of an AppleTalk socket. Just copy the right @@ -1918,10 +1911,6 @@ return (err ? err : (copied)); } -static int atalk_shutdown(struct socket *sk,int how) -{ - return (-EOPNOTSUPP); -} /* * AppleTalk ioctl calls. @@ -2029,12 +2018,12 @@ atalk_bind, atalk_connect, sock_no_socketpair, - atalk_accept, + sock_no_accept, atalk_getname, datagram_poll, atalk_ioctl, sock_no_listen, - atalk_shutdown, + sock_no_shutdown, sock_no_setsockopt, sock_no_getsockopt, sock_no_fcntl, diff -u --recursive --new-file v2.3.16/linux/net/atm/pvc.c linux/net/atm/pvc.c --- v2.3.16/linux/net/atm/pvc.c Tue Aug 31 17:29:15 1999 +++ linux/net/atm/pvc.c Tue Sep 7 10:20:11 1999 @@ -62,18 +62,6 @@ } -static int pvc_listen(struct socket *sock,int backlog) -{ - return -EOPNOTSUPP; -} - - -static int pvc_accept(struct socket *sock,struct socket *newsock,int flags) -{ - return -EOPNOTSUPP; -} - - static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, int *sockaddr_len,int peer) { @@ -100,11 +88,11 @@ pvc_bind, pvc_connect, sock_no_socketpair, - pvc_accept, + sock_no_accept, pvc_getname, atm_poll, atm_ioctl, - pvc_listen, + sock_no_listen, pvc_shutdown, atm_setsockopt, atm_getsockopt, diff -u --recursive --new-file v2.3.16/linux/net/core/iovec.c linux/net/core/iovec.c --- v2.3.16/linux/net/core/iovec.c Mon May 10 09:55:25 1999 +++ linux/net/core/iovec.c Fri Sep 3 11:44:16 1999 @@ -27,6 +27,7 @@ #include #include #include +#include /* * Verify iovec. The caller must ensure that the iovec is big enough diff -u --recursive --new-file v2.3.16/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c --- v2.3.16/linux/net/decnet/af_decnet.c Tue Aug 31 17:29:15 1999 +++ linux/net/decnet/af_decnet.c Tue Sep 7 10:20:11 1999 @@ -1239,9 +1239,6 @@ if ((sk->protinfo.dn.state != DN_O) || (sk->state == TCP_LISTEN)) goto out; - if (backlog > SOMAXCONN) - backlog = SOMAXCONN; - sk->max_ack_backlog = backlog; sk->ack_backlog = 0; sk->state = TCP_LISTEN; diff -u --recursive --new-file v2.3.16/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.3.16/linux/net/ipv4/af_inet.c Tue Aug 31 17:29:15 1999 +++ linux/net/ipv4/af_inet.c Tue Sep 7 10:20:11 1999 @@ -285,11 +285,6 @@ if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM) return -EINVAL; - if ((unsigned) backlog == 0) /* BSDism */ - backlog = 1; - if ((unsigned) backlog > SOMAXCONN) - backlog = SOMAXCONN; - lock_sock(sk); old_state = sk->state; err = -EINVAL; diff -u --recursive --new-file v2.3.16/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.3.16/linux/net/ipx/af_ipx.c Tue Aug 31 17:29:15 1999 +++ linux/net/ipx/af_ipx.c Tue Sep 7 10:20:11 1999 @@ -1983,10 +1983,6 @@ return (0); } -static int ipx_accept(struct socket *sock, struct socket *newsock, int flags) -{ - return (-EOPNOTSUPP); -} static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) @@ -2213,13 +2209,6 @@ return (err); } -/* - * FIXME: We have to really support shutdown. - */ -static int ipx_shutdown(struct socket *sk,int how) -{ - return (-EOPNOTSUPP); -} static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) { @@ -2342,12 +2331,12 @@ ipx_bind, ipx_connect, sock_no_socketpair, - ipx_accept, + sock_no_accept, ipx_getname, datagram_poll, ipx_ioctl, sock_no_listen, - ipx_shutdown, + sock_no_shutdown, /* FIXME: We have to really support shutdown. */ ipx_setsockopt, ipx_getsockopt, sock_no_fcntl, diff -u --recursive --new-file v2.3.16/linux/net/ipx/af_spx.c linux/net/ipx/af_spx.c --- v2.3.16/linux/net/ipx/af_spx.c Thu Aug 26 13:05:46 1999 +++ linux/net/ipx/af_spx.c Tue Sep 7 10:20:11 1999 @@ -113,10 +113,6 @@ return (0); } -static int spx_shutdown(struct socket *sk,int how) -{ - return (-EOPNOTSUPP); -} void spx_close_socket(struct sock *sk) { @@ -184,10 +180,6 @@ if(sk->zapped != 0) return (-EAGAIN); - if((unsigned) backlog == 0) /* BSDism */ - backlog = 1; - if((unsigned) backlog > SOMAXCONN) - backlog = SOMAXCONN; sk->max_ack_backlog = backlog; if(sk->state != TCP_LISTEN) { @@ -853,7 +845,7 @@ datagram_poll, /* this does seqpacket too */ spx_ioctl, spx_listen, - spx_shutdown, + sock_no_shutdown, spx_setsockopt, spx_getsockopt, sock_no_fcntl, diff -u --recursive --new-file v2.3.16/linux/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c --- v2.3.16/linux/net/irda/irlmp_event.c Tue Aug 31 17:29:15 1999 +++ linux/net/irda/irlmp_event.c Tue Sep 7 10:14:37 1999 @@ -347,16 +347,17 @@ * must be the one that tries to close IrLAP. It will be * removed later and moved to the list of unconnected LSAPs */ - if (hashbin_get_size(self->lsaps) == 1) + if (hashbin_get_size(self->lsaps) > 0) irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); - + else { + /* No more connections, so close IrLAP */ + irlmp_next_lap_state(self, LAP_STANDBY); + irlap_disconnect_request(self->irlap); + } break; case LM_LAP_IDLE_TIMEOUT: if (hashbin_get_size(self->lsaps) == 0) { - DEBUG(2, __FUNCTION__ - "(), no more LSAPs so time to close IrLAP\n"); irlmp_next_lap_state(self, LAP_STANDBY); - irlap_disconnect_request(self->irlap); } else /* Still not ready, so wait a little bit more */ diff -u --recursive --new-file v2.3.16/linux/net/khttpd/misc.c linux/net/khttpd/misc.c --- v2.3.16/linux/net/khttpd/misc.c Thu Aug 26 13:05:46 1999 +++ linux/net/khttpd/misc.c Thu Sep 2 11:47:20 1999 @@ -214,9 +214,9 @@ */ -static char NoPerm[] = "403 Permission denied\r\nServer: kHTTPd 0.1.6\r\n\r\n Permission denied"; -static char TryLater[] = "500 Try again later\r\nServer: kHTTPd 0.1.6\r\n\r\n Try again later"; -static char NotModified[] = "304 Not Modified\r\nServer: kHTTPd 0.1.6\r\n\r\n"; +static char NoPerm[] = "HTTP/1.0 403 Forbidden\r\nServer: kHTTPd 0.1.6\r\n\r\n"; +static char TryLater[] = "HTTP/1.0 503 Service Unavailable\r\nServer: kHTTPd 0.1.6\r\nContent-Length: 15\r\n\r\nTry again later"; +static char NotModified[] = "HTTP/1.0 304 Not Modified\r\nServer: kHTTPd 0.1.6\r\n\r\n"; void Send403(struct socket *sock) @@ -229,7 +229,7 @@ void Send304(struct socket *sock) { EnterFunction("Send304"); - (void)SendBuffer(sock,NotModified,strlen(NoPerm)); + (void)SendBuffer(sock,NotModified,strlen(NotModified)); LeaveFunction("Send304"); } diff -u --recursive --new-file v2.3.16/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.3.16/linux/net/netrom/af_netrom.c Tue Aug 31 17:29:15 1999 +++ linux/net/netrom/af_netrom.c Tue Sep 7 10:20:11 1999 @@ -1100,10 +1100,6 @@ return copied; } -static int nr_shutdown(struct socket *sk, int how) -{ - return -EOPNOTSUPP; -} static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { @@ -1255,7 +1251,7 @@ datagram_poll, nr_ioctl, nr_listen, - nr_shutdown, + sock_no_shutdown, nr_setsockopt, nr_getsockopt, sock_no_fcntl, diff -u --recursive --new-file v2.3.16/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.3.16/linux/net/rose/af_rose.c Tue Aug 31 17:29:15 1999 +++ linux/net/rose/af_rose.c Tue Sep 7 10:20:11 1999 @@ -1245,10 +1245,6 @@ return copied; } -static int rose_shutdown(struct socket *sk, int how) -{ - return -EOPNOTSUPP; -} static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { @@ -1445,7 +1441,7 @@ datagram_poll, rose_ioctl, rose_listen, - rose_shutdown, + sock_no_shutdown, rose_setsockopt, rose_getsockopt, sock_no_fcntl, diff -u --recursive --new-file v2.3.16/linux/net/socket.c linux/net/socket.c --- v2.3.16/linux/net/socket.c Thu Aug 26 13:05:46 1999 +++ linux/net/socket.c Tue Sep 7 10:20:11 1999 @@ -42,6 +42,8 @@ * Andi Kleen : Some small cleanups, optimizations, * and fixed a copy_from_user() bug. * Tigran Aivazian : sys_send(args) calls sys_sendto(args, NULL, 0) + * Tigran Aivazian : Made listen(2) backlog sanity checks + * protocol-independent * * * This program is free software; you can redistribute it and/or @@ -894,6 +896,10 @@ int err; if ((sock = sockfd_lookup(fd, &err)) != NULL) { + if ((unsigned) backlog == 0) /* BSDism */ + backlog = 1; + if ((unsigned) backlog > SOMAXCONN) + backlog = SOMAXCONN; err=sock->ops->listen(sock, backlog); sockfd_put(sock); } diff -u --recursive --new-file v2.3.16/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.3.16/linux/net/unix/af_unix.c Tue Aug 31 17:29:15 1999 +++ linux/net/unix/af_unix.c Tue Sep 7 10:20:11 1999 @@ -414,8 +414,6 @@ err = -EINVAL; if (!sk->protinfo.af_unix.addr) goto out; /* No listens on an unbound socket */ - if ((unsigned) backlog > SOMAXCONN) - backlog = SOMAXCONN; unix_state_wlock(sk); if (sk->state != TCP_CLOSE && sk->state != TCP_LISTEN) goto out_unlock; diff -u --recursive --new-file v2.3.16/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.3.16/linux/net/x25/af_x25.c Tue Aug 31 17:29:15 1999 +++ linux/net/x25/af_x25.c Tue Sep 7 10:20:11 1999 @@ -1044,10 +1044,6 @@ return copied; } -static int x25_shutdown(struct socket *sk, int how) -{ - return -EOPNOTSUPP; -} static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { @@ -1246,7 +1242,7 @@ datagram_poll, x25_ioctl, x25_listen, - x25_shutdown, + sock_no_shutdown, x25_setsockopt, x25_getsockopt, sock_no_fcntl,